Skip to content

Commit

Permalink
Lingo: Pre-compile datafile to improve loading time (ArchipelagoMW#2829)
Browse files Browse the repository at this point in the history
  • Loading branch information
hatkirby authored and EmilyV99 committed Apr 15, 2024
1 parent 5ef1f76 commit 49555c1
Show file tree
Hide file tree
Showing 13 changed files with 626 additions and 515 deletions.
8 changes: 4 additions & 4 deletions worlds/lingo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

from BaseClasses import Item, ItemClassification, Tutorial
from worlds.AutoWorld import WebWorld, World
from .datatypes import Room, RoomEntrance
from .items import ALL_ITEM_TABLE, LingoItem
from .locations import ALL_LOCATION_TABLE
from .options import LingoOptions
from .player_logic import LingoPlayerLogic
from .regions import create_regions
from .static_logic import Room, RoomEntrance


class LingoWebWorld(WebWorld):
Expand Down Expand Up @@ -100,9 +100,9 @@ def create_item(self, name: str) -> Item:
item = ALL_ITEM_TABLE[name]

classification = item.classification
if hasattr(self, "options") and self.options.shuffle_paintings and len(item.painting_ids) > 0\
and len(item.door_ids) == 0 and all(painting_id not in self.player_logic.painting_mapping
for painting_id in item.painting_ids)\
if hasattr(self, "options") and self.options.shuffle_paintings and len(item.painting_ids) > 0 \
and not item.has_doors and all(painting_id not in self.player_logic.painting_mapping
for painting_id in item.painting_ids) \
and "pilgrim_painting2" not in item.painting_ids:
# If this is a "door" that just moves one or more paintings, and painting shuffle is on and those paintings
# go nowhere, then this item should not be progression. The Pilgrim Room painting is special and needs to be
Expand Down
5 changes: 5 additions & 0 deletions worlds/lingo/data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# lingo data

The source of truth for the Lingo randomizer is (currently) the LL1.yaml and ids.yaml files located here. These files are used by the generator, the game client, and the tracker, in order to have logic that is consistent across them all.

The generator does not actually read in the yaml files. Instead, a compiled datafile called generated.dat is also located in this directory. If you update LL1.yaml and/or ids.yaml, you must also regenerate the datafile using `python worlds/lingo/utils/pickle_static_data.py`. A unit test will fail if you don't.
Binary file added worlds/lingo/data/generated.dat
Binary file not shown.
67 changes: 67 additions & 0 deletions worlds/lingo/datatypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from typing import List, NamedTuple, Optional


class RoomAndDoor(NamedTuple):
room: Optional[str]
door: str


class RoomAndPanel(NamedTuple):
room: Optional[str]
panel: str


class RoomEntrance(NamedTuple):
room: str # source room
door: Optional[RoomAndDoor]
painting: bool


class Room(NamedTuple):
name: str
entrances: List[RoomEntrance]


class Door(NamedTuple):
name: str
item_name: str
location_name: Optional[str]
panels: Optional[List[RoomAndPanel]]
skip_location: bool
skip_item: bool
has_doors: bool
painting_ids: List[str]
event: bool
group: Optional[str]
include_reduce: bool
junk_item: bool


class Panel(NamedTuple):
required_rooms: List[str]
required_doors: List[RoomAndDoor]
required_panels: List[RoomAndPanel]
colors: List[str]
check: bool
event: bool
exclude_reduce: bool
achievement: bool
non_counting: bool


class Painting(NamedTuple):
id: str
room: str
enter_only: bool
exit_only: bool
required: bool
required_when_no_doors: bool
required_door: Optional[RoomAndDoor]
disable: bool
req_blocked: bool
req_blocked_when_no_doors: bool


class Progression(NamedTuple):
item_name: str
index: int
12 changes: 6 additions & 6 deletions worlds/lingo/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ItemData(NamedTuple):
code: int
classification: ItemClassification
mode: Optional[str]
door_ids: List[str]
has_doors: bool
painting_ids: List[str]

def should_include(self, world: "LingoWorld") -> bool:
Expand Down Expand Up @@ -61,19 +61,19 @@ def load_item_data():
door_mode = "doors"
else:
door_mode = "complex door"
door_groups.setdefault(door.group, []).extend(door.door_ids)
door_groups.setdefault(door.group, [])

if room_name in PROGRESSION_BY_ROOM and door_name in PROGRESSION_BY_ROOM[room_name]:
door_mode = "special"

ALL_ITEM_TABLE[door.item_name] = \
ItemData(get_door_item_id(room_name, door_name),
ItemClassification.filler if door.junk_item else ItemClassification.progression, door_mode,
door.door_ids, door.painting_ids)
door.has_doors, door.painting_ids)

for group, group_door_ids in door_groups.items():
ALL_ITEM_TABLE[group] = ItemData(get_door_group_item_id(group),
ItemClassification.progression, "door group", group_door_ids, [])
ItemClassification.progression, "door group", True, [])

special_items: Dict[str, ItemClassification] = {
":)": ItemClassification.filler,
Expand All @@ -88,11 +88,11 @@ def load_item_data():

for item_name, classification in special_items.items():
ALL_ITEM_TABLE[item_name] = ItemData(get_special_item_id(item_name), classification,
"special", [], [])
"special", False, [])

for item_name in PROGRESSIVE_ITEMS:
ALL_ITEM_TABLE[item_name] = ItemData(get_progressive_item_id(item_name),
ItemClassification.progression, "special", [], [])
ItemClassification.progression, "special", False, [])


# Initialize the item data at module scope.
Expand Down
11 changes: 2 additions & 9 deletions worlds/lingo/locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from typing import Dict, List, NamedTuple

from BaseClasses import Location
from .static_logic import DOORS_BY_ROOM, PANELS_BY_ROOM, RoomAndPanel, get_door_location_id, get_panel_location_id
from .datatypes import RoomAndPanel
from .static_logic import DOORS_BY_ROOM, PANELS_BY_ROOM, get_door_location_id, get_panel_location_id


class LocationClassification(Flag):
Expand All @@ -20,14 +21,6 @@ class LocationData(NamedTuple):
panels: List[RoomAndPanel]
classification: LocationClassification

def panel_ids(self):
ids = set()
for panel in self.panels:
effective_room = self.room if panel.room is None else panel.room
panel_data = PANELS_BY_ROOM[effective_room][panel.panel]
ids = ids | set(panel_data.internal_ids)
return ids


class LingoLocation(Location):
"""
Expand Down
11 changes: 6 additions & 5 deletions worlds/lingo/player_logic.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from enum import Enum
from typing import Dict, List, NamedTuple, Optional, Set, Tuple, TYPE_CHECKING

from .datatypes import Door, RoomAndDoor, RoomAndPanel
from .items import ALL_ITEM_TABLE
from .locations import ALL_LOCATION_TABLE, LocationClassification
from .options import LocationChecks, ShuffleDoors, VictoryCondition
from .static_logic import DOORS_BY_ROOM, Door, PAINTINGS, PAINTINGS_BY_ROOM, PAINTING_ENTRANCES, PAINTING_EXITS, \
PANELS_BY_ROOM, PROGRESSION_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS, RoomAndDoor, \
RoomAndPanel
from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \
PANELS_BY_ROOM, PROGRESSION_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS

if TYPE_CHECKING:
from . import LingoWorld
Expand Down Expand Up @@ -279,8 +279,9 @@ def __init__(self, world: "LingoWorld"):

# When painting shuffle is off, most Starting Room paintings give color hallways access. The Wondrous's
# painting does not, but it gives access to SHRINK and WELCOME BACK.
for painting_obj in PAINTINGS_BY_ROOM["Starting Room"]:
if not painting_obj.enter_only or painting_obj.required_door is None:
for painting_obj in PAINTINGS.values():
if not painting_obj.enter_only or painting_obj.required_door is None\
or painting_obj.room != "Starting Room":
continue

# If painting shuffle is on, we only want to consider paintings that actually go somewhere.
Expand Down
3 changes: 2 additions & 1 deletion worlds/lingo/regions.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from typing import Dict, Optional, TYPE_CHECKING

from BaseClasses import Entrance, ItemClassification, Region
from .datatypes import Room, RoomAndDoor
from .items import LingoItem
from .locations import LingoLocation
from .player_logic import LingoPlayerLogic
from .rules import lingo_can_use_entrance, make_location_lambda
from .static_logic import ALL_ROOMS, PAINTINGS, Room, RoomAndDoor
from .static_logic import ALL_ROOMS, PAINTINGS

if TYPE_CHECKING:
from . import LingoWorld
Expand Down
3 changes: 2 additions & 1 deletion worlds/lingo/rules.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from typing import TYPE_CHECKING

from BaseClasses import CollectionState
from .datatypes import RoomAndDoor
from .player_logic import AccessRequirements, LingoPlayerLogic, PlayerLocation
from .static_logic import PROGRESSION_BY_ROOM, PROGRESSIVE_ITEMS, RoomAndDoor
from .static_logic import PROGRESSION_BY_ROOM, PROGRESSIVE_ITEMS

if TYPE_CHECKING:
from . import LingoWorld
Expand Down
Loading

0 comments on commit 49555c1

Please sign in to comment.