Skip to content

Commit 8a9c729

Browse files
Merge branch 'main' into deathlink
2 parents 85cd9ee + 6a08064 commit 8a9c729

73 files changed

Lines changed: 1374 additions & 544 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎BaseClasses.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ def set_item_links(self):
261261
"local_items": set(item_link.get("local_items", [])),
262262
"non_local_items": set(item_link.get("non_local_items", [])),
263263
"link_replacement": replacement_prio.index(item_link["link_replacement"]),
264+
"skip_if_solo": item_link.get("skip_if_solo", False),
264265
}
265266

266267
for _name, item_link in item_links.items():
@@ -284,6 +285,8 @@ def set_item_links(self):
284285

285286
for group_name, item_link in item_links.items():
286287
game = item_link["game"]
288+
if item_link["skip_if_solo"] and len(item_link["players"]) == 1:
289+
continue
287290
group_id, group = self.add_group(group_name, game, set(item_link["players"]))
288291

289292
group["item_pool"] = item_link["item_pool"]

‎Generate.py‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,22 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b
486486
if required_plando_options:
487487
raise Exception(f"Settings reports required plando module {str(required_plando_options)}, "
488488
f"which is not enabled.")
489-
489+
games = requirements.get("game", {})
490+
for game, version in games.items():
491+
if game not in AutoWorldRegister.world_types:
492+
continue
493+
if not version:
494+
raise Exception(f"Invalid version for game {game}: {version}.")
495+
if isinstance(version, str):
496+
version = {"min": version}
497+
if "min" in version and tuplize_version(version["min"]) > AutoWorldRegister.world_types[game].world_version:
498+
raise Exception(f"Settings reports required version of world \"{game}\" is at least {version['min']}, "
499+
f"however world is of version "
500+
f"{AutoWorldRegister.world_types[game].world_version.as_simple_string()}.")
501+
if "max" in version and tuplize_version(version["max"]) < AutoWorldRegister.world_types[game].world_version:
502+
raise Exception(f"Settings reports required version of world \"{game}\" is no later than {version['max']}, "
503+
f"however world is of version "
504+
f"{AutoWorldRegister.world_types[game].world_version.as_simple_string()}.")
490505
ret = argparse.Namespace()
491506
for option_key in Options.PerGameCommonOptions.type_hints:
492507
if option_key in weights and option_key not in Options.CommonOptions.type_hints:

‎LinksAwakeningClient.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,10 @@ async def recved_item_from_ap(self, item_id, from_player, next_index):
412412
status = (await self.gameboy.async_read_memory_safe(LAClientConstants.wLinkStatusBits))[0]
413413

414414
item_id -= LABaseID
415-
# The player name table only goes up to 100, so don't go past that
415+
# The player name table only goes up to 101, so don't go past that
416416
# Even if it didn't, the remote player _index_ byte is just a byte, so 255 max
417-
if from_player > 100:
418-
from_player = 100
417+
if from_player > 101:
418+
from_player = 101
419419

420420
next_index += 1
421421
self.gameboy.write_memory(LAClientConstants.wLinkGiveItem, [

‎Main.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ def main(args, seed=None, baked_server_options: dict[str, object] | None = None)
5959

6060
for name, cls in AutoWorld.AutoWorldRegister.world_types.items():
6161
if not cls.hidden and len(cls.item_names) > 0:
62-
logger.info(f" {name:{longest_name}}: Items: {len(cls.item_names):{item_count}} | "
62+
logger.info(f" {name:{longest_name}}: "
63+
f"v{cls.world_version.as_simple_string()} |"
64+
f"Items: {len(cls.item_names):{item_count}} | "
6365
f"Locations: {len(cls.location_names):{location_count}}")
6466

6567
del item_count, location_count

‎MultiServer.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1321,7 +1321,8 @@ def get_help_text(self) -> str:
13211321
argname += "=" + parameter.default
13221322
argtext += argname
13231323
argtext += " "
1324-
s += f"{self.marker}{command} {argtext}\n {method.__doc__}\n"
1324+
doctext = '\n '.join(inspect.getdoc(method).split('\n'))
1325+
s += f"{self.marker}{command} {argtext}\n {doctext}\n"
13251326
return s
13261327

13271328
def _cmd_help(self):

‎Options.py‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,7 @@ class ItemLinks(OptionList):
14461446
Optional("local_items"): [And(str, len)],
14471447
Optional("non_local_items"): [And(str, len)],
14481448
Optional("link_replacement"): Or(None, bool),
1449+
Optional("skip_if_solo"): Or(None, bool),
14491450
}
14501451
])
14511452

@@ -1709,7 +1710,7 @@ def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], ge
17091710
from jinja2 import Template
17101711

17111712
from worlds import AutoWorldRegister
1712-
from Utils import local_path, __version__
1713+
from Utils import local_path, __version__, tuplize_version
17131714

17141715
full_path: str
17151716

@@ -1752,7 +1753,10 @@ def yaml_dump_scalar(scalar) -> str:
17521753

17531754
res = template.render(
17541755
option_groups=option_groups,
1755-
__version__=__version__, game=game_name, yaml_dump=yaml_dump_scalar,
1756+
__version__=__version__,
1757+
game=game_name,
1758+
world_version=world.world_version.as_simple_string(),
1759+
yaml_dump=yaml_dump_scalar,
17561760
dictify_range=dictify_range,
17571761
cleandoc=cleandoc,
17581762
)

‎Utils.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ def as_simple_string(self) -> str:
4949

5050
__version__ = "0.6.4"
5151
version_tuple = tuplize_version(__version__)
52+
version = Version(*version_tuple)
5253

5354
is_linux = sys.platform.startswith("linux")
5455
is_macos = sys.platform == "darwin"
@@ -322,11 +323,13 @@ def get_options() -> Settings:
322323
return get_settings()
323324

324325

325-
def persistent_store(category: str, key: str, value: typing.Any):
326-
path = user_path("_persistent_storage.yaml")
326+
def persistent_store(category: str, key: str, value: typing.Any, force_store: bool = False):
327327
storage = persistent_load()
328+
if not force_store and category in storage and key in storage[category] and storage[category][key] == value:
329+
return # no changes necessary
328330
category_dict = storage.setdefault(category, {})
329331
category_dict[key] = value
332+
path = user_path("_persistent_storage.yaml")
330333
with open(path, "wt") as f:
331334
f.write(dump(storage, Dumper=Dumper))
332335

‎WebHost.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ def copy_tutorials_files_to_static() -> None:
109109
logging.exception(e)
110110
logging.warning("Could not update LttP sprites.")
111111
app = get_app()
112+
from worlds import AutoWorldRegister
113+
# Update to only valid WebHost worlds
114+
invalid_worlds = {name for name, world in AutoWorldRegister.world_types.items()
115+
if not hasattr(world.web, "tutorials")}
116+
if invalid_worlds:
117+
logging.error(f"Following worlds not loaded as they are invalid for WebHost: {invalid_worlds}")
118+
AutoWorldRegister.world_types = {k: v for k, v in AutoWorldRegister.world_types.items() if k not in invalid_worlds}
112119
create_options_files()
113120
copy_tutorials_files_to_static()
114121
if app.config["SELFLAUNCH"]:

‎WebHostLib/api/tracker.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ class PlayerStatus(TypedDict):
5252
status: ClientStatus
5353

5454

55+
class PlayerLocationsTotal(TypedDict):
56+
team: int
57+
player: int
58+
total_locations: int
59+
60+
5561
@api_endpoints.route("/tracker/<suuid:tracker>")
5662
@cache.memoize(timeout=60)
5763
def tracker_data(tracker: UUID) -> dict[str, Any]:
@@ -195,9 +201,16 @@ def static_tracker_data(tracker: UUID) -> dict[str, Any]:
195201
})
196202
break
197203

204+
player_locations_total: list[PlayerLocationsTotal] = []
205+
for team, players in all_players.items():
206+
for player in players:
207+
player_locations_total.append(
208+
{"team": team, "player": player, "total_locations": len(tracker_data.get_player_locations(player))})
209+
198210
return {
199211
"groups": groups,
200212
"datapackage": tracker_data._multidata["datapackage"],
213+
"player_locations_total": player_locations_total,
201214
}
202215

203216
# It should be exceedingly rare that slot data is needed, so it's separated out.

‎data/options.yaml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ description: {{ yaml_dump("Default %s Template" % game) }}
3333
game: {{ yaml_dump(game) }}
3434
requires:
3535
version: {{ __version__ }} # Version of Archipelago required for this yaml to work as expected.
36+
{%- if world_version != "0.0.0" %}
37+
game:
38+
{{ yaml_dump(game) }}: {{ world_version }} # Version of the world required for this yaml to work as expected.
39+
{%- endif %}
3640

3741
{%- macro range_option(option) %}
3842
# You can define additional values between the minimum and maximum values.

0 commit comments

Comments
 (0)