Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] main from ArchipelagoMW:main #52

Merged
merged 19 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
283d1ab
DLC Quest Bug Fix 50+ coin bundle basic Campaign (#4276)
axe-y Nov 29, 2024
3ba0576
CV64: Fix the first Waterway 3HB ledge setting the flag of one of the…
LiquidCat64 Nov 29, 2024
4780fd9
The Witness: Rename some *horrendously* named variables (#4258)
NewSoupVi Nov 29, 2024
5d30d16
Docs: Mention explicit_indirect_conditions & "Menu" -> origin_region_…
NewSoupVi Nov 29, 2024
3cb5219
Core: Fix playthrough only checking half of the sphere 0 items (#4268)
Mysteryem Nov 29, 2024
c022c74
Core: Add item.filler helper (#4081)
Exempt-Medic Nov 29, 2024
ce78c75
OoT: Turn Logic Tricks into an OptionSet (#3551)
Exempt-Medic Nov 29, 2024
62e4285
Core: Make region.add_exits return the created Entrances (#3885)
NewSoupVi Nov 29, 2024
82260d7
The Witness: Add Fast Travel Option (#3766)
NewSoupVi Nov 29, 2024
710cf4e
Core: Add __iter__ to VerifyKeys (#3550)
NewSoupVi Nov 29, 2024
1ba7700
Muse Dash: Change AttributeError to KeyError when Create_Item receive…
DeamonHunter Nov 29, 2024
faeb542
Super Mario 64: Option groups (#4161)
josephwhite Nov 29, 2024
b972e8c
Core: fix deprecation warning for utcnow() in setup.py (#4170)
Berserker66 Nov 29, 2024
b783eab
Core: Introduce 'Hint Priority' concept (#3506)
EmilyV99 Nov 29, 2024
8923b06
Webhost: Make YGO 06 setup title match page #4262
BootsinSoots Nov 29, 2024
ce210cd
SMZ3: Add Start Inventory From Pool (#4252)
dontjoome Nov 29, 2024
30b4144
LTTP: sort of use new options system (#3764)
Berserker66 Nov 29, 2024
1371c63
Core: Actually take item from pool when plandoing from_pool (#2420)
NewSoupVi Nov 29, 2024
91185f4
Core: Add timestamps to logging for seed generation (#3028)
kedNalatacId Nov 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions BaseClasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,7 @@ def create_exit(self, name: str) -> Entrance:
return exit_

def add_exits(self, exits: Union[Iterable[str], Dict[str, Optional[str]]],
rules: Dict[str, Callable[[CollectionState], bool]] = None) -> None:
rules: Dict[str, Callable[[CollectionState], bool]] = None) -> List[Entrance]:
"""
Connects current region to regions in exit dictionary. Passed region names must exist first.

Expand All @@ -1120,10 +1120,14 @@ def add_exits(self, exits: Union[Iterable[str], Dict[str, Optional[str]]],
"""
if not isinstance(exits, Dict):
exits = dict.fromkeys(exits)
for connecting_region, name in exits.items():
self.connect(self.multiworld.get_region(connecting_region, self.player),
name,
rules[connecting_region] if rules and connecting_region in rules else None)
return [
self.connect(
self.multiworld.get_region(connecting_region, self.player),
name,
rules[connecting_region] if rules and connecting_region in rules else None,
)
for connecting_region, name in exits.items()
]

def __repr__(self):
return self.multiworld.get_name_string_for_object(self) if self.multiworld else f'{self.name} (Player {self.player})'
Expand Down Expand Up @@ -1262,6 +1266,10 @@ def useful(self) -> bool:
def trap(self) -> bool:
return ItemClassification.trap in self.classification

@property
def filler(self) -> bool:
return not (self.advancement or self.useful or self.trap)

@property
def excludable(self) -> bool:
return not (self.advancement or self.useful)
Expand Down Expand Up @@ -1384,14 +1392,21 @@ def create_playthrough(self, create_paths: bool = True) -> None:

# second phase, sphere 0
removed_precollected: List[Item] = []
for item in (i for i in chain.from_iterable(multiworld.precollected_items.values()) if i.advancement):
logging.debug('Checking if %s (Player %d) is required to beat the game.', item.name, item.player)
multiworld.precollected_items[item.player].remove(item)
multiworld.state.remove(item)
if not multiworld.can_beat_game():
multiworld.push_precollected(item)
else:
removed_precollected.append(item)

for precollected_items in multiworld.precollected_items.values():
# The list of items is mutated by removing one item at a time to determine if each item is required to beat
# the game, and re-adding that item if it was required, so a copy needs to be made before iterating.
for item in precollected_items.copy():
if not item.advancement:
continue
logging.debug('Checking if %s (Player %d) is required to beat the game.', item.name, item.player)
precollected_items.remove(item)
multiworld.state.remove(item)
if not multiworld.can_beat_game():
# Add the item back into `precollected_items` and collect it into `multiworld.state`.
multiworld.push_precollected(item)
else:
removed_precollected.append(item)

# we are now down to just the required progress items in collection_spheres. Unfortunately
# the previous pruning stage could potentially have made certain items dependant on others
Expand Down
12 changes: 10 additions & 2 deletions CommonClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from MultiServer import CommandProcessor
from NetUtils import (Endpoint, decode, NetworkItem, encode, JSONtoTextParser, ClientStatus, Permission, NetworkSlot,
RawJSONtoTextParser, add_json_text, add_json_location, add_json_item, JSONTypes, SlotType)
RawJSONtoTextParser, add_json_text, add_json_location, add_json_item, JSONTypes, HintStatus, SlotType)
from Utils import Version, stream_input, async_start
from worlds import network_data_package, AutoWorldRegister
import os
Expand Down Expand Up @@ -412,6 +412,7 @@ async def disconnect(self, allow_autoreconnect: bool = False):
await self.server.socket.close()
if self.server_task is not None:
await self.server_task
self.ui.update_hints()

async def send_msgs(self, msgs: typing.List[typing.Any]) -> None:
""" `msgs` JSON serializable """
Expand Down Expand Up @@ -551,7 +552,14 @@ async def shutdown(self):
await self.ui_task
if self.input_task:
self.input_task.cancel()


# Hints
def update_hint(self, location: int, finding_player: int, status: typing.Optional[HintStatus]) -> None:
msg = {"cmd": "UpdateHint", "location": location, "player": finding_player}
if status is not None:
msg["status"] = status
async_start(self.send_msgs([msg]), name="update_hint")

# DataPackage
async def prepare_data_package(self, relevant_games: typing.Set[str],
remote_date_package_versions: typing.Dict[str, int],
Expand Down
39 changes: 28 additions & 11 deletions Fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -978,15 +978,32 @@ def failed(warning: str, force: typing.Union[bool, str]) -> None:
multiworld.random.shuffle(items)
count = 0
err: typing.List[str] = []
successful_pairs: typing.List[typing.Tuple[Item, Location]] = []
successful_pairs: typing.List[typing.Tuple[int, Item, Location]] = []
claimed_indices: typing.Set[typing.Optional[int]] = set()
for item_name in items:
item = multiworld.worlds[player].create_item(item_name)
index_to_delete: typing.Optional[int] = None
if from_pool:
try:
# If from_pool, try to find an existing item with this name & player in the itempool and use it
index_to_delete, item = next(
(i, item) for i, item in enumerate(multiworld.itempool)
if item.player == player and item.name == item_name and i not in claimed_indices
)
except StopIteration:
warn(
f"Could not remove {item_name} from pool for {multiworld.player_name[player]} as it's already missing from it.",
placement['force'])
item = multiworld.worlds[player].create_item(item_name)
else:
item = multiworld.worlds[player].create_item(item_name)

for location in reversed(candidates):
if (location.address is None) == (item.code is None): # either both None or both not None
if not location.item:
if location.item_rule(item):
if location.can_fill(multiworld.state, item, False):
successful_pairs.append((item, location))
successful_pairs.append((index_to_delete, item, location))
claimed_indices.add(index_to_delete)
candidates.remove(location)
count = count + 1
break
Expand All @@ -998,24 +1015,24 @@ def failed(warning: str, force: typing.Union[bool, str]) -> None:
err.append(f"Cannot place {item_name} into already filled location {location}.")
else:
err.append(f"Mismatch between {item_name} and {location}, only one is an event.")

if count == maxcount:
break
if count < placement['count']['min']:
m = placement['count']['min']
failed(
f"Plando block failed to place {m - count} of {m} item(s) for {multiworld.player_name[player]}, error(s): {' '.join(err)}",
placement['force'])
for (item, location) in successful_pairs:

# Sort indices in reverse so we can remove them one by one
successful_pairs = sorted(successful_pairs, key=lambda successful_pair: successful_pair[0] or 0, reverse=True)

for (index, item, location) in successful_pairs:
multiworld.push_item(location, item, collect=False)
location.locked = True
logging.debug(f"Plando placed {item} at {location}")
if from_pool:
try:
multiworld.itempool.remove(item)
except ValueError:
warn(
f"Could not remove {item} from pool for {multiworld.player_name[player]} as it's already missing from it.",
placement['force'])
if index is not None: # If this item is from_pool and was found in the pool, remove it.
multiworld.itempool.pop(index)

except Exception as e:
raise Exception(
Expand Down
2 changes: 1 addition & 1 deletion Main.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ def write_multidata():
def precollect_hint(location):
entrance = er_hint_data.get(location.player, {}).get(location.address, "")
hint = NetUtils.Hint(location.item.player, location.player, location.address,
location.item.code, False, entrance, location.item.flags)
location.item.code, False, entrance, location.item.flags, False)
precollected_hints[location.player].add(hint)
if location.item.player not in multiworld.groups:
precollected_hints[location.item.player].add(hint)
Expand Down
Loading
Loading