mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-04-05 08:28:14 -07:00
Merge branch 'main' into player-tracker
This commit is contained in:
@@ -493,7 +493,8 @@ async def server_loop(ctx: CommonContext, address=None):
|
||||
logger.info(f'Connecting to Archipelago server at {address}')
|
||||
try:
|
||||
socket = await websockets.connect(address, port=port, ping_timeout=None, ping_interval=None)
|
||||
ctx.ui.update_address_bar(server_url.netloc)
|
||||
if ctx.ui is not None:
|
||||
ctx.ui.update_address_bar(server_url.netloc)
|
||||
ctx.server = Endpoint(socket)
|
||||
logger.info('Connected')
|
||||
ctx.server_address = address
|
||||
|
||||
4
Utils.py
4
Utils.py
@@ -422,6 +422,10 @@ def get_text_between(text: str, start: str, end: str) -> str:
|
||||
return text[text.index(start) + len(start): text.rindex(end)]
|
||||
|
||||
|
||||
def get_text_after(text: str, start: str) -> str:
|
||||
return text[text.index(start) + len(start):]
|
||||
|
||||
|
||||
loglevel_mapping = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}
|
||||
|
||||
|
||||
|
||||
@@ -42,12 +42,11 @@ def get_app():
|
||||
def create_ordered_tutorials_file() -> typing.List[typing.Dict[str, typing.Any]]:
|
||||
import json
|
||||
import shutil
|
||||
import pathlib
|
||||
import zipfile
|
||||
|
||||
zfile: zipfile.ZipInfo
|
||||
|
||||
from worlds.AutoWorld import AutoWorldRegister, __file__
|
||||
from worlds.AutoWorld import AutoWorldRegister
|
||||
worlds = {}
|
||||
data = []
|
||||
for game, world in AutoWorldRegister.world_types.items():
|
||||
@@ -60,8 +59,8 @@ def create_ordered_tutorials_file() -> typing.List[typing.Dict[str, typing.Any]]
|
||||
target_path = os.path.join(base_target_path, game)
|
||||
os.makedirs(target_path, exist_ok=True)
|
||||
|
||||
if world.is_zip:
|
||||
zipfile_path = pathlib.Path(world.__file__).parents[1]
|
||||
if world.zip_path:
|
||||
zipfile_path = world.zip_path
|
||||
|
||||
assert os.path.isfile(zipfile_path), f"{zipfile_path} is not a valid file(path)."
|
||||
assert zipfile.is_zipfile(zipfile_path), f"{zipfile_path} is not a valid zipfile."
|
||||
|
||||
@@ -768,10 +768,10 @@ def getTracker(tracker: UUID):
|
||||
if game_state == 30:
|
||||
inventory[team][player][106] = 1 # Triforce
|
||||
|
||||
player_big_key_locations = {playernumber: set() for playernumber in range(1, len(names[0]) + 1) if playernumber not in groups}
|
||||
player_small_key_locations = {playernumber: set() for playernumber in range(1, len(names[0]) + 1) if playernumber not in groups}
|
||||
player_big_key_locations = {playernumber: set() for playernumber in range(1, len(names[0]) + 1)}
|
||||
player_small_key_locations = {playernumber: set() for playernumber in range(1, len(names[0]) + 1)}
|
||||
for loc_data in locations.values():
|
||||
for values in loc_data.values():
|
||||
for values in loc_data.values():
|
||||
item_id, item_player, flags = values
|
||||
|
||||
if item_id in ids_big_key:
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import pathlib
|
||||
from typing import Dict, FrozenSet, Set, Tuple, List, Optional, TextIO, Any, Callable, Union, TYPE_CHECKING
|
||||
|
||||
from Options import Option
|
||||
@@ -48,13 +49,14 @@ class AutoWorldRegister(type):
|
||||
raise RuntimeError(f"""Game {dct["game"]} already registered.""")
|
||||
AutoWorldRegister.world_types[dct["game"]] = new_class
|
||||
new_class.__file__ = sys.modules[new_class.__module__].__file__
|
||||
new_class.is_zip = ".apworld" in new_class.__file__
|
||||
if ".apworld" in new_class.__file__:
|
||||
new_class.zip_path = pathlib.Path(new_class.__file__).parents[1]
|
||||
return new_class
|
||||
|
||||
|
||||
class AutoLogicRegister(type):
|
||||
def __new__(cls, name: str, bases: Tuple[type, ...], dct: Dict[str, Any]) -> AutoLogicRegister:
|
||||
new_class = super().__new__(cls, name, bases, dct)
|
||||
def __new__(mcs, name: str, bases: Tuple[type, ...], dct: Dict[str, Any]) -> AutoLogicRegister:
|
||||
new_class = super().__new__(mcs, name, bases, dct)
|
||||
function: Callable[..., Any]
|
||||
for item_name, function in dct.items():
|
||||
if item_name == "copy_mixin":
|
||||
@@ -189,7 +191,7 @@ class World(metaclass=AutoWorldRegister):
|
||||
item_names: Set[str] # set of all potential item names
|
||||
location_names: Set[str] # set of all potential location names
|
||||
|
||||
is_zip: bool # was loaded from a .apworld ?
|
||||
zip_path: Optional[pathlib.Path] = None # If loaded from a .apworld, this is the Path to it.
|
||||
__file__: str # path it was loaded from
|
||||
|
||||
def __init__(self, world: "MultiWorld", player: int):
|
||||
|
||||
@@ -37,7 +37,6 @@ for file in os.scandir(folder):
|
||||
world_sources.sort()
|
||||
for world_source in world_sources:
|
||||
if world_source.is_zip:
|
||||
|
||||
importer = zipimport.zipimporter(os.path.join(folder, world_source.path))
|
||||
importer.load_module(world_source.path.split(".", 1)[0])
|
||||
else:
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
import random
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import threading
|
||||
import typing
|
||||
|
||||
from BaseClasses import Item, CollectionState, Tutorial
|
||||
from .SubClasses import ALttPItem
|
||||
from ..AutoWorld import World, WebWorld, LogicMixin
|
||||
from .Options import alttp_options, smallkey_shuffle
|
||||
from .Items import item_init_table, item_name_groups, item_table, GetBeemizerItem
|
||||
from .Regions import lookup_name_to_id, create_regions, mark_light_world_regions
|
||||
from .Rules import set_rules
|
||||
from .ItemPool import generate_itempool, difficulties
|
||||
from .Shops import create_shops, ShopSlotFill
|
||||
from .Dungeons import create_dungeons
|
||||
from .EntranceShuffle import link_entrances, link_inverted_entrances, plando_connect
|
||||
from .InvertedRegions import create_inverted_regions, mark_dark_world_regions
|
||||
from .ItemPool import generate_itempool, difficulties
|
||||
from .Items import item_init_table, item_name_groups, item_table, GetBeemizerItem
|
||||
from .Options import alttp_options, smallkey_shuffle
|
||||
from .Regions import lookup_name_to_id, create_regions, mark_light_world_regions
|
||||
from .Rom import LocalRom, patch_rom, patch_race_rom, check_enemizer, patch_enemizer, apply_rom_settings, \
|
||||
get_hash_string, get_base_rom_path, LttPDeltaPatch
|
||||
import Patch
|
||||
from itertools import chain
|
||||
|
||||
from .InvertedRegions import create_inverted_regions, mark_dark_world_regions
|
||||
from .EntranceShuffle import link_entrances, link_inverted_entrances, plando_connect
|
||||
from .Rules import set_rules
|
||||
from .Shops import create_shops, ShopSlotFill
|
||||
from .SubClasses import ALttPItem
|
||||
from ..AutoWorld import World, WebWorld, LogicMixin
|
||||
|
||||
lttp_logger = logging.getLogger("A Link to the Past")
|
||||
|
||||
|
||||
@@ -78,9 +78,14 @@ def generate_mod(world, output_directory: str):
|
||||
global data_final_template, locale_template, control_template, data_template, settings_template
|
||||
with template_load_lock:
|
||||
if not data_final_template:
|
||||
mod_template_folder = os.path.join(os.path.dirname(__file__), "data", "mod_template")
|
||||
def load_template(name: str):
|
||||
import pkgutil
|
||||
data = pkgutil.get_data(__name__, "data/mod_template/" + name).decode()
|
||||
return data, name, lambda: False
|
||||
|
||||
template_env: Optional[jinja2.Environment] = \
|
||||
jinja2.Environment(loader=jinja2.FileSystemLoader([mod_template_folder]))
|
||||
jinja2.Environment(loader=jinja2.FunctionLoader(load_template))
|
||||
|
||||
data_template = template_env.get_template("data.lua")
|
||||
data_final_template = template_env.get_template("data-final-fixes.lua")
|
||||
locale_template = template_env.get_template(r"locale/en/locale.cfg")
|
||||
@@ -158,7 +163,21 @@ def generate_mod(world, output_directory: str):
|
||||
mod_dir = os.path.join(output_directory, mod_name + "_" + Utils.__version__)
|
||||
en_locale_dir = os.path.join(mod_dir, "locale", "en")
|
||||
os.makedirs(en_locale_dir, exist_ok=True)
|
||||
shutil.copytree(os.path.join(os.path.dirname(__file__), "data", "mod"), mod_dir, dirs_exist_ok=True)
|
||||
|
||||
if world.zip_path:
|
||||
# Maybe investigate read from zip, write to zip, without temp file?
|
||||
with zipfile.ZipFile(world.zip_path) as zf:
|
||||
for file in zf.infolist():
|
||||
if not file.is_dir() and "/data/mod/" in file.filename:
|
||||
path_part = Utils.get_text_after(file.filename, "/data/mod/")
|
||||
target = os.path.join(mod_dir, path_part)
|
||||
os.makedirs(os.path.split(target)[0], exist_ok=True)
|
||||
|
||||
with open(target, "wb") as f:
|
||||
f.write(zf.read(file))
|
||||
else:
|
||||
shutil.copytree(os.path.join(os.path.dirname(__file__), "data", "mod"), mod_dir, dirs_exist_ok=True)
|
||||
|
||||
with open(os.path.join(mod_dir, "data.lua"), "wt") as f:
|
||||
f.write(data_template_code)
|
||||
with open(os.path.join(mod_dir, "data-final-fixes.lua"), "wt") as f:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from typing import Dict, List, Set
|
||||
from collections import deque
|
||||
|
||||
from worlds.factorio.Options import TechTreeLayout
|
||||
from .Options import TechTreeLayout
|
||||
|
||||
funnel_layers = {TechTreeLayout.option_small_funnels: 3,
|
||||
TechTreeLayout.option_medium_funnels: 4,
|
||||
|
||||
@@ -19,8 +19,8 @@ pool = ThreadPoolExecutor(1)
|
||||
|
||||
|
||||
def load_json_data(data_name: str) -> Union[List[str], Dict[str, Any]]:
|
||||
with open(os.path.join(source_folder, f"{data_name}.json")) as f:
|
||||
return json.load(f)
|
||||
import pkgutil
|
||||
return json.loads(pkgutil.get_data(__name__, "data/" + data_name + ".json").decode())
|
||||
|
||||
|
||||
techs_future = pool.submit(load_json_data, "techs")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import collections
|
||||
import typing
|
||||
|
||||
from ..AutoWorld import World, WebWorld
|
||||
from worlds.AutoWorld import World, WebWorld
|
||||
|
||||
from BaseClasses import Region, Entrance, Location, Item, RegionType, Tutorial, ItemClassification
|
||||
from .Technologies import base_tech_table, recipe_sources, base_technology_table, \
|
||||
|
||||
@@ -33,12 +33,12 @@ leave this window open as this is your server console.
|
||||
|
||||
### Connect to the MultiServer
|
||||
|
||||
Using Minecraft 1.18.2 connect to the server `localhost`.
|
||||
Open Minecraft, go to `Multiplayer > Direct Connection`, and join the `localhost` server address.
|
||||
|
||||
If you are using the website to host the game then it should auto-connect to the AP server without the need to `/connect`
|
||||
|
||||
otherwise once you are in game type `/connect <AP-Address> (Port) (Password)` where `<AP-Address>` is the address of the
|
||||
Archipelago server. `(Port)` is only required if the Archipelago server is not using the default port of 38281.
|
||||
Archipelago server. `(Port)` is only required if the Archipelago server is not using the default port of 38281. Note that there is no colon between `<AP-Address>` and `(Port)`.
|
||||
`(Password)` is only required if the Archipelago server you are using has a password set.
|
||||
|
||||
### Play the game
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import random
|
||||
|
||||
from BaseClasses import LocationProgressType
|
||||
from .Items import OOTItem
|
||||
|
||||
# Abbreviations
|
||||
# DMC Death Mountain Crater
|
||||
@@ -1260,7 +1261,7 @@ def hintExclusions(world, clear_cache=False):
|
||||
world.hint_exclusions = []
|
||||
|
||||
for location in world.get_locations():
|
||||
if (location.locked and (location.item.type != 'Song' or world.shuffle_song_items != 'song')) or location.progress_type == LocationProgressType.EXCLUDED:
|
||||
if (location.locked and ((isinstance(location.item, OOTItem) and location.item.type != 'Song') or world.shuffle_song_items != 'song')) or location.progress_type == LocationProgressType.EXCLUDED:
|
||||
world.hint_exclusions.append(location.name)
|
||||
|
||||
world_location_names = [
|
||||
|
||||
@@ -2104,7 +2104,7 @@ def place_shop_items(rom, world, shop_items, messages, locations, init_shop_id=F
|
||||
|
||||
shop_objs = { 0x0148 } # "Sold Out" object
|
||||
for location in locations:
|
||||
if location.item.type == 'Shop':
|
||||
if isinstance(location.item, OOTItem) and location.item.type == 'Shop':
|
||||
shop_objs.add(location.item.special['object'])
|
||||
rom.write_int16(location.address1, location.item.index)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user