Skip to content

Commit

Permalink
Merge branch 'ArchipelagoMW:main' into anxm2r
Browse files Browse the repository at this point in the history
  • Loading branch information
Ehseezed authored Dec 8, 2023
2 parents 3f94b9a + abfc2dd commit d136a5f
Show file tree
Hide file tree
Showing 420 changed files with 82,442 additions and 13,226 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
*.apmc
*.apz5
*.aptloz
*.apemerald
*.pyc
*.pyd
*.sfc
*.z64
*.n64
*.nes
*.smc
*.sms
*.gb
*.gbc
Expand Down
42 changes: 27 additions & 15 deletions BaseClasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ def extend(self, regions: Iterable[Region]):
for region in regions:
self.region_cache[region.player][region.name] = region

def add_group(self, new_id: int):
self.region_cache[new_id] = {}
self.entrance_cache[new_id] = {}
self.location_cache[new_id] = {}

def __iter__(self) -> Iterator[Region]:
for regions in self.region_cache.values():
yield from regions.values()
Expand Down Expand Up @@ -220,6 +225,7 @@ def add_group(self, name: str, game: str, players: Set[int] = frozenset()) -> Tu
return group_id, group
new_id: int = self.players + len(self.groups) + 1

self.regions.add_group(new_id)
self.game[new_id] = game
self.player_types[new_id] = NetUtils.SlotType.group
world_type = AutoWorld.AutoWorldRegister.world_types[game]
Expand Down Expand Up @@ -605,7 +611,7 @@ def all_done() -> bool:


class CollectionState():
prog_items: typing.Counter[Tuple[str, int]]
prog_items: Dict[int, Counter[str]]
multiworld: MultiWorld
reachable_regions: Dict[int, Set[Region]]
blocked_connections: Dict[int, Set[Entrance]]
Expand All @@ -617,7 +623,7 @@ class CollectionState():
additional_copy_functions: List[Callable[[CollectionState, CollectionState], CollectionState]] = []

def __init__(self, parent: MultiWorld):
self.prog_items = Counter()
self.prog_items = {player: Counter() for player in parent.get_all_ids()}
self.multiworld = parent
self.reachable_regions = {player: set() for player in parent.get_all_ids()}
self.blocked_connections = {player: set() for player in parent.get_all_ids()}
Expand Down Expand Up @@ -665,7 +671,7 @@ def update_reachable_regions(self, player: int):

def copy(self) -> CollectionState:
ret = CollectionState(self.multiworld)
ret.prog_items = self.prog_items.copy()
ret.prog_items = copy.deepcopy(self.prog_items)
ret.reachable_regions = {player: copy.copy(self.reachable_regions[player]) for player in
self.reachable_regions}
ret.blocked_connections = {player: copy.copy(self.blocked_connections[player]) for player in
Expand Down Expand Up @@ -708,45 +714,51 @@ def sweep_for_events(self, key_only: bool = False, locations: Optional[Iterable[
assert isinstance(event.item, Item), "tried to collect Event with no Item"
self.collect(event.item, True, event)

# item name related
def has(self, item: str, player: int, count: int = 1) -> bool:
return self.prog_items[item, player] >= count
return self.prog_items[player][item] >= count

def has_all(self, items: Set[str], player: int) -> bool:
def has_all(self, items: Iterable[str], player: int) -> bool:
"""Returns True if each item name of items is in state at least once."""
return all(self.prog_items[item, player] for item in items)
return all(self.prog_items[player][item] for item in items)

def has_any(self, items: Set[str], player: int) -> bool:
def has_any(self, items: Iterable[str], player: int) -> bool:
"""Returns True if at least one item name of items is in state at least once."""
return any(self.prog_items[item, player] for item in items)
return any(self.prog_items[player][item] for item in items)

def count(self, item: str, player: int) -> int:
return self.prog_items[item, player]
return self.prog_items[player][item]

def item_count(self, item: str, player: int) -> int:
Utils.deprecate("Use count instead.")
return self.count(item, player)

# item name group related
def has_group(self, item_name_group: str, player: int, count: int = 1) -> bool:
found: int = 0
player_prog_items = self.prog_items[player]
for item_name in self.multiworld.worlds[player].item_name_groups[item_name_group]:
found += self.prog_items[item_name, player]
found += player_prog_items[item_name]
if found >= count:
return True
return False

def count_group(self, item_name_group: str, player: int) -> int:
found: int = 0
player_prog_items = self.prog_items[player]
for item_name in self.multiworld.worlds[player].item_name_groups[item_name_group]:
found += self.prog_items[item_name, player]
found += player_prog_items[item_name]
return found

def item_count(self, item: str, player: int) -> int:
return self.prog_items[item, player]

# Item related
def collect(self, item: Item, event: bool = False, location: Optional[Location] = None) -> bool:
if location:
self.locations_checked.add(location)

changed = self.multiworld.worlds[item.player].collect(self, item)

if not changed and event:
self.prog_items[item.name, item.player] += 1
self.prog_items[item.player][item.name] += 1
changed = True

self.stale[item.player] = True
Expand Down
10 changes: 8 additions & 2 deletions CommonClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,8 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
elif 'InvalidGame' in errors:
ctx.event_invalid_game()
elif 'IncompatibleVersion' in errors:
raise Exception('Server reported your client version as incompatible')
raise Exception('Server reported your client version as incompatible. '
'This probably means you have to update.')
elif 'InvalidItemsHandling' in errors:
raise Exception('The item handling flags requested by the client are not supported')
# last to check, recoverable problem
Expand All @@ -758,6 +759,7 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
ctx.slot_info = {int(pid): data for pid, data in args["slot_info"].items()}
ctx.hint_points = args.get("hint_points", 0)
ctx.consume_players_package(args["players"])
ctx.stored_data_notification_keys.add(f"_read_hints_{ctx.team}_{ctx.slot}")
msgs = []
if ctx.locations_checked:
msgs.append({"cmd": "LocationChecks",
Expand Down Expand Up @@ -836,10 +838,14 @@ async def process_server_cmd(ctx: CommonContext, args: dict):

elif cmd == "Retrieved":
ctx.stored_data.update(args["keys"])
if ctx.ui and f"_read_hints_{ctx.team}_{ctx.slot}" in args["keys"]:
ctx.ui.update_hints()

elif cmd == "SetReply":
ctx.stored_data[args["key"]] = args["value"]
if args["key"].startswith("EnergyLink"):
if ctx.ui and f"_read_hints_{ctx.team}_{ctx.slot}" == args["key"]:
ctx.ui.update_hints()
elif args["key"].startswith("EnergyLink"):
ctx.current_energy_link_value = args["value"]
if ctx.ui:
ctx.ui.set_new_energy_link_value()
Expand Down
7 changes: 5 additions & 2 deletions Fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations:

location.item = None
placed_item.location = None
swap_state = sweep_from_pool(base_state, [placed_item] if unsafe else [])
swap_state = sweep_from_pool(base_state, [placed_item, *item_pool] if unsafe else item_pool)
# unsafe means swap_state assumes we can somehow collect placed_item before item_to_place
# by continuing to swap, which is not guaranteed. This is unsafe because there is no mechanic
# to clean that up later, so there is a chance generation fails.
Expand Down Expand Up @@ -471,7 +471,7 @@ def mark_for_locking(location: Location):
raise FillError(
f"Not enough filler items for excluded locations. There are {len(excludedlocations)} more locations than items")

restitempool = usefulitempool + filleritempool
restitempool = filleritempool + usefulitempool

remaining_fill(world, defaultlocations, restitempool)

Expand Down Expand Up @@ -792,6 +792,9 @@ def failed(warning: str, force: typing.Union[bool, str]) -> None:
block['force'] = 'silent'
if 'from_pool' not in block:
block['from_pool'] = True
elif not isinstance(block['from_pool'], bool):
from_pool_type = type(block['from_pool'])
raise Exception(f'Plando "from_pool" has to be boolean, not {from_pool_type} for player {player}.')
if 'world' not in block:
target_world = False
else:
Expand Down
13 changes: 12 additions & 1 deletion Generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from BaseClasses import seeddigits, get_seed, PlandoOptions
from Main import main as ERmain
from settings import get_settings
from Utils import parse_yamls, version_tuple, __version__, tuplize_version, user_path
from Utils import parse_yamls, version_tuple, __version__, tuplize_version
from worlds.alttp import Options as LttPOptions
from worlds.alttp.EntranceRandomizer import parse_arguments
from worlds.alttp.Text import TextTable
Expand Down Expand Up @@ -53,6 +53,9 @@ def mystery_argparse():
help='List of options that can be set manually. Can be combined, for example "bosses, items"')
parser.add_argument("--skip_prog_balancing", action="store_true",
help="Skip progression balancing step during generation.")
parser.add_argument("--skip_output", action="store_true",
help="Skips generation assertion and output stages and skips multidata and spoiler output. "
"Intended for debugging and testing purposes.")
args = parser.parse_args()
if not os.path.isabs(args.weights_file_path):
args.weights_file_path = os.path.join(args.player_files_path, args.weights_file_path)
Expand Down Expand Up @@ -127,6 +130,13 @@ def main(args=None, callback=ERmain):
player_id += 1

args.multi = max(player_id - 1, args.multi)

if args.multi == 0:
raise ValueError(
"No individual player files found and number of players is 0. "
"Provide individual player files or specify the number of players via host.yaml or --multi."
)

logging.info(f"Generating for {args.multi} player{'s' if args.multi > 1 else ''}, "
f"{seed_name} Seed {seed} with plando: {args.plando}")

Expand All @@ -143,6 +153,7 @@ def main(args=None, callback=ERmain):
erargs.outputname = seed_name
erargs.outputpath = args.outputpath
erargs.skip_prog_balancing = args.skip_prog_balancing
erargs.skip_output = args.skip_output

settings_cache: Dict[str, Tuple[argparse.Namespace, ...]] = \
{fname: (tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.samesettings else None)
Expand Down
Loading

0 comments on commit d136a5f

Please sign in to comment.