Skip to content

Commit f8e1d2e

Browse files
committed
Merge branch 'main' into smw-main
2 parents 4a2eab8 + 02d3eef commit f8e1d2e

Some content is hidden

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

66 files changed

+1034
-623
lines changed

BaseClasses.py

+50-8
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
from __future__ import annotations
2-
from argparse import Namespace
32

43
import copy
5-
from enum import unique, IntEnum, IntFlag
6-
import logging
7-
import json
84
import functools
5+
import json
6+
import logging
7+
import random
8+
import secrets
9+
import typing # this can go away when Python 3.8 support is dropped
10+
from argparse import Namespace
911
from collections import OrderedDict, Counter, deque
12+
from enum import unique, IntEnum, IntFlag
1013
from typing import List, Dict, Optional, Set, Iterable, Union, Any, Tuple, TypedDict, Callable, NamedTuple
11-
import typing # this can go away when Python 3.8 support is dropped
12-
import secrets
13-
import random
1414

15+
import NetUtils
1516
import Options
1617
import Utils
17-
import NetUtils
1818

1919

2020
class Group(TypedDict, total=False):
@@ -48,6 +48,7 @@ class MultiWorld():
4848
precollected_items: Dict[int, List[Item]]
4949
state: CollectionState
5050

51+
plando_options: PlandoOptions
5152
accessibility: Dict[int, Options.Accessibility]
5253
early_items: Dict[int, Dict[str, int]]
5354
local_early_items: Dict[int, Dict[str, int]]
@@ -160,6 +161,7 @@ def set_player_attr(attr, val):
160161
self.custom_data = {}
161162
self.worlds = {}
162163
self.slot_seeds = {}
164+
self.plando_options = PlandoOptions.none
163165

164166
def get_all_ids(self) -> Tuple[int, ...]:
165167
return self.player_ids + tuple(self.groups)
@@ -1558,6 +1560,7 @@ def write_option(option_key: str, option_obj: type(Options.Option)):
15581560
Utils.__version__, self.multiworld.seed))
15591561
outfile.write('Filling Algorithm: %s\n' % self.multiworld.algorithm)
15601562
outfile.write('Players: %d\n' % self.multiworld.players)
1563+
outfile.write(f'Plando Options: {self.multiworld.plando_options}\n')
15611564
AutoWorld.call_stage(self.multiworld, "write_spoiler_header", outfile)
15621565

15631566
for player in range(1, self.multiworld.players + 1):
@@ -1674,6 +1677,45 @@ class Tutorial(NamedTuple):
16741677
authors: List[str]
16751678

16761679

1680+
class PlandoOptions(IntFlag):
1681+
none = 0b0000
1682+
items = 0b0001
1683+
connections = 0b0010
1684+
texts = 0b0100
1685+
bosses = 0b1000
1686+
1687+
@classmethod
1688+
def from_option_string(cls, option_string: str) -> PlandoOptions:
1689+
result = cls(0)
1690+
for part in option_string.split(","):
1691+
part = part.strip().lower()
1692+
if part:
1693+
result = cls._handle_part(part, result)
1694+
return result
1695+
1696+
@classmethod
1697+
def from_set(cls, option_set: Set[str]) -> PlandoOptions:
1698+
result = cls(0)
1699+
for part in option_set:
1700+
result = cls._handle_part(part, result)
1701+
return result
1702+
1703+
@classmethod
1704+
def _handle_part(cls, part: str, base: PlandoOptions) -> PlandoOptions:
1705+
try:
1706+
part = cls[part]
1707+
except Exception as e:
1708+
raise KeyError(f"{part} is not a recognized name for a plando module. "
1709+
f"Known options: {', '.join(flag.name for flag in cls)}") from e
1710+
else:
1711+
return base | part
1712+
1713+
def __str__(self) -> str:
1714+
if self.value:
1715+
return ", ".join(flag.name for flag in PlandoOptions if self.value & flag.value)
1716+
return "None"
1717+
1718+
16771719
seeddigits = 20
16781720

16791721

CommonClient.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ def gui_error(self, title: str, text: typing.Union[Exception, str]) -> typing.Op
494494
self._messagebox.open()
495495
return self._messagebox
496496

497-
def _handle_connection_loss(self, msg: str) -> None:
497+
def handle_connection_loss(self, msg: str) -> None:
498498
"""Helper for logging and displaying a loss of connection. Must be called from an except block."""
499499
exc_info = sys.exc_info()
500500
logger.exception(msg, exc_info=exc_info, extra={'compact_gui': True})
@@ -580,14 +580,22 @@ def reconnect_hint() -> str:
580580
for msg in decode(data):
581581
await process_server_cmd(ctx, msg)
582582
logger.warning(f"Disconnected from multiworld server{reconnect_hint()}")
583+
except websockets.InvalidMessage:
584+
# probably encrypted
585+
if address.startswith("ws://"):
586+
await server_loop(ctx, "ws" + address[1:])
587+
else:
588+
ctx.handle_connection_loss(f"Lost connection to the multiworld server due to InvalidMessage"
589+
f"{reconnect_hint()}")
583590
except ConnectionRefusedError:
584-
ctx._handle_connection_loss("Connection refused by the server. May not be running Archipelago on that address or port.")
591+
ctx.handle_connection_loss("Connection refused by the server. "
592+
"May not be running Archipelago on that address or port.")
585593
except websockets.InvalidURI:
586-
ctx._handle_connection_loss("Failed to connect to the multiworld server (invalid URI)")
594+
ctx.handle_connection_loss("Failed to connect to the multiworld server (invalid URI)")
587595
except OSError:
588-
ctx._handle_connection_loss("Failed to connect to the multiworld server")
596+
ctx.handle_connection_loss("Failed to connect to the multiworld server")
589597
except Exception:
590-
ctx._handle_connection_loss(f"Lost connection to the multiworld server{reconnect_hint()}")
598+
ctx.handle_connection_loss(f"Lost connection to the multiworld server{reconnect_hint()}")
591599
finally:
592600
await ctx.connection_closed()
593601
if ctx.server_address and ctx.username and not ctx.disconnected_intentionally:

Generate.py

+16-51
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22

33
import argparse
44
import logging
5+
import os
56
import random
6-
import urllib.request
7+
import string
78
import urllib.parse
8-
from typing import Set, Dict, Tuple, Callable, Any, Union
9-
import os
9+
import urllib.request
1010
from collections import Counter, ChainMap
11-
import string
12-
import enum
11+
from typing import Dict, Tuple, Callable, Any, Union
1312

1413
import ModuleUpdate
1514

@@ -18,52 +17,17 @@
1817
import Utils
1918
from worlds.alttp import Options as LttPOptions
2019
from worlds.generic import PlandoConnection
21-
from Utils import parse_yamls, version_tuple, __version__, tuplize_version, get_options, local_path, user_path
20+
from Utils import parse_yamls, version_tuple, __version__, tuplize_version, get_options, user_path
2221
from worlds.alttp.EntranceRandomizer import parse_arguments
2322
from Main import main as ERmain
24-
from BaseClasses import seeddigits, get_seed
23+
from BaseClasses import seeddigits, get_seed, PlandoOptions
2524
import Options
2625
from worlds.alttp.Text import TextTable
2726
from worlds.AutoWorld import AutoWorldRegister
2827
import copy
2928

3029

31-
class PlandoSettings(enum.IntFlag):
32-
items = 0b0001
33-
connections = 0b0010
34-
texts = 0b0100
35-
bosses = 0b1000
36-
37-
@classmethod
38-
def from_option_string(cls, option_string: str) -> PlandoSettings:
39-
result = cls(0)
40-
for part in option_string.split(","):
41-
part = part.strip().lower()
42-
if part:
43-
result = cls._handle_part(part, result)
44-
return result
45-
46-
@classmethod
47-
def from_set(cls, option_set: Set[str]) -> PlandoSettings:
48-
result = cls(0)
49-
for part in option_set:
50-
result = cls._handle_part(part, result)
51-
return result
52-
53-
@classmethod
54-
def _handle_part(cls, part: str, base: PlandoSettings) -> PlandoSettings:
55-
try:
56-
part = cls[part]
57-
except Exception as e:
58-
raise KeyError(f"{part} is not a recognized name for a plando module. "
59-
f"Known options: {', '.join(flag.name for flag in cls)}") from e
60-
else:
61-
return base | part
6230

63-
def __str__(self) -> str:
64-
if self.value:
65-
return ", ".join(flag.name for flag in PlandoSettings if self.value & flag.value)
66-
return "Off"
6731

6832

6933
def mystery_argparse():
@@ -97,7 +61,7 @@ def resolve_path(path: str, resolver: Callable[[str], str]) -> str:
9761
args.weights_file_path = os.path.join(args.player_files_path, args.weights_file_path)
9862
if not os.path.isabs(args.meta_file_path):
9963
args.meta_file_path = os.path.join(args.player_files_path, args.meta_file_path)
100-
args.plando: PlandoSettings = PlandoSettings.from_option_string(args.plando)
64+
args.plando: PlandoOptions = PlandoOptions.from_option_string(args.plando)
10165
return args, options
10266

10367

@@ -170,6 +134,7 @@ def main(args=None, callback=ERmain):
170134
f"A mix is also permitted.")
171135
erargs = parse_arguments(['--multi', str(args.multi)])
172136
erargs.seed = seed
137+
erargs.plando_options = args.plando
173138
erargs.glitch_triforce = options["generator"]["glitch_triforce_room"]
174139
erargs.spoiler = args.spoiler
175140
erargs.race = args.race
@@ -226,7 +191,7 @@ def main(args=None, callback=ERmain):
226191
elif not erargs.name[player]: # if name was not specified, generate it from filename
227192
erargs.name[player] = os.path.splitext(os.path.split(path)[-1])[0]
228193
erargs.name[player] = handle_name(erargs.name[player], player, name_counter)
229-
194+
230195
player += 1
231196
except Exception as e:
232197
raise ValueError(f"File {path} is destroyed. Please fix your yaml.") from e
@@ -443,7 +408,7 @@ def roll_triggers(weights: dict, triggers: list) -> dict:
443408
return weights
444409

445410

446-
def handle_option(ret: argparse.Namespace, game_weights: dict, option_key: str, option: type(Options.Option), plando_options: PlandoSettings):
411+
def handle_option(ret: argparse.Namespace, game_weights: dict, option_key: str, option: type(Options.Option), plando_options: PlandoOptions):
447412
if option_key in game_weights:
448413
try:
449414
if not option.supports_weighting:
@@ -459,7 +424,7 @@ def handle_option(ret: argparse.Namespace, game_weights: dict, option_key: str,
459424
setattr(ret, option_key, option.from_any(option.default)) # call the from_any here to support default "random"
460425

461426

462-
def roll_settings(weights: dict, plando_options: PlandoSettings = PlandoSettings.bosses):
427+
def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.bosses):
463428
if "linked_options" in weights:
464429
weights = roll_linked_options(weights)
465430

@@ -472,7 +437,7 @@ def roll_settings(weights: dict, plando_options: PlandoSettings = PlandoSettings
472437
if tuplize_version(version) > version_tuple:
473438
raise Exception(f"Settings reports required version of generator is at least {version}, "
474439
f"however generator is of version {__version__}")
475-
required_plando_options = PlandoSettings.from_option_string(requirements.get("plando", ""))
440+
required_plando_options = PlandoOptions.from_option_string(requirements.get("plando", ""))
476441
if required_plando_options not in plando_options:
477442
if required_plando_options:
478443
raise Exception(f"Settings reports required plando module {str(required_plando_options)}, "
@@ -506,12 +471,12 @@ def roll_settings(weights: dict, plando_options: PlandoSettings = PlandoSettings
506471
if option_key not in world_type.option_definitions and \
507472
(option_key not in Options.common_options or option_key in game_weights):
508473
handle_option(ret, game_weights, option_key, option, plando_options)
509-
if PlandoSettings.items in plando_options:
474+
if PlandoOptions.items in plando_options:
510475
ret.plando_items = game_weights.get("plando_items", [])
511476
if ret.game == "Minecraft" or ret.game == "Ocarina of Time":
512477
# bad hardcoded behavior to make this work for now
513478
ret.plando_connections = []
514-
if PlandoSettings.connections in plando_options:
479+
if PlandoOptions.connections in plando_options:
515480
options = game_weights.get("plando_connections", [])
516481
for placement in options:
517482
if roll_percentage(get_choice("percentage", placement, 100)):
@@ -626,7 +591,7 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
626591
raise Exception(f"unknown Medallion {medallion} for {'misery mire' if index == 0 else 'turtle rock'}")
627592

628593
ret.plando_texts = {}
629-
if PlandoSettings.texts in plando_options:
594+
if PlandoOptions.texts in plando_options:
630595
tt = TextTable()
631596
tt.removeUnwantedText()
632597
options = weights.get("plando_texts", [])
@@ -638,7 +603,7 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
638603
ret.plando_texts[at] = str(get_choice_legacy("text", placement))
639604

640605
ret.plando_connections = []
641-
if PlandoSettings.connections in plando_options:
606+
if PlandoOptions.connections in plando_options:
642607
options = weights.get("plando_connections", [])
643608
for placement in options:
644609
if roll_percentage(get_choice_legacy("percentage", placement, 100)):

Main.py

+1-21
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
3838

3939
logger = logging.getLogger()
4040
world.set_seed(seed, args.race, str(args.outputname if args.outputname else world.seed))
41+
world.plando_options = args.plando_options
4142

4243
world.shuffle = args.shuffle.copy()
4344
world.logic = args.logic.copy()
@@ -291,27 +292,6 @@ def find_common_pool(players: Set[int], shared_pool: Set[str]) -> Tuple[
291292
checks_in_area[location.player]["Dark World"].append(location.address)
292293
checks_in_area[location.player]["Total"] += 1
293294

294-
oldmancaves = []
295-
takeanyregions = ["Old Man Sword Cave", "Take-Any #1", "Take-Any #2", "Take-Any #3", "Take-Any #4"]
296-
for index, take_any in enumerate(takeanyregions):
297-
for region in [world.get_region(take_any, player) for player in
298-
world.get_game_players("A Link to the Past") if world.retro_caves[player]]:
299-
item = world.create_item(
300-
region.shop.inventory[(0 if take_any == "Old Man Sword Cave" else 1)]['item'],
301-
region.player)
302-
player = region.player
303-
location_id = SHOP_ID_START + total_shop_slots + index
304-
305-
main_entrance = region.get_connecting_entrance(is_main_entrance)
306-
if main_entrance.parent_region.type == RegionType.LightWorld:
307-
checks_in_area[player]["Light World"].append(location_id)
308-
else:
309-
checks_in_area[player]["Dark World"].append(location_id)
310-
checks_in_area[player]["Total"] += 1
311-
312-
er_hint_data[player][location_id] = main_entrance.name
313-
oldmancaves.append(((location_id, player), (item.code, player)))
314-
315295
FillDisabledShopSlots(world)
316296

317297
def write_multidata():

0 commit comments

Comments
 (0)