Skip to content

Commit

Permalink
Merge branch 'ArchipelagoMW:main' into mmx2
Browse files Browse the repository at this point in the history
  • Loading branch information
TheLX5 authored Aug 24, 2024
2 parents 5542d99 + 0fcca25 commit e417ab3
Show file tree
Hide file tree
Showing 184 changed files with 76,770 additions and 15,090 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
worlds/blasphemous/region_data.py linguist-generated=true
164 changes: 81 additions & 83 deletions BaseClasses.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion CommonClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def update_game(self, game: str, name_to_id_lookup_table: typing.Dict[str, int])
starting_reconnect_delay: int = 5
current_reconnect_delay: int = starting_reconnect_delay
command_processor: typing.Type[CommandProcessor] = ClientCommandProcessor
ui = None
ui: typing.Optional["kvui.GameManager"] = None
ui_task: typing.Optional["asyncio.Task[None]"] = None
input_task: typing.Optional["asyncio.Task[None]"] = None
keep_alive_task: typing.Optional["asyncio.Task[None]"] = None
Expand Down
33 changes: 20 additions & 13 deletions Fill.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@


class FillError(RuntimeError):
pass
def __init__(self, *args: typing.Union[str, typing.Any], **kwargs) -> None:
if "multiworld" in kwargs and isinstance(args[0], str):
placements = (args[0] + f"\nAll Placements:\n" +
f"{[(loc, loc.item) for loc in kwargs['multiworld'].get_filled_locations()]}")
args = (placements, *args[1:])
super().__init__(*args)


def _log_fill_progress(name: str, placed: int, total_items: int) -> None:
Expand All @@ -24,7 +29,7 @@ def sweep_from_pool(base_state: CollectionState, itempool: typing.Sequence[Item]
new_state = base_state.copy()
for item in itempool:
new_state.collect(item, True)
new_state.sweep_for_events(locations=locations)
new_state.sweep_for_advancements(locations=locations)
return new_state


Expand Down Expand Up @@ -212,7 +217,7 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
f"Unfilled locations:\n"
f"{', '.join(str(location) for location in locations)}\n"
f"Already placed {len(placements)}:\n"
f"{', '.join(str(place) for place in placements)}")
f"{', '.join(str(place) for place in placements)}", multiworld=multiworld)

item_pool.extend(unplaced_items)

Expand Down Expand Up @@ -299,7 +304,7 @@ def remaining_fill(multiworld: MultiWorld,
f"Unfilled locations:\n"
f"{', '.join(str(location) for location in locations)}\n"
f"Already placed {len(placements)}:\n"
f"{', '.join(str(place) for place in placements)}")
f"{', '.join(str(place) for place in placements)}", multiworld=multiworld)

itempool.extend(unplaced_items)

Expand All @@ -324,8 +329,8 @@ def accessibility_corrections(multiworld: MultiWorld, state: CollectionState, lo
pool.append(location.item)
state.remove(location.item)
location.item = None
if location in state.events:
state.events.remove(location)
if location in state.advancements:
state.advancements.remove(location)
locations.append(location)
if pool and locations:
locations.sort(key=lambda loc: loc.progress_type != LocationProgressType.PRIORITY)
Expand Down Expand Up @@ -358,7 +363,7 @@ def distribute_early_items(multiworld: MultiWorld,
early_priority_locations: typing.List[Location] = []
loc_indexes_to_remove: typing.Set[int] = set()
base_state = multiworld.state.copy()
base_state.sweep_for_events(locations=(loc for loc in multiworld.get_filled_locations() if loc.address is None))
base_state.sweep_for_advancements(locations=(loc for loc in multiworld.get_filled_locations() if loc.address is None))
for i, loc in enumerate(fill_locations):
if loc.can_reach(base_state):
if loc.progress_type == LocationProgressType.PRIORITY:
Expand Down Expand Up @@ -506,7 +511,8 @@ def mark_for_locking(location: Location):
if progitempool:
raise FillError(
f"Not enough locations for progression items. "
f"There are {len(progitempool)} more progression items than there are available locations."
f"There are {len(progitempool)} more progression items than there are available locations.",
multiworld=multiworld,
)
accessibility_corrections(multiworld, multiworld.state, defaultlocations)

Expand All @@ -523,7 +529,8 @@ def mark_for_locking(location: Location):
if excludedlocations:
raise FillError(
f"Not enough filler items for excluded locations. "
f"There are {len(excludedlocations)} more excluded locations than filler or trap items."
f"There are {len(excludedlocations)} more excluded locations than filler or trap items.",
multiworld=multiworld,
)

restitempool = filleritempool + usefulitempool
Expand Down Expand Up @@ -551,7 +558,7 @@ def flood_items(multiworld: MultiWorld) -> None:
progress_done = False

# sweep once to pick up preplaced items
multiworld.state.sweep_for_events()
multiworld.state.sweep_for_advancements()

# fill multiworld from top of itempool while we can
while not progress_done:
Expand Down Expand Up @@ -589,7 +596,7 @@ def flood_items(multiworld: MultiWorld) -> None:
if candidate_item_to_place is not None:
item_to_place = candidate_item_to_place
else:
raise FillError('No more progress items left to place.')
raise FillError('No more progress items left to place.', multiworld=multiworld)

# find item to replace with progress item
location_list = multiworld.get_reachable_locations()
Expand Down Expand Up @@ -739,7 +746,7 @@ def item_percentage(player: int, num: int) -> float:
), items_to_test):
reducing_state.collect(location.item, True, location)

reducing_state.sweep_for_events(locations=locations_to_test)
reducing_state.sweep_for_advancements(locations=locations_to_test)

if multiworld.has_beaten_game(balancing_state):
if not multiworld.has_beaten_game(reducing_state):
Expand Down Expand Up @@ -822,7 +829,7 @@ def failed(warning: str, force: typing.Union[bool, str]) -> None:
warn(warning, force)

swept_state = multiworld.state.copy()
swept_state.sweep_for_events()
swept_state.sweep_for_advancements()
reachable = frozenset(multiworld.get_reachable_locations(swept_state))
early_locations: typing.Dict[int, typing.List[str]] = collections.defaultdict(list)
non_early_locations: typing.Dict[int, typing.List[str]] = collections.defaultdict(list)
Expand Down
2 changes: 1 addition & 1 deletion Generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b
continue
logging.warning(f"{option_key} is not a valid option name for {ret.game} and is not present in triggers.")
if PlandoOptions.items in plando_options:
ret.plando_items = game_weights.get("plando_items", [])
ret.plando_items = copy.deepcopy(game_weights.get("plando_items", []))
if ret.game == "A Link to the Past":
roll_alttp_settings(ret, game_weights)

Expand Down
9 changes: 9 additions & 0 deletions KH1Client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
if __name__ == '__main__':
import ModuleUpdate
ModuleUpdate.update()

import Utils
Utils.init_logging("KH1Client", exception_logger="Client")

from worlds.kh1.Client import launch
launch()
2 changes: 1 addition & 1 deletion Launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def _on_drop_file(self, window: Window, filename: bytes, x: int, y: int) -> None
if file and component:
run_component(component, file)
else:
logging.warning(f"unable to identify component for {filename}")
logging.warning(f"unable to identify component for {file}")

def _stop(self, *largs):
# ran into what appears to be https://groups.google.com/g/kivy-users/c/saWDLoYCSZ4 with PyCharm.
Expand Down
34 changes: 17 additions & 17 deletions LttPAdjuster.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from argparse import Namespace
from concurrent.futures import as_completed, ThreadPoolExecutor
from glob import glob
from tkinter import Tk, Frame, Label, StringVar, Entry, filedialog, messagebox, Button, Radiobutton, LEFT, X, TOP, LabelFrame, \
from tkinter import Tk, Frame, Label, StringVar, Entry, filedialog, messagebox, Button, Radiobutton, LEFT, X, BOTH, TOP, LabelFrame, \
IntVar, Checkbutton, E, W, OptionMenu, Toplevel, BOTTOM, RIGHT, font as font, PhotoImage
from tkinter.constants import DISABLED, NORMAL
from urllib.parse import urlparse
Expand All @@ -29,7 +29,8 @@


GAME_ALTTP = "A Link to the Past"

WINDOW_MIN_HEIGHT = 525
WINDOW_MIN_WIDTH = 425

class AdjusterWorld(object):
def __init__(self, sprite_pool):
Expand Down Expand Up @@ -242,16 +243,17 @@ def adjustGUI():
from argparse import Namespace
from Utils import __version__ as MWVersion
adjustWindow = Tk()
adjustWindow.minsize(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT)
adjustWindow.wm_title("Archipelago %s LttP Adjuster" % MWVersion)
set_icon(adjustWindow)

rom_options_frame, rom_vars, set_sprite = get_rom_options_frame(adjustWindow)

bottomFrame2 = Frame(adjustWindow)
bottomFrame2 = Frame(adjustWindow, padx=8, pady=2)

romFrame, romVar = get_rom_frame(adjustWindow)

romDialogFrame = Frame(adjustWindow)
romDialogFrame = Frame(adjustWindow, padx=8, pady=2)
baseRomLabel2 = Label(romDialogFrame, text='Rom to adjust')
romVar2 = StringVar()
romEntry2 = Entry(romDialogFrame, textvariable=romVar2)
Expand All @@ -261,9 +263,9 @@ def RomSelect2():
romVar2.set(rom)

romSelectButton2 = Button(romDialogFrame, text='Select Rom', command=RomSelect2)
romDialogFrame.pack(side=TOP, expand=True, fill=X)
baseRomLabel2.pack(side=LEFT)
romEntry2.pack(side=LEFT, expand=True, fill=X)
romDialogFrame.pack(side=TOP, expand=False, fill=X)
baseRomLabel2.pack(side=LEFT, expand=False, fill=X, padx=(0, 8))
romEntry2.pack(side=LEFT, expand=True, fill=BOTH, pady=1)
romSelectButton2.pack(side=LEFT)

def adjustRom():
Expand Down Expand Up @@ -331,12 +333,11 @@ def saveGUISettings():
messagebox.showinfo(title="Success", message="Settings saved to persistent storage")

adjustButton = Button(bottomFrame2, text='Adjust Rom', command=adjustRom)
rom_options_frame.pack(side=TOP)
rom_options_frame.pack(side=TOP, padx=8, pady=8, fill=BOTH, expand=True)
adjustButton.pack(side=LEFT, padx=(5,5))

saveButton = Button(bottomFrame2, text='Save Settings', command=saveGUISettings)
saveButton.pack(side=LEFT, padx=(5,5))

bottomFrame2.pack(side=TOP, pady=(5,5))

tkinter_center_window(adjustWindow)
Expand Down Expand Up @@ -576,7 +577,7 @@ def hide(self):
def get_rom_frame(parent=None):
adjuster_settings = get_adjuster_settings(GAME_ALTTP)

romFrame = Frame(parent)
romFrame = Frame(parent, padx=8, pady=8)
baseRomLabel = Label(romFrame, text='LttP Base Rom: ')
romVar = StringVar(value=adjuster_settings.baserom)
romEntry = Entry(romFrame, textvariable=romVar)
Expand All @@ -596,20 +597,19 @@ def RomSelect():
romSelectButton = Button(romFrame, text='Select Rom', command=RomSelect)

baseRomLabel.pack(side=LEFT)
romEntry.pack(side=LEFT, expand=True, fill=X)
romEntry.pack(side=LEFT, expand=True, fill=BOTH, pady=1)
romSelectButton.pack(side=LEFT)
romFrame.pack(side=TOP, expand=True, fill=X)
romFrame.pack(side=TOP, fill=X)

return romFrame, romVar

def get_rom_options_frame(parent=None):
adjuster_settings = get_adjuster_settings(GAME_ALTTP)

romOptionsFrame = LabelFrame(parent, text="Rom options")
romOptionsFrame.columnconfigure(0, weight=1)
romOptionsFrame.columnconfigure(1, weight=1)
romOptionsFrame = LabelFrame(parent, text="Rom options", padx=8, pady=8)

for i in range(5):
romOptionsFrame.rowconfigure(i, weight=1)
romOptionsFrame.rowconfigure(i, weight=0, pad=4)
vars = Namespace()

vars.MusicVar = IntVar()
Expand Down Expand Up @@ -660,7 +660,7 @@ def SpriteSelect():
spriteSelectButton = Button(spriteDialogFrame, text='...', command=SpriteSelect)

baseSpriteLabel.pack(side=LEFT)
spriteEntry.pack(side=LEFT)
spriteEntry.pack(side=LEFT, expand=True, fill=X)
spriteSelectButton.pack(side=LEFT)

oofDialogFrame = Frame(romOptionsFrame)
Expand Down
22 changes: 14 additions & 8 deletions Main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

import worlds
from BaseClasses import CollectionState, Item, Location, LocationProgressType, MultiWorld, Region
from Fill import balance_multiworld_progression, distribute_items_restrictive, distribute_planned, flood_items
from Fill import FillError, balance_multiworld_progression, distribute_items_restrictive, distribute_planned, \
flood_items
from Options import StartInventoryPool
from Utils import __version__, output_path, version_tuple, get_settings
from settings import get_settings
Expand Down Expand Up @@ -100,7 +101,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
multiworld.early_items[player][item_name] = max(0, early-count)
remaining_count = count-early
if remaining_count > 0:
local_early = multiworld.early_local_items[player].get(item_name, 0)
local_early = multiworld.local_early_items[player].get(item_name, 0)
if local_early:
multiworld.early_items[player][item_name] = max(0, local_early - remaining_count)
del local_early
Expand Down Expand Up @@ -151,6 +152,7 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
# Because some worlds don't actually create items during create_items this has to be as late as possible.
if any(getattr(multiworld.worlds[player].options, "start_inventory_from_pool", None) for player in multiworld.player_ids):
new_items: List[Item] = []
old_items: List[Item] = []
depletion_pool: Dict[int, Dict[str, int]] = {
player: getattr(multiworld.worlds[player].options,
"start_inventory_from_pool",
Expand All @@ -169,20 +171,24 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
depletion_pool[item.player][item.name] -= 1
# quick abort if we have found all items
if not target:
new_items.extend(multiworld.itempool[i+1:])
old_items.extend(multiworld.itempool[i+1:])
break
else:
new_items.append(item)
old_items.append(item)

# leftovers?
if target:
for player, remaining_items in depletion_pool.items():
remaining_items = {name: count for name, count in remaining_items.items() if count}
if remaining_items:
raise Exception(f"{multiworld.get_player_name(player)}"
logger.warning(f"{multiworld.get_player_name(player)}"
f" is trying to remove items from their pool that don't exist: {remaining_items}")
assert len(multiworld.itempool) == len(new_items), "Item Pool amounts should not change."
multiworld.itempool[:] = new_items
# find all filler we generated for the current player and remove until it matches
removables = [item for item in new_items if item.player == player]
for _ in range(sum(remaining_items.values())):
new_items.remove(removables.pop())
assert len(multiworld.itempool) == len(new_items + old_items), "Item Pool amounts should not change."
multiworld.itempool[:] = new_items + old_items

multiworld.link_items()

Expand Down Expand Up @@ -341,7 +347,7 @@ def precollect_hint(location):
output_file_futures.append(pool.submit(write_multidata))
if not check_accessibility_task.result():
if not multiworld.can_beat_game():
raise Exception("Game appears as unbeatable. Aborting.")
raise FillError("Game appears as unbeatable. Aborting.", multiworld=multiworld)
else:
logger.warning("Location Accessibility requirements not fulfilled.")

Expand Down
18 changes: 9 additions & 9 deletions MultiServer.py
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ def collect_player(ctx: Context, team: int, slot: int, is_group: bool = False):
collect_player(ctx, team, group, True)


def get_remaining(ctx: Context, team: int, slot: int) -> typing.List[int]:
def get_remaining(ctx: Context, team: int, slot: int) -> typing.List[typing.Tuple[int, int]]:
return ctx.locations.get_remaining(ctx.location_checks, team, slot)


Expand Down Expand Up @@ -1350,10 +1350,10 @@ def _cmd_collect(self) -> bool:
def _cmd_remaining(self) -> bool:
"""List remaining items in your game, but not their location or recipient"""
if self.ctx.remaining_mode == "enabled":
remaining_item_ids = get_remaining(self.ctx, self.client.team, self.client.slot)
if remaining_item_ids:
self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[self.client.slot]][item_id]
for item_id in remaining_item_ids))
rest_locations = get_remaining(self.ctx, self.client.team, self.client.slot)
if rest_locations:
self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[slot]][item_id]
for slot, item_id in rest_locations))
else:
self.output("No remaining items found.")
return True
Expand All @@ -1363,10 +1363,10 @@ def _cmd_remaining(self) -> bool:
return False
else: # is goal
if self.ctx.client_game_state[self.client.team, self.client.slot] == ClientStatus.CLIENT_GOAL:
remaining_item_ids = get_remaining(self.ctx, self.client.team, self.client.slot)
if remaining_item_ids:
self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[self.client.slot]][item_id]
for item_id in remaining_item_ids))
rest_locations = get_remaining(self.ctx, self.client.team, self.client.slot)
if rest_locations:
self.output("Remaining items: " + ", ".join(self.ctx.item_names[self.ctx.games[slot]][item_id]
for slot, item_id in rest_locations))
else:
self.output("No remaining items found.")
return True
Expand Down
9 changes: 5 additions & 4 deletions NetUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class NetworkItem(typing.NamedTuple):
item: int
location: int
player: int
""" Sending player, except in LocationInfo (from LocationScouts), where it is the receiving player. """
flags: int = 0


Expand Down Expand Up @@ -397,12 +398,12 @@ def get_missing(self, state: typing.Dict[typing.Tuple[int, int], typing.Set[int]
location_id not in checked]

def get_remaining(self, state: typing.Dict[typing.Tuple[int, int], typing.Set[int]], team: int, slot: int
) -> typing.List[int]:
) -> typing.List[typing.Tuple[int, int]]:
checked = state[team, slot]
player_locations = self[slot]
return sorted([player_locations[location_id][0] for
location_id in player_locations if
location_id not in checked])
return sorted([(player_locations[location_id][1], player_locations[location_id][0]) for
location_id in player_locations if
location_id not in checked])


if typing.TYPE_CHECKING: # type-check with pure python implementation until we have a typing stub
Expand Down
Loading

0 comments on commit e417ab3

Please sign in to comment.