검색

가이드

LD플레이어 멀티 매크로와 블루스택 멀티 인스턴스 동기화 실행

MAS에서 BlueStacks나 LDPlayer 인스턴스를 포트별로 추가하고 기기 그룹으로 묶어, 기기마다 프로필과 프록시를 주고 한 번에 실행하는 멀티 인스턴스 자동화 안내입니다.

  • Windows
  • Mac
  • 에뮬레이터
  • 스튜디오
  • Python SDK
중급 업데이트 10분 소요
이 페이지의 내용
  1. 시작하기 전에
  2. 멀티 인스턴스 안드로이드 에뮬레이터의 각 인스턴스가 기기
  3. 기기 그룹 만들기
  4. 기기마다 자기 인수 주기
  5. 기기마다 자기 프록시 주기
  6. Start All: LDPlayer나 BlueStacks의 멀티 인스턴스 동기화 실행
  7. 스토리지로 기기별 상태 유지
  8. 그룹별 웹훅
  9. 블루스택 봇 팜의 자원 한계 확인
  10. 그룹 예약
  11. 완전한 예제
  12. 잘못될 수 있는 것
  13. Port is already in use
  14. 인스턴스 하나만 실행되고 나머지는 Connecting에 머묾
  15. 템플릿이 한 인스턴스에서만 일치함
  16. 모든 인스턴스가 카운터 하나를 공유함

매크로 하나, 계정 다섯 개, 클릭 한 번. 그것이 LD플레이어 멀티 매크로이자 블루스택 멀티 인스턴스 자동화입니다. Macro Automation Studio(MAS)는 모든 에뮬레이터 인스턴스를 별도 기기로 취급합니다. 그러면 기기 그룹이 LD플레이어 멀티 매크로를 모든 인스턴스에서 실행하며, 기기별 인수, 기기마다 프록시 하나, 그리고 카운터가 절대 섞이지 않는 스토리지를 제공합니다. 이 가이드는 BlueStacks, LDPlayer, MuMu Player 또는 MEmu에서 그 구성을 만듭니다. 계정을 하나 이상 운영하는 분을 위한 가이드입니다.

시작하기 전에

  • MAS가 설치되어 있고, 동시에 실행하려는 인스턴스 수를 기기 수가 감당하는 요금제로 로그인한 상태. 결제를 참고하세요.
  • 에뮬레이터의 다중 인스턴스 관리자에서 인스턴스를 만들었고 각각 ADB가 켜진 상태. 설정과 포트 위치는 BlueStacks, LDPlayer, MuMu Player, MEmu 가이드에 있습니다.
  • 모든 인스턴스가 템플릿을 캡처한 인스턴스와 같은 해상도와 DPI를 사용.
  • 매크로가 Code Editor에서 인스턴스 하나로 동작하는 상태. 반복 가이드를 참고하세요.

멀티 인스턴스 안드로이드 에뮬레이터의 각 인스턴스가 기기

에뮬레이터 인스턴스는 자기 로컬 TCP 포트로 adb를 수신합니다. MAS는 실행 중인 프로세스를 스캔하고 각 에뮬레이터의 알려진 범위 안의 포트를 남겨 인스턴스를 찾습니다. 따라서 BlueStacks 창 두 개는 Port 목록에 항목 두 개로 나타납니다. 기기는 포트이고, 그룹은 포트 목록입니다.

에뮬레이터MAS가 인정하는 포트
BlueStacks5555부터 8500까지
LDPlayer5555부터 5599까지의 홀수 포트
MuMu Player5555부터 5599까지의 홀수 포트, 7555, 16384부터 16576까지, 26624부터 27264까지
MEmu21503과 그 위로 3으로 끝나는 30000 미만의 모든 포트

추가하는 동안 모든 인스턴스를 열어 두세요. 멈춘 인스턴스에는 찾을 포트가 없습니다. 전체 검색 규칙은 기기 페이지에 있습니다.

기기 그룹 만들기

  1. Device Groups를 열고 Create New Group을 클릭합니다.
  2. Name을 입력하고 유형은 Local로 둔 채 Create Group을 클릭합니다.
  3. 그룹을 열고 Add Device를 클릭합니다.
  4. 어느 계정인지 알 수 있는 Device Name을 입력합니다. 예를 들어 farm-alt-2입니다.
  5. Port에서 인스턴스의 포트를 고릅니다. 없으면 Refresh를 클릭하거나 Custom Port를 선택해 입력합니다.
  6. Add Device를 클릭하고 모든 인스턴스에 대해 반복합니다.
  7. 각 기기 카드의 Macro 선택기에서 매크로를 고릅니다.

포트 하나는 기기 하나에만 속할 수 있습니다. 두 번 추가하면 “Port is already in use”로 실패합니다. 기기 그룹을 참고하세요.

기기마다 자기 인수 주기

대부분의 봇에는 계정마다 다른 값 하나가 필요합니다: 이름, 목표, 회차 수. 넘기는 방법은 두 가지입니다.

설정 프로필(코드 변경 없음). 매크로에 UI Builder로 만든 인수 폼이 있으면 각 기기 카드에 Edit Arguments가 있습니다. 대화 상자에 Profile 바가 있습니다: 값을 입력하고 Save current values as a new profile을 선택해 이름을 짓고 Create profile을 클릭합니다. 기기는 프로필 하나를 따르며, 프로필을 편집하면 그것을 따르는 모든 기기가 다음 실행에서 갱신됩니다. “Default”는 항상 존재하며 삭제할 수 없습니다. 설정 프로필UI Builder를 참고하세요.

코드의 포트. 스크립트가 자기가 어느 인스턴스에 있는지 물어보고 자기 설정을 고를 수 있습니다. 폼이 필요 없으며 끝의 예제가 이 방식입니다.

python
import mas

port = mas.get_current_device_port()   # 5555, 5557, 5559 ...

값이 자주 바뀌거나 다른 사람이 봇을 실행할 때는 프로필을, 대응이 고정되어 코드와 함께 살 때는 포트를 쓰세요.

기기마다 자기 프록시 주기

IP를 공유하는 계정은 운명도 공유합니다. MAS는 기기마다 프록시 하나를 연결하고 그 인스턴스의 트래픽을 프록시로 보냅니다.

  1. Proxies를 엽니다. Add a proxy 아래에서 Gateway account 탭을 채우거나, 본인 프록시(http, https 또는 socks5)를 위한 Another provider 탭을 채우고 Add & test를 클릭합니다.
  2. 테스트를 기다립니다. 프록시가 응답하는지 확인하고 국가를 감지합니다. Test가 나중에 반복합니다.
  3. Assign을 클릭해 기기를 고르거나, Device Groups에서 기기 카드를 열고 Proxy 아래에서 프록시를 고릅니다.

기기 카드는 실행마다 프록시 상태를 보여 주고, 실행 웹훅에는 proxy_exit_ipproxy_country가 담깁니다. 기기는 프록시 하나를 가지며, 다른 것을 연결하면 대체됩니다. 프록시를 참고하세요.

Start All: LDPlayer나 BlueStacks의 멀티 인스턴스 동기화 실행

그룹 위쪽의 Start All을 클릭합니다. MAS가 기기를 0.5초 간격으로 차례로 시작하며, 각각 자기 실행, 자기 로그, 자기 종료 코드를 가집니다. 매크로가 없는 기기는 오류와 함께 건너뛰고 나머지는 계속됩니다. Stop All은 그룹의 모든 실행을 끝냅니다. 각 카드의 Logs 탭은 그 기기만 보여 주고, Dashboard 탭은 매크로에 런타임 UI가 있으면 이를 보여 줍니다.

스토리지로 기기별 상태 유지

mas.save, mas.retrieve, mas.clear는 이 컴퓨터, 기기 포트, 작업 이름을 키로 씁니다. 따라서 같은 매크로를 실행하는 인스턴스 두 개는 추가 코드 없이 별도 카운터를 유지합니다. 합산하려면 mas.retrieve_all(task_name)machine_id, port, data, updated_at이 있는 항목을 포트마다 하나씩 반환합니다.

python
TASK = "collector"

mine = mas.retrieve(TASK)                          # this instance only
everyone = mas.retrieve_all(TASK)                  # every instance on this computer
total = sum(entry["data"].get("done", 0) for entry in everyone)

스토리지를 참고하세요.

그룹별 웹훅

어느 계정이든 끝나거나 실패할 때 알림을 받으려면 Webhooks 페이지에서 엔드포인트를 추가하고, Send me 아래에서 이벤트를 고르고, Send me events from 아래에서 Specific groups를 선택해 그룹을 체크합니다. 나중에 그룹에 추가한 기기도 포함됩니다. 각 이벤트에는 device_name, device_port, group_id, status, exit_code가 담기므로 엔드포인트 하나로 계정을 구별할 수 있습니다. 웹훅을 참고하세요.

블루스택 봇 팜의 자원 한계 확인

모든 인스턴스는 완전한 Android 시스템입니다. 늘리기 전에 세 가지를 확인하세요:

  • 인스턴스당 CPU와 RAM. 각 인스턴스는 에뮬레이터 인스턴스 설정의 코어와 메모리를 차지합니다. 모두 더하고, 같은 컴퓨터에서 모든 인스턴스의 템플릿 매칭과 OCR을 실행하는 MAS를 위한 여유를 남기세요. 탭이 늦게 떨어지기 시작하면 한계를 넘은 것입니다.
  • 요금제의 기기 수. 요금제는 본인 기기 몇 대를 동시에 실행할 수 있는지로 정해집니다. Start All은 요금제가 허용하는 만큼 실행합니다. 결제가격 페이지를 참고하세요.
  • 예약된 작업. 스케줄러는 포트당 하나씩 최대 20개 작업을 동시에 실행합니다.

깨끗하게 돌아가는 적은 인스턴스가 템플릿을 놓치는 많은 인스턴스보다 낫습니다.

그룹 예약

스케줄러는 작업마다 포트 하나를 대상으로 하므로 그룹 예약은 기기마다 작업 하나입니다.

  1. Scheduler를 열고 Create New Schedule을 클릭합니다.
  2. Macro를 고르고 Emulator Port 아래의 Scan을 클릭해 첫 인스턴스를 선택합니다.
  3. Date, Time, Recurrence를 설정하고 Create Schedule을 클릭합니다.
  4. 각 포트에 대해 반복합니다. 작업에 같은 시간을 주세요. 다른 포트는 절대 충돌하지 않습니다.

예약 실행은 각 기기 카드에 저장된 인수, 또는 기기가 따르는 프로필을 사용하므로 계정별 값이 그대로 전달됩니다. 앱은 열어 두어야 합니다. 스케줄러반복 가이드를 참고하세요.

완전한 예제

매크로는 자기 포트를 읽고, 계정의 설정을 고르고, 포트별 카운터를 유지하고, 끝에 모든 인스턴스의 합계를 기록합니다. 포트와 이미지 ID를 본인 것으로 바꾸세요.

python
import random
import sys
import time

import mas

images = mas.images({
    "collect": 501,
    "close_popup": 502,
})

SETTINGS = {   # per instance, keyed by the emulator's adb port
    5555: {"account": "main", "rounds": 20},
    5557: {"account": "alt-1", "rounds": 10},
    5559: {"account": "alt-2", "rounds": 10},
}
DEFAULT = {"account": "unknown", "rounds": 5}
TASK = "collector"
TIME_BUDGET_S = 15 * 60


def main():
    port = mas.get_current_device_port()
    settings = SETTINGS.get(port, DEFAULT)
    account = settings["account"]
    mas.log(f"Port {port}: account {account}, {settings['rounds']} rounds")

    done = mas.retrieve(TASK).get("done", 0)
    started = time.monotonic()
    misses = 0

    while done < settings["rounds"]:
        if time.monotonic() - started > TIME_BUDGET_S:
            mas.log(f"{account}: time budget reached", level="warning")
            break
        popup = mas.find_object(images.close_popup)
        if popup:
            mas.click(popup.x, popup.y, delay_ms=800)
            continue
        button = mas.find_object_retry(images.collect, total_tries=3, time_sleep=2.0)
        if button is None:
            misses += 1
            if misses >= 5:
                mas.log(f"{account}: five misses, giving up", level="error")
                sys.exit(2)
            continue
        misses = 0
        mas.click(button.x, button.y, delay_ms=1000)
        done += 1
        mas.save(TASK, {"done": done, "account": account})
        time.sleep(random.uniform(0.8, 2.5))

    total = sum(entry["data"].get("done", 0) for entry in mas.retrieve_all(TASK))
    mas.log(f"{account}: {done} rounds done; {total} across all instances")
    mas.webhook("account.finished", {"account": account, "port": port, "done": done})


if __name__ == "__main__":
    main()

mas.webhook은 사용자 지정 이벤트를 구독한 엔드포인트에 custom.account.finished 이벤트를 보냅니다. 없으면 그 줄을 빼세요. 대응표가 커지면 인수 폼으로 옮기고 딕셔너리 대신 args.<tab>.<key>를 읽으세요.

잘못될 수 있는 것

Port is already in use

내 그룹의 다른 기기가 그 포트를 갖고 있습니다. 포트는 한 번만 추가할 수 있습니다. 기존 항목을 제거하거나 다른 인스턴스의 포트를 고르세요.

인스턴스 하나만 실행되고 나머지는 Connecting에 머묾

나머지 인스턴스는 ADB가 꺼져 있거나, 아직 부팅 중이거나, 에뮬레이터 범위 밖 포트로 수신합니다. 각 인스턴스의 설정을 열어 ADB와 포트를 확인하고 Add Device에서 Refresh를 클릭하세요. 포트가 위 표 밖이면 Custom Port를 쓰세요. ADB 문제 해결을 참고하세요.

템플릿이 한 인스턴스에서만 일치함

그 인스턴스의 해상도나 DPI가 다릅니다. 템플릿 매칭은 픽셀 기반입니다. 에뮬레이터 인스턴스 설정에서 모든 인스턴스를 캡처 해상도로 맞추고 다시 시작하세요. 나머지는 이미지 인식 가이드에서 설명합니다.

모든 인스턴스가 카운터 하나를 공유함

스크립트가 mas.save에 명시적인 portmachine_id를 넘기거나, 스토리지 대신 디스크의 파일을 씁니다. 기본값으로 mas.save(TASK, data)를 호출하세요. 현재 포트는 자동으로 추가됩니다.

100% 안전한 자동화 도구는 없으므로, 책임감을 가지고 본인의 판단에 따라 자동화하세요.

다음 단계

관련 페이지

이 페이지가 도움이 되었나요?

궁금한 점이 있으신가요? Discord에서 질문하기