Make multiclient/multiserver/tracker keydropshuffle aware

This commit is contained in:
CaitSith2 2020-10-27 00:47:59 -07:00
parent 0c681c8903
commit 83db79815a
4 changed files with 145 additions and 13 deletions

View File

@ -342,7 +342,40 @@ location_table_uw = {"Blind's Hideout - Top": (0x11d, 0x10),
'Ganons Tower - Mini Helmasaur Room - Left': (0x3d, 0x10), 'Ganons Tower - Mini Helmasaur Room - Left': (0x3d, 0x10),
'Ganons Tower - Mini Helmasaur Room - Right': (0x3d, 0x20), 'Ganons Tower - Mini Helmasaur Room - Right': (0x3d, 0x20),
'Ganons Tower - Pre-Moldorm Chest': (0x3d, 0x40), 'Ganons Tower - Pre-Moldorm Chest': (0x3d, 0x40),
'Ganons Tower - Validation Chest': (0x4d, 0x10)} 'Ganons Tower - Validation Chest': (0x4d, 0x10),
'Hyrule Castle - Map Guard Key Drop': (0x72, 0x400),
'Hyrule Castle - Boomerang Guard Key Drop': (0x71, 0x400),
'Hyrule Castle - Key Rat Key Drop': (0x21, 0x400),
'Hyrule Castle - Big Key Drop': (0x80, 0x400),
'Eastern Palace - Dark Square Pot Key': (0xba, 0x400),
'Eastern Palace - Dark Eyegore Key Drop': (0x99, 0x400),
'Desert Palace - Desert Tiles 1 Pot Key': (0x63, 0x400),
'Desert Palace - Beamos Hall Pot Key': (0x53, 0x400),
'Desert Palace - Desert Tiles 2 Pot Key': (0x43, 0x400),
'Castle Tower - Dark Archer Key Drop': (0xc0, 0x400),
'Castle Tower - Circle of Pots Key Drop': (0xb0, 0x400),
'Swamp Palace - Pot Row Pot Key': (0x38, 0x400),
'Swamp Palace - Trench 1 Pot Key': (0x37, 0x400),
'Swamp Palace - Hookshot Pot Key': (0x36, 0x400),
'Swamp Palace - Trench 2 Pot Key': (0x35, 0x400),
'Swamp Palace - Waterway Pot Key': (0x16, 0x400),
'Skull Woods - West Lobby Pot Key': (0x56, 0x400),
'Skull Woods - Spike Corner Key Drop': (0x39, 0x400),
'Thieves\' Town - Hallway Pot Key': (0xbc, 0x400),
'Thieves\' Town - Spike Switch Pot Key': (0xab, 0x400),
'Ice Palace - Jelly Key Drop': (0x0e, 0x400),
'Ice Palace - Conveyor Key Drop': (0x3e, 0x400),
'Ice Palace - Hammer Block Key Drop': (0x3f, 0x400),
'Ice Palace - Many Pots Pot Key': (0x9f, 0x400),
'Misery Mire - Spikes Pot Key': (0xb3, 0x400),
'Misery Mire - Fishbone Pot Key': (0xa1, 0x400),
'Misery Mire - Conveyor Crystal Key Drop': (0xc1, 0x400),
'Turtle Rock - Pokey 1 Key Drop': (0xb6, 0x400),
'Turtle Rock - Pokey 2 Key Drop': (0x13, 0x400),
'Ganons Tower - Conveyor Cross Pot Key': (0x8b, 0x400),
'Ganons Tower - Double Switch Pot Key': (0x9b, 0x400),
'Ganons Tower - Conveyor Star Pits Pot Key': (0x7b, 0x400),
'Ganons Tower - Mini Helmasaur Key Drop': (0x3d, 0x400)}
location_table_npc = {'Mushroom': 0x1000, location_table_npc = {'Mushroom': 0x1000,
'King Zora': 0x2, 'King Zora': 0x2,
'Sahasrahla': 0x10, 'Sahasrahla': 0x10,
@ -822,7 +855,7 @@ async def process_server_cmd(ctx: Context, cmd, args):
ctx.player_names = {p: n for p, n in args[1]} ctx.player_names = {p: n for p, n in args[1]}
msgs = [] msgs = []
if ctx.locations_checked: if ctx.locations_checked:
msgs.append(['LocationChecks', [Regions.location_table[loc][0] for loc in ctx.locations_checked]]) msgs.append(['LocationChecks', [Regions.lookup_name_to_id[loc] for loc in ctx.locations_checked]])
if ctx.locations_scouted: if ctx.locations_scouted:
msgs.append(['LocationScouts', list(ctx.locations_scouted)]) msgs.append(['LocationScouts', list(ctx.locations_scouted)])
if msgs: if msgs:
@ -837,7 +870,7 @@ async def process_server_cmd(ctx: Context, cmd, args):
elif start_index != len(ctx.items_received): elif start_index != len(ctx.items_received):
sync_msg = [['Sync']] sync_msg = [['Sync']]
if ctx.locations_checked: if ctx.locations_checked:
sync_msg.append(['LocationChecks', [Regions.location_table[loc][0] for loc in ctx.locations_checked]]) sync_msg.append(['LocationChecks', [Regions.lookup_name_to_id[loc] for loc in ctx.locations_checked]])
await ctx.send_msgs(sync_msg) await ctx.send_msgs(sync_msg)
if start_index == len(ctx.items_received): if start_index == len(ctx.items_received):
for item in items: for item in items:
@ -1014,6 +1047,11 @@ class ClientCommandProcessor(CommandProcessor):
self.output('Missing: ' + location) self.output('Missing: ' + location)
count += 1 count += 1
for location in [k for k, v in Regions.key_drop_data.items()]:
if location not in self.ctx.locations_checked:
self.output('Missing: ' + location)
count += 1
if count: if count:
self.output(f"Found {count} missing location checks") self.output(f"Found {count} missing location checks")
else: else:
@ -1077,11 +1115,14 @@ async def track_locations(ctx : Context, roomid, roomdata):
ctx.locations_checked.add(location) ctx.locations_checked.add(location)
ctx.ui_node.log_info("New check: %s (%d/216)" % (location, len(ctx.locations_checked))) ctx.ui_node.log_info("New check: %s (%d/216)" % (location, len(ctx.locations_checked)))
ctx.ui_node.send_location_check(ctx, location) ctx.ui_node.send_location_check(ctx, location)
new_locations.append(Regions.location_table[location][0]) new_locations.append(Regions.lookup_name_to_id[location])
for location, (loc_roomid, loc_mask) in location_table_uw.items(): for location, (loc_roomid, loc_mask) in location_table_uw.items():
if location not in ctx.locations_checked and loc_roomid == roomid and (roomdata << 4) & loc_mask != 0: try:
new_check(location) if location not in ctx.locations_checked and loc_roomid == roomid and (roomdata << 4) & loc_mask != 0:
new_check(location)
except Exception as e:
ctx.ui_node.log_info(f"Exception: {e}")
uw_begin = 0x129 uw_begin = 0x129
uw_end = 0 uw_end = 0

View File

@ -29,7 +29,7 @@ import Utils
from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem, _version_tuple from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem, _version_tuple
from NetUtils import Node, Endpoint from NetUtils import Node, Endpoint
console_names = frozenset(set(Items.item_table) | set(Regions.location_table) | set(Items.item_name_groups)) console_names = frozenset(set(Items.item_table) | set(Regions.location_table) | set(Items.item_name_groups) | set(Regions.key_drop_data))
CLIENT_PLAYING = 0 CLIENT_PLAYING = 0
CLIENT_GOAL = 1 CLIENT_GOAL = 1
@ -439,6 +439,7 @@ def send_new_items(ctx: Context):
def forfeit_player(ctx: Context, team: int, slot: int): def forfeit_player(ctx: Context, team: int, slot: int):
all_locations = {values[0] for values in Regions.location_table.values() if type(values[0]) is int} all_locations = {values[0] for values in Regions.location_table.values() if type(values[0]) is int}
all_locations.update({values[1] for values in Regions.key_drop_data.values()})
ctx.notify_all("%s (Team #%d) has forfeited" % (ctx.player_names[(team, slot)], team + 1)) ctx.notify_all("%s (Team #%d) has forfeited" % (ctx.player_names[(team, slot)], team + 1))
register_location_checks(ctx, team, slot, all_locations) register_location_checks(ctx, team, slot, all_locations)
@ -514,7 +515,7 @@ def collect_hints(ctx: Context, team: int, slot: int, item: str) -> typing.List[
def collect_hints_location(ctx: Context, team: int, slot: int, location: str) -> typing.List[Utils.Hint]: def collect_hints_location(ctx: Context, team: int, slot: int, location: str) -> typing.List[Utils.Hint]:
hints = [] hints = []
seeked_location = Regions.location_table[location][0] seeked_location = Regions.lookup_name_to_id[location]
for check, result in ctx.locations.items(): for check, result in ctx.locations.items():
location_id, finding_player = check location_id, finding_player = check
if finding_player == slot and location_id == seeked_location: if finding_player == slot and location_id == seeked_location:

View File

@ -397,6 +397,42 @@ shop_table = {
'Capacity Upgrade': (0x0115, ShopType.UpgradeShop, 0x04, True, True, [('Bomb Upgrade (+5)', 100, 7), ('Arrow Upgrade (+5)', 100, 7)]) 'Capacity Upgrade': (0x0115, ShopType.UpgradeShop, 0x04, True, True, [('Bomb Upgrade (+5)', 100, 7), ('Arrow Upgrade (+5)', 100, 7)])
} }
key_drop_data = {
'Hyrule Castle - Map Guard Key Drop': [0x140036, 0x140037],
'Hyrule Castle - Boomerang Guard Key Drop': [0x140033, 0x140034],
'Hyrule Castle - Key Rat Key Drop': [0x14000c, 0x14000d],
'Hyrule Castle - Big Key Drop': [0x14003c, 0x14003d],
'Eastern Palace - Dark Square Pot Key': [0x14005a, 0x14005b],
'Eastern Palace - Dark Eyegore Key Drop': [0x140048, 0x140049],
'Desert Palace - Desert Tiles 1 Pot Key': [0x140030, 0x140031],
'Desert Palace - Beamos Hall Pot Key': [0x14002a, 0x14002b],
'Desert Palace - Desert Tiles 2 Pot Key': [0x140027, 0x140028],
'Castle Tower - Dark Archer Key Drop': [0x140060, 0x140061],
'Castle Tower - Circle of Pots Key Drop': [0x140051, 0x140052],
'Swamp Palace - Pot Row Pot Key': [0x140018, 0x140019],
'Swamp Palace - Trench 1 Pot Key': [0x140015, 0x140016],
'Swamp Palace - Hookshot Pot Key': [0x140012, 0x140013],
'Swamp Palace - Trench 2 Pot Key': [0x14000f, 0x140010],
'Swamp Palace - Waterway Pot Key': [0x140009, 0x14000a],
'Skull Woods - West Lobby Pot Key': [0x14002d, 0x14002e],
'Skull Woods - Spike Corner Key Drop': [0x14001b, 0x14001c],
'Thieves\' Town - Hallway Pot Key': [0x14005d, 0x14005e],
'Thieves\' Town - Spike Switch Pot Key': [0x14004e, 0x14004f],
'Ice Palace - Jelly Key Drop': [0x140003, 0x140004],
'Ice Palace - Conveyor Key Drop': [0x140021, 0x140022],
'Ice Palace - Hammer Block Key Drop': [0x140024, 0x140025],
'Ice Palace - Many Pots Pot Key': [0x140045, 0x140046],
'Misery Mire - Spikes Pot Key': [0x140054, 0x140055],
'Misery Mire - Fishbone Pot Key': [0x14004b, 0x14004c],
'Misery Mire - Conveyor Crystal Key Drop': [0x140063, 0x140064],
'Turtle Rock - Pokey 1 Key Drop': [0x140057, 0x140058],
'Turtle Rock - Pokey 2 Key Drop': [0x140006, 0x140007],
'Ganons Tower - Conveyor Cross Pot Key': [0x14003f, 0x140040],
'Ganons Tower - Double Switch Pot Key': [0x140042, 0x140043],
'Ganons Tower - Conveyor Star Pits Pot Key': [0x140039, 0x14003a],
'Ganons Tower - Mini Helmasaur Key Drop': [0x14001e, 0x14001f]
}
location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'), location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'),
'Bottle Merchant': (0x2eb18, 0x186339, False, 'with a merchant'), 'Bottle Merchant': (0x2eb18, 0x186339, False, 'with a merchant'),
'Flute Spot': (0x18014a, 0x18633d, False, 'underground'), 'Flute Spot': (0x18014a, 0x18633d, False, 'underground'),
@ -640,7 +676,9 @@ location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'),
[0x120A7, 0x53F24, 0x53F25, 0x18005C, 0x180079, 0xC708], None, True, 'Turtle Rock')} [0x120A7, 0x53F24, 0x53F25, 0x18005C, 0x180079, 0xC708], None, True, 'Turtle Rock')}
lookup_id_to_name = {data[0]: name for name, data in location_table.items() if type(data[0]) == int} lookup_id_to_name = {data[0]: name for name, data in location_table.items() if type(data[0]) == int}
lookup_id_to_name[-1] = "cheat console" lookup_id_to_name = {**lookup_id_to_name, **{data[1]: name for name, data in key_drop_data.items()}, -1: "cheat console"}
lookup_name_to_id = {name: data[0] for name, data in location_table.items() if type(data[0]) == int}
lookup_name_to_id = {**lookup_name_to_id, **{name: data[1] for name, data in key_drop_data.items()}, "cheat console": -1}
lookup_vanilla_location_to_entrance = {1572883: 'Kings Grave Inner Rocks', 191256: 'Kings Grave Inner Rocks', lookup_vanilla_location_to_entrance = {1572883: 'Kings Grave Inner Rocks', 191256: 'Kings Grave Inner Rocks',
1573194: 'Kings Grave Inner Rocks', 1573189: 'Kings Grave Inner Rocks', 1573194: 'Kings Grave Inner Rocks', 1573189: 'Kings Grave Inner Rocks',
@ -745,7 +783,28 @@ lookup_vanilla_location_to_entrance = {1572883: 'Kings Grave Inner Rocks', 19125
60103: 'Ganons Tower', 60106: 'Ganons Tower', 60109: 'Ganons Tower', 60103: 'Ganons Tower', 60106: 'Ganons Tower', 60109: 'Ganons Tower',
60127: 'Ganons Tower', 60118: 'Ganons Tower', 60148: 'Ganons Tower', 60127: 'Ganons Tower', 60118: 'Ganons Tower', 60148: 'Ganons Tower',
60151: 'Ganons Tower', 60145: 'Ganons Tower', 60157: 'Ganons Tower', 60151: 'Ganons Tower', 60145: 'Ganons Tower', 60157: 'Ganons Tower',
60160: 'Ganons Tower', 60163: 'Ganons Tower', 60166: 'Ganons Tower'} 60160: 'Ganons Tower', 60163: 'Ganons Tower', 60166: 'Ganons Tower',
0x140037: 'Hyrule Castle Entrance (South)',
0x140034: 'Hyrule Castle Entrance (South)',
0x14000d: 'Hyrule Castle Entrance (South)',
0x14003d: 'Hyrule Castle Entrance (South)',
0x14005b: 'Eastern Palace', 0x140049: 'Eastern Palace',
0x140031: 'Desert Palace Entrance (North)',
0x14002b: 'Desert Palace Entrance (North)',
0x140028: 'Desert Palace Entrance (North)',
0x140061: 'Agahnims Tower', 0x140052: 'Agahnims Tower',
0x140019: 'Swamp Palace', 0x140016: 'Swamp Palace', 0x140013: 'Swamp Palace',
0x140010: 'Swamp Palace', 0x14000a: 'Swamp Palace',
0x14002e: 'Skull Woods Second Section Door (East)',
0x14001c: 'Skull Woods Final Section',
0x14005e: 'Thieves Town', 0x14004f: 'Thieves Town',
0x140004: 'Ice Palace', 0x140022: 'Ice Palace',
0x140025: 'Ice Palace', 0x140046: 'Ice Palace',
0x140055: 'Misery Mire', 0x14004c: 'Misery Mire',
0x140064: 'Misery Mire',
0x140058: 'Turtle Rock', 0x140007: 'Dark Death Mountain Ledge (West)',
0x140040: 'Ganons Tower', 0x140043: 'Ganons Tower',
0x14003a: 'Ganons Tower', 0x14001f: 'Ganons Tower'}
lookup_prizes = {location for location in location_table if location.endswith(" - Prize")} lookup_prizes = {location for location in location_table if location.endswith(" - Prize")}
lookup_boss_drops = {location for location in location_table if location.endswith(" - Boss")} lookup_boss_drops = {location for location in location_table if location.endswith(" - Boss")}

View File

@ -180,6 +180,25 @@ default_locations = {
60121, 60124, 60127, 1573217, 60130, 60133, 60136, 60139, 60142, 60145, 60148, 60151, 60157}, 60121, 60124, 60127, 1573217, 60130, 60133, 60136, 60139, 60142, 60145, 60148, 60151, 60157},
'Total': set()} 'Total': set()}
key_only_locations = {
'Light World': set(),
'Dark World': set(),
'Desert Palace': {0x140031, 0x14002b, 0x140061, 0x140028},
'Eastern Palace': {0x14005b, 0x140049},
'Hyrule Castle': {0x140037, 0x140034, 0x14000d, 0x14003d},
'Agahnims Tower': {0x140061, 0x140052},
'Tower of Hera': set(),
'Swamp Palace': {0x140019, 0x140016, 0x140013, 0x140010, 0x14000a},
'Thieves Town': {0x14005e, 0x14004f},
'Skull Woods': {0x14002e, 0x14001c},
'Ice Palace': {0x140004, 0x140022, 0x140025, 0x140046},
'Misery Mire': {0x140055, 0x14004c, 0x140064},
'Turtle Rock': {0x140058, 0x140007},
'Palace of Darkness': set(),
'Ganons Tower': {0x140040, 0x140043, 0x14003a, 0x14001f},
'Total': set()
}
key_locations = {"Desert Palace", "Eastern Palace", "Hyrule Castle", "Agahnims Tower", "Tower of Hera", "Swamp Palace", key_locations = {"Desert Palace", "Eastern Palace", "Hyrule Castle", "Agahnims Tower", "Tower of Hera", "Swamp Palace",
"Thieves Town", "Skull Woods", "Ice Palace", "Misery Mire", "Turtle Rock", "Palace of Darkness", "Thieves Town", "Skull Woods", "Ice Palace", "Misery Mire", "Turtle Rock", "Palace of Darkness",
"Ganons Tower"} "Ganons Tower"}
@ -191,6 +210,10 @@ for area, locations in default_locations.items():
for location in locations: for location in locations:
location_to_area[location] = area location_to_area[location] = area
for area, locations in key_only_locations.items():
for location in locations:
location_to_area[location] = area
checks_in_area = {area: len(checks) for area, checks in default_locations.items()} checks_in_area = {area: len(checks) for area, checks in default_locations.items()}
checks_in_area["Total"] = 216 checks_in_area["Total"] = 216
@ -244,11 +267,16 @@ def get_static_room_data(room: Room):
# in > 100 players this can take a bit of time and is the main reason for the cache # in > 100 players this can take a bit of time and is the main reason for the cache
locations = {tuple(k): tuple(v) for k, v in multidata['locations']} locations = {tuple(k): tuple(v) for k, v in multidata['locations']}
names = multidata["names"] names = multidata["names"]
seed_checks_in_area = checks_in_area.copy()
use_door_tracker = False use_door_tracker = False
if "tags" in multidata: if "tags" in multidata:
use_door_tracker = "DR" in multidata["tags"] use_door_tracker = "DR" in multidata["tags"]
result = locations, names, use_door_tracker if use_door_tracker:
for area, checks in key_only_locations.items():
seed_checks_in_area[area] += len(checks)
seed_checks_in_area["Total"] = 249
result = locations, names, use_door_tracker, seed_checks_in_area
_multidata_cache[room.seed.id] = result _multidata_cache[room.seed.id] = result
return result return result
@ -259,7 +287,7 @@ def get_tracker(tracker: UUID):
room = Room.get(tracker=tracker) room = Room.get(tracker=tracker)
if not room: if not room:
abort(404) abort(404)
locations, names, use_door_tracker = get_static_room_data(room) locations, names, use_door_tracker, seed_checks_in_area = get_static_room_data(room)
inventory = {teamnumber: {playernumber: collections.Counter() for playernumber in range(1, len(team) + 1)} inventory = {teamnumber: {playernumber: collections.Counter() for playernumber in range(1, len(team) + 1)}
for teamnumber, team in enumerate(names)} for teamnumber, team in enumerate(names)}
@ -280,6 +308,9 @@ def get_tracker(tracker: UUID):
for item_id in precollected: for item_id in precollected:
attribute_item(inventory, team, player, item_id) attribute_item(inventory, team, player, item_id)
for location in locations_checked: for location in locations_checked:
if (location, player) not in locations or location not in location_to_area:
continue
item, recipient = locations[location, player] item, recipient = locations[location, player]
attribute_item(inventory, team, recipient, item) attribute_item(inventory, team, recipient, item)
checks_done[team][player][location_to_area[location]] += 1 checks_done[team][player][location_to_area[location]] += 1
@ -311,7 +342,7 @@ def get_tracker(tracker: UUID):
lookup_id_to_name=Items.lookup_id_to_name, player_names=player_names, lookup_id_to_name=Items.lookup_id_to_name, player_names=player_names,
tracking_names=tracking_names, tracking_ids=tracking_ids, room=room, icons=icons, tracking_names=tracking_names, tracking_ids=tracking_ids, room=room, icons=icons,
multi_items=multi_items, checks_done=checks_done, ordered_areas=ordered_areas, multi_items=multi_items, checks_done=checks_done, ordered_areas=ordered_areas,
checks_in_area=checks_in_area, activity_timers=activity_timers, checks_in_area=seed_checks_in_area, activity_timers=activity_timers,
key_locations=key_locations, small_key_ids=small_key_ids, big_key_ids=big_key_ids, key_locations=key_locations, small_key_ids=small_key_ids, big_key_ids=big_key_ids,
video=video, big_key_locations=key_locations if use_door_tracker else big_key_locations, video=video, big_key_locations=key_locations if use_door_tracker else big_key_locations,
hints=hints, long_player_names = long_player_names) hints=hints, long_player_names = long_player_names)