mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-07 15:13:52 -08:00
LADX: Give better feedback during patching (#5401)
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
import binascii
|
||||
import importlib.util
|
||||
import importlib.machinery
|
||||
import os
|
||||
import random
|
||||
import pickle
|
||||
import Utils
|
||||
import settings
|
||||
from collections import defaultdict
|
||||
from typing import Dict
|
||||
|
||||
@@ -65,8 +63,27 @@ from .patches.aesthetics import rgb_to_bin, bin_to_rgb
|
||||
|
||||
from .. import Options
|
||||
|
||||
class VersionError(Exception):
|
||||
pass
|
||||
|
||||
# Function to generate a final rom, this patches the rom with all required patches
|
||||
def generateRom(base_rom: bytes, args, patch_data: Dict):
|
||||
from .. import LinksAwakeningWorld
|
||||
patcher_version = LinksAwakeningWorld.world_version
|
||||
generated_version = Utils.tuplize_version(patch_data.get("generated_world_version", "2.0.0"))
|
||||
if generated_version.major != patcher_version.major or generated_version.minor != patcher_version.minor:
|
||||
Utils.messagebox(
|
||||
"Error",
|
||||
"The apworld version that this patch was generated on is incompatible with your installed world.\n\n"
|
||||
f"Generated on {generated_version.as_simple_string()}\n"
|
||||
f"Installed version {patcher_version.as_simple_string()}",
|
||||
True
|
||||
)
|
||||
raise VersionError(
|
||||
f"The installed world ({patcher_version.as_simple_string()}) is incompatible with the world this patch "
|
||||
f"was generated on ({generated_version.as_simple_string()})"
|
||||
)
|
||||
|
||||
random.seed(patch_data["seed"] + patch_data["player"])
|
||||
multi_key = binascii.unhexlify(patch_data["multi_key"].encode())
|
||||
item_list = pickle.loads(binascii.unhexlify(patch_data["item_list"].encode()))
|
||||
@@ -85,9 +102,8 @@ def generateRom(base_rom: bytes, args, patch_data: Dict):
|
||||
pymod.prePatch(rom)
|
||||
|
||||
if options["gfxmod"]:
|
||||
user_settings = settings.get_settings()
|
||||
try:
|
||||
gfx_mod_file = user_settings["ladx_options"]["gfx_mod_file"]
|
||||
gfx_mod_file = LinksAwakeningWorld.settings.gfx_mod_file
|
||||
patches.aesthetics.gfxMod(rom, gfx_mod_file)
|
||||
except FileNotFoundError:
|
||||
pass # if user just doesnt provide gfxmod file, let patching continue
|
||||
|
||||
@@ -47,6 +47,10 @@ class BadRetroArchResponse(GameboyException):
|
||||
|
||||
class BadRetroArchResponse(GameboyException):
|
||||
pass
|
||||
|
||||
|
||||
class VersionError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LAClientConstants:
|
||||
@@ -518,7 +522,7 @@ class LinksAwakeningContext(CommonContext):
|
||||
class LADXManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago"),
|
||||
("Tracker", "Tracker"),
|
||||
("Tracker", "Tracker"),
|
||||
]
|
||||
base_title = f"Links Awakening DX Client {LinksAwakeningWorld.world_version.as_simple_string()} | Archipelago"
|
||||
|
||||
@@ -614,11 +618,20 @@ class LinksAwakeningContext(CommonContext):
|
||||
|
||||
def on_package(self, cmd: str, args: dict):
|
||||
if cmd == "Connected":
|
||||
self.game = self.slot_info[self.slot].game
|
||||
self.slot_data = args.get("slot_data", {})
|
||||
generated_version = Utils.tuplize_version(self.slot_data.get("world_version", "2.0.0"))
|
||||
client_version = LinksAwakeningWorld.world_version
|
||||
if generated_version.major != client_version.major:
|
||||
self.disconnected_intentionally = True
|
||||
raise VersionError(
|
||||
f"The installed world ({client_version.as_simple_string()}) is incompatible with "
|
||||
f"the world this game was generated on ({generated_version.as_simple_string()})"
|
||||
)
|
||||
# This is sent to magpie over local websocket to make its own connection
|
||||
self.slot_data.update({
|
||||
"server_address": self.server_address,
|
||||
"slot_name": self.player_names[self.slot],
|
||||
"password": self.password,
|
||||
"client_version": client_version.as_simple_string(),
|
||||
})
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import settings
|
||||
import worlds.Files
|
||||
import hashlib
|
||||
import Utils
|
||||
@@ -59,6 +58,7 @@ class LADXProcedurePatch(worlds.Files.APProcedurePatch):
|
||||
def write_patch_data(world: "LinksAwakeningWorld", patch: LADXProcedurePatch):
|
||||
item_list = pickle.dumps([item for item in world.ladxr_logic.iteminfo_list if not isinstance(item, KeyLocation)])
|
||||
data_dict = {
|
||||
"generated_world_version": world.world_version.as_simple_string(),
|
||||
"out_base": world.multiworld.get_out_file_name_base(patch.player),
|
||||
"is_race": world.multiworld.is_race,
|
||||
"seed": world.multiworld.seed,
|
||||
@@ -125,9 +125,9 @@ def get_base_rom_bytes(file_name: str = "") -> bytes:
|
||||
|
||||
|
||||
def get_base_rom_path(file_name: str = "") -> str:
|
||||
options = settings.get_settings()
|
||||
from . import LinksAwakeningWorld
|
||||
if not file_name:
|
||||
file_name = options["ladx_options"]["rom_file"]
|
||||
file_name = LinksAwakeningWorld.settings.rom_file
|
||||
if not os.path.exists(file_name):
|
||||
file_name = Utils.user_path(file_name)
|
||||
return file_name
|
||||
|
||||
@@ -4,8 +4,10 @@ import os
|
||||
import typing
|
||||
import logging
|
||||
import re
|
||||
import struct
|
||||
|
||||
import settings
|
||||
import Utils
|
||||
from BaseClasses import CollectionState, Entrance, Item, ItemClassification, Location, Tutorial
|
||||
from Fill import fill_restrictive
|
||||
from worlds.AutoWorld import WebWorld, World
|
||||
@@ -50,6 +52,17 @@ class LinksAwakeningSettings(settings.Group):
|
||||
description = "LADX ROM File"
|
||||
md5s = [LADXProcedurePatch.hash]
|
||||
|
||||
@classmethod
|
||||
def validate(cls, path: str) -> None:
|
||||
try:
|
||||
super().validate(path)
|
||||
except ValueError:
|
||||
Utils.messagebox(
|
||||
"Error",
|
||||
"Provided rom does not match hash for English 1.0/revision-0 of Link's Awakening DX",
|
||||
True)
|
||||
raise
|
||||
|
||||
class RomStart(str):
|
||||
"""
|
||||
Set this to false to never autostart a rom (such as after patching)
|
||||
@@ -71,6 +84,24 @@ class LinksAwakeningSettings(settings.Group):
|
||||
Only .bin or .bdiff files
|
||||
The same directory will be checked for a matching text modification file
|
||||
"""
|
||||
def browse(self, filetypes=None, **kwargs):
|
||||
filetypes = [("Binary / Patch files", [".bin", ".bdiff"])]
|
||||
return super().browse(filetypes=filetypes, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def validate(cls, path: str) -> None:
|
||||
with open(path, "rb", buffering=0) as f:
|
||||
header, size = struct.unpack("<II", f.read()[:8])
|
||||
if path.endswith('.bin') and header == 0xDEADBEEF and size < 1024:
|
||||
# detect extended spritesheets from upstream ladxr
|
||||
Utils.messagebox(
|
||||
"Error",
|
||||
"Extended sprite sheets are not supported. Try again with a different gfxmod file, "
|
||||
"or provide no file to continue without modifying graphics.",
|
||||
True)
|
||||
raise ValueError("Provided gfxmod file is an extended sheet, which is not supported")
|
||||
|
||||
|
||||
|
||||
rom_file: RomFile = RomFile(RomFile.copy_to)
|
||||
rom_start: typing.Union[RomStart, bool] = True
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"game": "Links Awakening DX",
|
||||
"authors": [ "zig", "threeandthree" ],
|
||||
"minimum_ap_version": "0.6.4",
|
||||
"world_version": "2.0.0"
|
||||
"world_version": "2.0.1"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user