mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Merge branch 'pull/5'
# Conflicts: # MultiClient.py # MultiServer.py # Mystery.py
This commit is contained in:
198
MultiClient.py
198
MultiClient.py
@@ -16,26 +16,19 @@ while True:
|
||||
break
|
||||
except ImportError:
|
||||
aioconsole = None
|
||||
input('Required python module "aioconsole" not found, press enter to install it')
|
||||
print('Required python module "aioconsole" not found, press enter to install it')
|
||||
input()
|
||||
subprocess.call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'aioconsole'])
|
||||
|
||||
websockets = None
|
||||
|
||||
while not websockets:
|
||||
while True:
|
||||
try:
|
||||
import websockets
|
||||
break
|
||||
except ImportError:
|
||||
websockets = None
|
||||
input('Required python module "websockets" not found, press enter to install it')
|
||||
print('Required python module "websockets" not found, press enter to install it')
|
||||
input()
|
||||
subprocess.call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'websockets'])
|
||||
else:
|
||||
version = websockets.__version__
|
||||
if type(version) == str:
|
||||
version = tuple(int(part) for part in version.split("."))
|
||||
if version < (8,1):
|
||||
websockets = None
|
||||
input('Required python module "websockets" too old, press enter to upgrade it')
|
||||
subprocess.call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'websockets'])
|
||||
|
||||
try:
|
||||
import colorama
|
||||
@@ -54,6 +47,7 @@ class Context:
|
||||
self.server_address = server_address
|
||||
|
||||
self.exit_event = asyncio.Event()
|
||||
self.watcher_event = asyncio.Event()
|
||||
|
||||
self.input_queue = asyncio.Queue()
|
||||
self.input_requests = 0
|
||||
@@ -75,7 +69,9 @@ class Context:
|
||||
self.slot = None
|
||||
self.player_names = {}
|
||||
self.locations_checked = set()
|
||||
self.locations_scouted = set()
|
||||
self.items_received = []
|
||||
self.locations_info = {}
|
||||
self.awaiting_rom = False
|
||||
self.rom = None
|
||||
self.auth = None
|
||||
@@ -104,11 +100,15 @@ INGAME_MODES = {0x07, 0x09, 0x0b}
|
||||
SAVEDATA_START = WRAM_START + 0xF000
|
||||
SAVEDATA_SIZE = 0x500
|
||||
|
||||
RECV_PROGRESS_ADDR = SAVEDATA_START + 0x4D0 # 2 bytes
|
||||
RECV_ITEM_ADDR = SAVEDATA_START + 0x4D2 # 1 byte
|
||||
RECV_ITEM_PLAYER_ADDR = SAVEDATA_START + 0x4D3 # 1 byte
|
||||
ROOMID_ADDR = SAVEDATA_START + 0x4D4 # 2 bytes
|
||||
ROOMDATA_ADDR = SAVEDATA_START + 0x4D6 # 1 byte
|
||||
RECV_PROGRESS_ADDR = SAVEDATA_START + 0x4D0 # 2 bytes
|
||||
RECV_ITEM_ADDR = SAVEDATA_START + 0x4D2 # 1 byte
|
||||
RECV_ITEM_PLAYER_ADDR = SAVEDATA_START + 0x4D3 # 1 byte
|
||||
ROOMID_ADDR = SAVEDATA_START + 0x4D4 # 2 bytes
|
||||
ROOMDATA_ADDR = SAVEDATA_START + 0x4D6 # 1 byte
|
||||
SCOUT_LOCATION_ADDR = SAVEDATA_START + 0x4D7 # 1 byte
|
||||
SCOUTREPLY_LOCATION_ADDR = SAVEDATA_START + 0x4D8 # 1 byte
|
||||
SCOUTREPLY_ITEM_ADDR = SAVEDATA_START + 0x4D9 # 1 byte
|
||||
SCOUTREPLY_PLAYER_ADDR = SAVEDATA_START + 0x4DA # 1 byte
|
||||
|
||||
location_table_uw = {"Blind's Hideout - Top": (0x11d, 0x10),
|
||||
"Blind's Hideout - Left": (0x11d, 0x20),
|
||||
@@ -334,7 +334,7 @@ SNES_ATTACHED = 3
|
||||
|
||||
async def snes_connect(ctx : Context, address):
|
||||
if ctx.snes_socket is not None:
|
||||
print('Already connected to snes')
|
||||
logging.error('Already connected to snes')
|
||||
return
|
||||
|
||||
ctx.snes_state = SNES_CONNECTING
|
||||
@@ -342,7 +342,7 @@ async def snes_connect(ctx : Context, address):
|
||||
|
||||
address = f"ws://{address}" if "://" not in address else address
|
||||
|
||||
print("Connecting to QUsb2snes at %s ..." % address)
|
||||
logging.info("Connecting to QUsb2snes at %s ..." % address)
|
||||
|
||||
try:
|
||||
ctx.snes_socket = await websockets.connect(address, ping_timeout=None, ping_interval=None)
|
||||
@@ -360,9 +360,9 @@ async def snes_connect(ctx : Context, address):
|
||||
if not devices:
|
||||
raise Exception('No device found')
|
||||
|
||||
print("Available devices:")
|
||||
logging.info("Available devices:")
|
||||
for id, device in enumerate(devices):
|
||||
print("[%d] %s" % (id + 1, device))
|
||||
logging.info("[%d] %s" % (id + 1, device))
|
||||
|
||||
device = None
|
||||
if len(devices) == 1:
|
||||
@@ -374,18 +374,18 @@ async def snes_connect(ctx : Context, address):
|
||||
device = devices[ctx.snes_attached_device[0]]
|
||||
else:
|
||||
while True:
|
||||
print("Select a device:")
|
||||
logging.info("Select a device:")
|
||||
choice = await console_input(ctx)
|
||||
if choice is None:
|
||||
raise Exception('Abort input')
|
||||
if not choice.isdigit() or int(choice) < 1 or int(choice) > len(devices):
|
||||
print("Invalid choice (%s)" % choice)
|
||||
logging.warning("Invalid choice (%s)" % choice)
|
||||
continue
|
||||
|
||||
device = devices[int(choice) - 1]
|
||||
break
|
||||
|
||||
print("Attaching to " + device)
|
||||
logging.info("Attaching to " + device)
|
||||
|
||||
Attach_Request = {
|
||||
"Opcode" : "Attach",
|
||||
@@ -397,12 +397,12 @@ async def snes_connect(ctx : Context, address):
|
||||
ctx.snes_attached_device = (devices.index(device), device)
|
||||
|
||||
if 'SD2SNES'.lower() in device.lower() or (len(device) == 4 and device[:3] == 'COM'):
|
||||
print("SD2SNES Detected")
|
||||
logging.info("SD2SNES Detected")
|
||||
ctx.is_sd2snes = True
|
||||
await ctx.snes_socket.send(json.dumps({"Opcode" : "Info", "Space" : "SNES"}))
|
||||
reply = json.loads(await ctx.snes_socket.recv())
|
||||
if reply and 'Results' in reply:
|
||||
print(reply['Results'])
|
||||
logging.info(reply['Results'])
|
||||
else:
|
||||
ctx.is_sd2snes = False
|
||||
|
||||
@@ -420,9 +420,9 @@ async def snes_connect(ctx : Context, address):
|
||||
ctx.snes_socket = None
|
||||
ctx.snes_state = SNES_DISCONNECTED
|
||||
if not ctx.snes_reconnect_address:
|
||||
print("Error connecting to snes (%s)" % e)
|
||||
logging.error("Error connecting to snes (%s)" % e)
|
||||
else:
|
||||
print(f"Error connecting to snes, attempt again in {RECONNECT_DELAY}s")
|
||||
logging.error(f"Error connecting to snes, attempt again in {RECONNECT_DELAY}s")
|
||||
asyncio.create_task(snes_autoreconnect(ctx))
|
||||
|
||||
async def snes_autoreconnect(ctx: Context):
|
||||
@@ -434,11 +434,11 @@ async def snes_recv_loop(ctx : Context):
|
||||
try:
|
||||
async for msg in ctx.snes_socket:
|
||||
ctx.snes_recv_queue.put_nowait(msg)
|
||||
print("Snes disconnected")
|
||||
logging.warning("Snes disconnected")
|
||||
except Exception as e:
|
||||
if not isinstance(e, websockets.WebSocketException):
|
||||
logging.exception(e)
|
||||
print("Lost connection to the snes, type /snes to reconnect")
|
||||
logging.error("Lost connection to the snes, type /snes to reconnect")
|
||||
finally:
|
||||
socket, ctx.snes_socket = ctx.snes_socket, None
|
||||
if socket is not None and not socket.closed:
|
||||
@@ -451,7 +451,7 @@ async def snes_recv_loop(ctx : Context):
|
||||
ctx.rom = None
|
||||
|
||||
if ctx.snes_reconnect_address:
|
||||
print(f"...reconnecting in {RECONNECT_DELAY}s")
|
||||
logging.info(f"...reconnecting in {RECONNECT_DELAY}s")
|
||||
asyncio.create_task(snes_autoreconnect(ctx))
|
||||
|
||||
async def snes_read(ctx : Context, address, size):
|
||||
@@ -479,9 +479,9 @@ async def snes_read(ctx : Context, address, size):
|
||||
break
|
||||
|
||||
if len(data) != size:
|
||||
print('Error reading %s, requested %d bytes, received %d' % (hex(address), size, len(data)))
|
||||
logging.error('Error reading %s, requested %d bytes, received %d' % (hex(address), size, len(data)))
|
||||
if len(data):
|
||||
print(str(data))
|
||||
logging.error(str(data))
|
||||
if ctx.snes_socket is not None and not ctx.snes_socket.closed:
|
||||
await ctx.snes_socket.close()
|
||||
return None
|
||||
@@ -507,7 +507,7 @@ async def snes_write(ctx : Context, write_list):
|
||||
|
||||
for address, data in write_list:
|
||||
if (address < WRAM_START) or ((address + len(data)) > (WRAM_START + WRAM_SIZE)):
|
||||
print("SD2SNES: Write out of range %s (%d)" % (hex(address), len(data)))
|
||||
logging.error("SD2SNES: Write out of range %s (%d)" % (hex(address), len(data)))
|
||||
return False
|
||||
for ptr, byte in enumerate(data, address + 0x7E0000 - WRAM_START):
|
||||
cmd += b'\xA9' # LDA
|
||||
@@ -566,48 +566,49 @@ async def send_msgs(websocket, msgs):
|
||||
|
||||
async def server_loop(ctx : Context, address = None):
|
||||
if ctx.socket is not None:
|
||||
print('Already connected')
|
||||
logging.error('Already connected')
|
||||
return
|
||||
|
||||
if address is None:
|
||||
address = ctx.server_address
|
||||
|
||||
while not address:
|
||||
print('Enter multiworld server address')
|
||||
logging.info('Enter multiworld server address')
|
||||
address = await console_input(ctx)
|
||||
|
||||
address = f"ws://{address}" if "://" not in address else address
|
||||
port = urllib.parse.urlparse(address).port or 38281
|
||||
|
||||
print('Connecting to multiworld server at %s' % address)
|
||||
logging.info('Connecting to multiworld server at %s' % address)
|
||||
try:
|
||||
ctx.socket = await websockets.connect(address, port=port, ping_timeout=None, ping_interval=None)
|
||||
print('Connected')
|
||||
logging.info('Connected')
|
||||
ctx.server_address = address
|
||||
|
||||
async for data in ctx.socket:
|
||||
for msg in json.loads(data):
|
||||
cmd, args = (msg[0], msg[1]) if len(msg) > 1 else (msg, None)
|
||||
await process_server_cmd(ctx, cmd, args)
|
||||
print('Disconnected from multiworld server, type /connect to reconnect')
|
||||
logging.warning('Disconnected from multiworld server, type /connect to reconnect')
|
||||
except ConnectionRefusedError:
|
||||
print('Connection refused by the multiworld server')
|
||||
logging.error('Connection refused by the multiworld server')
|
||||
except (OSError, websockets.InvalidURI):
|
||||
print('Failed to connect to the multiworld server')
|
||||
logging.error('Failed to connect to the multiworld server')
|
||||
except Exception as e:
|
||||
print('Lost connection to the multiworld server, type /connect to reconnect')
|
||||
logging.error('Lost connection to the multiworld server, type /connect to reconnect')
|
||||
if not isinstance(e, websockets.WebSocketException):
|
||||
logging.exception(e)
|
||||
finally:
|
||||
ctx.awaiting_rom = False
|
||||
ctx.auth = None
|
||||
ctx.items_received = []
|
||||
ctx.locations_info = {}
|
||||
socket, ctx.socket = ctx.socket, None
|
||||
if socket is not None and not socket.closed:
|
||||
await socket.close()
|
||||
ctx.server_task = None
|
||||
if ctx.server_address:
|
||||
print(f"... reconnecting in {RECONNECT_DELAY}s")
|
||||
logging.info(f"... reconnecting in {RECONNECT_DELAY}s")
|
||||
asyncio.create_task(server_autoreconnect(ctx))
|
||||
|
||||
async def server_autoreconnect(ctx: Context):
|
||||
@@ -617,28 +618,28 @@ async def server_autoreconnect(ctx: Context):
|
||||
|
||||
async def process_server_cmd(ctx : Context, cmd, args):
|
||||
if cmd == 'RoomInfo':
|
||||
print('--------------------------------')
|
||||
print('Room Information:')
|
||||
print('--------------------------------')
|
||||
logging.info('--------------------------------')
|
||||
logging.info('Room Information:')
|
||||
logging.info('--------------------------------')
|
||||
if args['password']:
|
||||
print('Password required')
|
||||
logging.info('Password required')
|
||||
if len(args['players']) < 1:
|
||||
print('No player connected')
|
||||
logging.info('No player connected')
|
||||
else:
|
||||
args['players'].sort()
|
||||
current_team = 0
|
||||
print('Connected players:')
|
||||
print(' Team #1')
|
||||
logging.info('Connected players:')
|
||||
logging.info(' Team #1')
|
||||
for team, slot, name in args['players']:
|
||||
if team != current_team:
|
||||
print(f' Team #{team + 1}')
|
||||
logging.info(f' Team #{team + 1}')
|
||||
current_team = team
|
||||
print(' %s (Player %d)' % (name, slot))
|
||||
logging.info(' %s (Player %d)' % (name, slot))
|
||||
await server_auth(ctx, args['password'])
|
||||
|
||||
if cmd == 'ConnectionRefused':
|
||||
if 'InvalidPassword' in args:
|
||||
print('Invalid password')
|
||||
logging.error('Invalid password')
|
||||
ctx.password = None
|
||||
await server_auth(ctx, True)
|
||||
if 'InvalidRom' in args:
|
||||
@@ -650,8 +651,13 @@ async def process_server_cmd(ctx : Context, cmd, args):
|
||||
if cmd == 'Connected':
|
||||
ctx.team, ctx.slot = args[0]
|
||||
ctx.player_names = {p: n for p, n in args[1]}
|
||||
msgs = []
|
||||
if ctx.locations_checked:
|
||||
await send_msgs(ctx.socket, [['LocationChecks', [Regions.location_table[loc][0] for loc in ctx.locations_checked]]])
|
||||
msgs.append(['LocationChecks', [Regions.location_table[loc][0] for loc in ctx.locations_checked]])
|
||||
if ctx.locations_scouted:
|
||||
msgs.append(['LocationScouts', list(ctx.locations_scouted)])
|
||||
if msgs:
|
||||
await send_msgs(ctx.socket, msgs)
|
||||
|
||||
if cmd == 'ReceivedItems':
|
||||
start_index, items = args
|
||||
@@ -665,24 +671,34 @@ async def process_server_cmd(ctx : Context, cmd, args):
|
||||
if start_index == len(ctx.items_received):
|
||||
for item in items:
|
||||
ctx.items_received.append(ReceivedItem(*item))
|
||||
ctx.watcher_event.set()
|
||||
|
||||
if cmd == 'LocationInfo':
|
||||
for location, item, player in args:
|
||||
if location not in ctx.locations_info:
|
||||
replacements = {0xA2: 'Small Key', 0x9D: 'Big Key', 0x8D: 'Compass', 0x7D: 'Map'}
|
||||
item_name = replacements.get(item, get_item_name_from_id(item))
|
||||
logging.info(f"Saw {color(item_name, 'red', 'bold')} at {list(Regions.location_table.keys())[location - 1]}")
|
||||
ctx.locations_info[location] = (item, player)
|
||||
ctx.watcher_event.set()
|
||||
|
||||
if cmd == 'ItemSent':
|
||||
player_sent, location, player_recvd, item = args
|
||||
item = color(get_item_name_from_id(item), 'cyan' if player_sent != ctx.slot else 'green')
|
||||
player_sent = color(ctx.player_names[player_sent], 'yellow' if player_sent != ctx.slot else 'magenta')
|
||||
player_recvd = color(ctx.player_names[player_recvd], 'yellow' if player_recvd != ctx.slot else 'magenta')
|
||||
print('%s sent %s to %s (%s)' % (player_sent, item, player_recvd, get_location_name_from_address(location)))
|
||||
logging.info('%s sent %s to %s (%s)' % (player_sent, item, player_recvd, get_location_name_from_address(location)))
|
||||
|
||||
if cmd == 'Print':
|
||||
print(args)
|
||||
logging.info(args)
|
||||
|
||||
async def server_auth(ctx : Context, password_requested):
|
||||
if password_requested and not ctx.password:
|
||||
print('Enter the password required to join this game:')
|
||||
logging.info('Enter the password required to join this game:')
|
||||
ctx.password = await console_input(ctx)
|
||||
if ctx.rom is None:
|
||||
ctx.awaiting_rom = True
|
||||
print('No ROM detected, awaiting snes connection to authenticate to the multiworld server')
|
||||
logging.info('No ROM detected, awaiting snes connection to authenticate to the multiworld server')
|
||||
return
|
||||
ctx.awaiting_rom = False
|
||||
ctx.auth = ctx.rom.copy()
|
||||
@@ -718,12 +734,6 @@ async def console_loop(ctx : Context):
|
||||
if command[0] == '/exit':
|
||||
ctx.exit_event.set()
|
||||
|
||||
if command[0] == '/installcolors' and 'colorama' not in sys.modules:
|
||||
subprocess.call([sys.executable, '-m', 'pip', 'install', '--upgrade', 'colorama'])
|
||||
global colorama
|
||||
import colorama
|
||||
colorama.init()
|
||||
|
||||
if command[0] == '/snes':
|
||||
ctx.snes_reconnect_address = None
|
||||
asyncio.create_task(snes_connect(ctx, command[1] if len(command) > 1 else ctx.snes_address))
|
||||
@@ -742,25 +752,25 @@ async def console_loop(ctx : Context):
|
||||
asyncio.create_task(send_msgs(ctx.socket, [['Say', input]]))
|
||||
|
||||
if command[0] == '/received':
|
||||
print('Received items:')
|
||||
logging.info('Received items:')
|
||||
for index, item in enumerate(ctx.items_received, 1):
|
||||
print('%s from %s (%s) (%d/%d in list)' % (
|
||||
logging.info('%s from %s (%s) (%d/%d in list)' % (
|
||||
color(get_item_name_from_id(item.item), 'red', 'bold'), color(ctx.player_names[item.player], 'yellow'),
|
||||
get_location_name_from_address(item.location), index, len(ctx.items_received)))
|
||||
|
||||
if command[0] == '/missing':
|
||||
for location in [k for k, v in Regions.location_table.items() if type(v[0]) is int]:
|
||||
if location not in ctx.locations_checked:
|
||||
print('Missing: ' + location)
|
||||
logging.info('Missing: ' + location)
|
||||
if command[0] == '/getitem' and len(command) > 1:
|
||||
item = input[9:]
|
||||
item_id = Items.item_table[item][3] if item in Items.item_table else None
|
||||
if type(item_id) is int and item_id in range(0x100):
|
||||
print('Sending item: ' + item)
|
||||
logging.info('Sending item: ' + item)
|
||||
snes_buffered_write(ctx, RECV_ITEM_ADDR, bytes([item_id]))
|
||||
snes_buffered_write(ctx, RECV_ITEM_PLAYER_ADDR, bytes([0]))
|
||||
else:
|
||||
print('Invalid item: ' + item)
|
||||
logging.info('Invalid item: ' + item)
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
@@ -779,7 +789,7 @@ async def track_locations(ctx : Context, roomid, roomdata):
|
||||
new_locations = []
|
||||
def new_check(location):
|
||||
ctx.locations_checked.add(location)
|
||||
print("New check: %s (%d/216)" % (location, len(ctx.locations_checked)))
|
||||
logging.info("New check: %s (%d/216)" % (location, len(ctx.locations_checked)))
|
||||
new_locations.append(Regions.location_table[location][0])
|
||||
|
||||
for location, (loc_roomid, loc_mask) in location_table_uw.items():
|
||||
@@ -838,7 +848,11 @@ async def track_locations(ctx : Context, roomid, roomdata):
|
||||
|
||||
async def game_watcher(ctx : Context):
|
||||
while not ctx.exit_event.is_set():
|
||||
await asyncio.sleep(2)
|
||||
try:
|
||||
await asyncio.wait_for(ctx.watcher_event.wait(), 2)
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
ctx.watcher_event.clear()
|
||||
|
||||
if not ctx.rom:
|
||||
rom = await snes_read(ctx, ROMNAME_START, ROMNAME_SIZE)
|
||||
@@ -847,50 +861,64 @@ async def game_watcher(ctx : Context):
|
||||
|
||||
ctx.rom = list(rom)
|
||||
ctx.locations_checked = set()
|
||||
ctx.locations_scouted = set()
|
||||
if ctx.awaiting_rom:
|
||||
await server_auth(ctx, False)
|
||||
|
||||
if ctx.auth and ctx.auth != ctx.rom:
|
||||
print("ROM change detected, please reconnect to the multiworld server")
|
||||
logging.warning("ROM change detected, please reconnect to the multiworld server")
|
||||
await disconnect(ctx)
|
||||
|
||||
gamemode = await snes_read(ctx, WRAM_START + 0x10, 1)
|
||||
if gamemode is None or gamemode[0] not in INGAME_MODES:
|
||||
continue
|
||||
|
||||
data = await snes_read(ctx, RECV_PROGRESS_ADDR, 7)
|
||||
data = await snes_read(ctx, RECV_PROGRESS_ADDR, 8)
|
||||
if data is None:
|
||||
continue
|
||||
|
||||
recv_index = data[0] | (data[1] << 8)
|
||||
assert(RECV_ITEM_ADDR == RECV_PROGRESS_ADDR + 2)
|
||||
assert RECV_ITEM_ADDR == RECV_PROGRESS_ADDR + 2
|
||||
recv_item = data[2]
|
||||
assert(ROOMID_ADDR == RECV_PROGRESS_ADDR + 4)
|
||||
assert ROOMID_ADDR == RECV_PROGRESS_ADDR + 4
|
||||
roomid = data[4] | (data[5] << 8)
|
||||
assert(ROOMDATA_ADDR == RECV_PROGRESS_ADDR + 6)
|
||||
assert ROOMDATA_ADDR == RECV_PROGRESS_ADDR + 6
|
||||
roomdata = data[6]
|
||||
|
||||
await track_locations(ctx, roomid, roomdata)
|
||||
assert SCOUT_LOCATION_ADDR == RECV_PROGRESS_ADDR + 7
|
||||
scout_location = data[7]
|
||||
|
||||
if recv_index < len(ctx.items_received) and recv_item == 0:
|
||||
item = ctx.items_received[recv_index]
|
||||
print('Received %s from %s (%s) (%d/%d in list)' % (
|
||||
logging.info('Received %s from %s (%s) (%d/%d in list)' % (
|
||||
color(get_item_name_from_id(item.item), 'red', 'bold'), color(ctx.player_names[item.player], 'yellow'),
|
||||
get_location_name_from_address(item.location), recv_index + 1, len(ctx.items_received)))
|
||||
recv_index += 1
|
||||
snes_buffered_write(ctx, RECV_PROGRESS_ADDR, bytes([recv_index & 0xFF, (recv_index >> 8) & 0xFF]))
|
||||
snes_buffered_write(ctx, RECV_ITEM_ADDR, bytes([item.item]))
|
||||
snes_buffered_write(ctx, RECV_ITEM_PLAYER_ADDR, bytes([item.player]))
|
||||
snes_buffered_write(ctx, RECV_ITEM_PLAYER_ADDR, bytes([item.player if item.player != ctx.slot else 0]))
|
||||
if scout_location > 0 and scout_location in ctx.locations_info:
|
||||
snes_buffered_write(ctx, SCOUTREPLY_LOCATION_ADDR, bytes([scout_location]))
|
||||
snes_buffered_write(ctx, SCOUTREPLY_ITEM_ADDR, bytes([ctx.locations_info[scout_location][0]]))
|
||||
snes_buffered_write(ctx, SCOUTREPLY_PLAYER_ADDR, bytes([ctx.locations_info[scout_location][1]]))
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
if scout_location > 0 and scout_location not in ctx.locations_scouted:
|
||||
ctx.locations_scouted.add(scout_location)
|
||||
logging.info(f'Scouting item at {list(Regions.location_table.keys())[scout_location - 1]}')
|
||||
await send_msgs(ctx.socket, [['LocationScouts', [scout_location]]])
|
||||
await track_locations(ctx, roomid, roomdata)
|
||||
|
||||
async def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--snes', default='localhost:8080', help='Address of the QUsb2snes server.')
|
||||
parser.add_argument('--connect', default=None, help='Address of the multiworld host.')
|
||||
parser.add_argument('--password', default=None, help='Password of the multiworld host.')
|
||||
parser.add_argument('--loglevel', default='info', choices=['debug', 'info', 'warning', 'error', 'critical'])
|
||||
args = parser.parse_args()
|
||||
|
||||
logging.basicConfig(format='%(message)s', level=getattr(logging, args.loglevel.upper(), logging.INFO))
|
||||
|
||||
ctx = Context(args.snes, args.connect, args.password)
|
||||
|
||||
input_task = asyncio.create_task(console_loop(ctx))
|
||||
@@ -924,13 +952,9 @@ async def main():
|
||||
await input_task
|
||||
|
||||
if __name__ == '__main__':
|
||||
if 'colorama' in sys.modules:
|
||||
colorama.init()
|
||||
|
||||
colorama.init()
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main())
|
||||
loop.run_until_complete(asyncio.gather(*asyncio.Task.all_tasks()))
|
||||
loop.close()
|
||||
|
||||
if 'colorama' in sys.modules:
|
||||
colorama.deinit()
|
||||
colorama.deinit()
|
||||
|
Reference in New Issue
Block a user