Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 11 additions & 1 deletion src/ManualClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -889,8 +889,18 @@ async def game_watcher_manual(ctx: ManualContext):
await asyncio.sleep(0.1)


def read_apmanual_file(apmanual_file):
def read_apmanual_file(apmanual_file) -> dict[str, Any]:
import zipfile
from base64 import b64decode
from .container import APManualFile

if zipfile.is_zipfile(apmanual_file):
try:
container = APManualFile(apmanual_file)
container.read()
return container.as_dict()
except Exception as e:
print("Error reading APManual file:", e)

with open(apmanual_file, 'r') as f:
return json.loads(b64decode(f.read()))
Expand Down
25 changes: 7 additions & 18 deletions src/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
from base64 import b64encode
import logging
import os
import json
from typing import Callable, Optional
import webbrowser

import Utils
from worlds.generic.Rules import forbid_items_for_player
from worlds.LauncherComponents import Component, SuffixIdentifier, components, Type, launch_subprocess, icon_paths

from .Data import item_table, location_table, region_table, category_table
from .Data import item_table, location_table, category_table
from .Game import game_name, filler_item_name, starting_items
from .Meta import world_description, world_webworld, enable_region_diagram
from .Locations import location_id_to_name, location_name_to_id, location_name_to_location, location_name_groups, victory_names
Expand All @@ -21,6 +19,7 @@
from .Rules import set_rules
from .Options import manual_options_data
from .Helpers import is_item_enabled, get_option_value, get_items_for_player, resolve_yaml_option, format_state_prog_items_key, ProgItemsCat
from .container import APManualFile

from BaseClasses import CollectionState, ItemClassification, Item
from Options import PerGameCommonOptions
Expand Down Expand Up @@ -386,10 +385,12 @@ def fill_slot_data(self):
return slot_data

def generate_output(self, output_directory: str):
data = self.client_data()
filename = f"{self.multiworld.get_out_file_name_base(self.player)}.apmanual"
with open(os.path.join(output_directory, filename), 'wb') as f:
f.write(b64encode(bytes(json.dumps(data), 'utf-8')))
zf_path = os.path.join(output_directory, filename)

apmanual = APManualFile(zf_path, player=self.player, player_name=self.player_name)
apmanual.write()


def write_spoiler(self, spoiler_handle):
before_write_spoiler(self, self.multiworld, spoiler_handle)
Expand Down Expand Up @@ -482,18 +483,6 @@ def get_item_counts(self, player: Optional[int] = None, reset: bool = False) ->
self.item_counts[player] = {i.name: real_pool.count(i) for i in real_pool}
return self.item_counts.get(player)

def client_data(self):
return {
"game": self.game,
'player_name': self.multiworld.get_player_name(self.player),
'player_id': self.player,
'items': self.item_name_to_item,
'locations': self.location_name_to_location,
# todo: extract connections out of multiworld.get_regions() instead, in case hooks have modified the regions.
'regions': region_table,
'categories': category_table
}

###
# Non-world client methods
###
Expand Down
44 changes: 44 additions & 0 deletions src/container.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import json
import zipfile
from typing import Any

from worlds import Files

from .Data import region_table
from .Game import game_name
from .Locations import location_name_to_location
from .Items import item_name_to_item

if hasattr(Files, 'APPlayerContainer'):
APPlayerContainer = Files.APPlayerContainer
else:
# Prior to 0.6.2, all containers were player containers.
APPlayerContainer = Files.APContainer

class APManualFile(APPlayerContainer):
game = game_name
patch_file_ending = ".apmanual"

def __init__(self, *args: Any, **kwargs: Any):
super().__init__(*args, **kwargs)


def write_contents(self, opened_zipfile: zipfile.ZipFile):
super().write_contents(opened_zipfile)
opened_zipfile.writestr("items.json", json.dumps(item_name_to_item, indent=2))
opened_zipfile.writestr("locations.json", json.dumps(location_name_to_location, indent=2))
opened_zipfile.writestr("regions.json", json.dumps(region_table, indent=2))

def read_contents(self, opened_zipfile: zipfile.ZipFile) -> dict[str, Any]:
manifest = super().read_contents(opened_zipfile)
self.items = json.loads(opened_zipfile.read("items.json"))
self.locations = json.loads(opened_zipfile.read("locations.json"))
self.regions = json.loads(opened_zipfile.read("regions.json"))
return manifest

def as_dict(self) -> dict[str, Any]:
data = {}
data["items"] = self.items
data["locations"] = self.locations
data["regions"] = self.regions
return data