unify clients and setup
This commit is contained in:
		
							parent
							
								
									096e682b18
								
							
						
					
					
						commit
						66514ec607
					
				| 
						 | 
				
			
			@ -16,7 +16,6 @@
 | 
			
		|||
*.apsave
 | 
			
		||||
 | 
			
		||||
build
 | 
			
		||||
/build_factorio/
 | 
			
		||||
bundle/components.wxs
 | 
			
		||||
dist
 | 
			
		||||
README.html
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,9 +25,9 @@ os.makedirs("logs", exist_ok=True)
 | 
			
		|||
# Log to file in gui case
 | 
			
		||||
if getattr(sys, "frozen", False) and not "--nogui" in sys.argv:
 | 
			
		||||
    logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO,
 | 
			
		||||
                        filename=os.path.join("logs", "FactorioClient.txt"), filemode="w")
 | 
			
		||||
                        filename=os.path.join("logs", "FactorioClient.txt"), filemode="w", force=True)
 | 
			
		||||
else:
 | 
			
		||||
    logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO)
 | 
			
		||||
    logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO, force=True)
 | 
			
		||||
    logging.getLogger().addHandler(logging.FileHandler(os.path.join("logs", "FactorioClient.txt"), "w"))
 | 
			
		||||
 | 
			
		||||
gui_enabled = Utils.is_frozen() or "--nogui" not in sys.argv
 | 
			
		||||
| 
						 | 
				
			
			@ -299,7 +299,7 @@ async def main(args):
 | 
			
		|||
 | 
			
		||||
    if ctx.server and not ctx.server.socket.closed:
 | 
			
		||||
        await ctx.server.socket.close()
 | 
			
		||||
    if ctx.server_task is not None:
 | 
			
		||||
    if ctx.server_task:
 | 
			
		||||
        await ctx.server_task
 | 
			
		||||
 | 
			
		||||
    while ctx.input_requests > 0:
 | 
			
		||||
| 
						 | 
				
			
			@ -352,7 +352,7 @@ if __name__ == '__main__':
 | 
			
		|||
    if not os.path.exists(bin_dir):
 | 
			
		||||
        raise FileNotFoundError(f"Path {bin_dir} does not exist or could not be accessed.")
 | 
			
		||||
    if not os.path.isdir(bin_dir):
 | 
			
		||||
        raise FileNotFoundError(f"Path {bin_dir} is not a directory.")
 | 
			
		||||
        raise NotADirectoryError(f"Path {bin_dir} is not a directory.")
 | 
			
		||||
    if not os.path.exists(executable):
 | 
			
		||||
        if os.path.exists(executable + ".exe"):
 | 
			
		||||
            executable = executable + ".exe"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
import argparse
 | 
			
		||||
import atexit
 | 
			
		||||
import threading
 | 
			
		||||
import time
 | 
			
		||||
import sys
 | 
			
		||||
import multiprocessing
 | 
			
		||||
import os
 | 
			
		||||
import subprocess
 | 
			
		||||
| 
						 | 
				
			
			@ -23,11 +25,22 @@ from NetUtils import *
 | 
			
		|||
from worlds.alttp import Regions, Shops
 | 
			
		||||
from worlds.alttp import Items
 | 
			
		||||
import Utils
 | 
			
		||||
from CommonClient import CommonContext, server_loop, logger, console_loop, ClientCommandProcessor
 | 
			
		||||
from CommonClient import CommonContext, server_loop, console_loop, ClientCommandProcessor
 | 
			
		||||
 | 
			
		||||
snes_logger = logging.getLogger("SNES")
 | 
			
		||||
 | 
			
		||||
from MultiServer import mark_raw
 | 
			
		||||
 | 
			
		||||
os.makedirs("logs", exist_ok=True)
 | 
			
		||||
 | 
			
		||||
# Log to file in gui case
 | 
			
		||||
if getattr(sys, "frozen", False) and not "--nogui" in sys.argv:
 | 
			
		||||
    logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO,
 | 
			
		||||
                        filename=os.path.join("logs", "LttPClient.txt"), filemode="w", force=True)
 | 
			
		||||
else:
 | 
			
		||||
    logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO, force=True)
 | 
			
		||||
    logging.getLogger().addHandler(logging.FileHandler(os.path.join("logs", "LttPClient.txt"), "w"))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LttPCommandProcessor(ClientCommandProcessor):
 | 
			
		||||
    def _cmd_slow_mode(self, toggle: str = ""):
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +84,7 @@ class Context(CommonContext):
 | 
			
		|||
        self.snes_recv_queue = asyncio.Queue()
 | 
			
		||||
        self.snes_request_lock = asyncio.Lock()
 | 
			
		||||
        self.snes_write_buffer = []
 | 
			
		||||
        self.snes_connector_lock = threading.Lock()
 | 
			
		||||
 | 
			
		||||
        self.awaiting_rom = False
 | 
			
		||||
        self.rom = None
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +105,7 @@ class Context(CommonContext):
 | 
			
		|||
            await super(Context, self).server_auth(password_requested)
 | 
			
		||||
        if self.rom is None:
 | 
			
		||||
            self.awaiting_rom = True
 | 
			
		||||
            logger.info(
 | 
			
		||||
            snes_logger.info(
 | 
			
		||||
                'No ROM detected, awaiting snes connection to authenticate to the multiworld server (/snes)')
 | 
			
		||||
            return
 | 
			
		||||
        self.awaiting_rom = False
 | 
			
		||||
| 
						 | 
				
			
			@ -420,19 +434,18 @@ def launch_sni(ctx: Context):
 | 
			
		|||
                sni_path = os.path.join(sni_path, file)
 | 
			
		||||
 | 
			
		||||
    if os.path.isfile(sni_path):
 | 
			
		||||
        logger.info(f"Attempting to start {sni_path}")
 | 
			
		||||
        snes_logger.info(f"Attempting to start {sni_path}")
 | 
			
		||||
        import subprocess
 | 
			
		||||
        subprocess.Popen(sni_path, cwd=os.path.dirname(sni_path), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 | 
			
		||||
    else:
 | 
			
		||||
        logger.info(
 | 
			
		||||
        snes_logger.info(
 | 
			
		||||
            f"Attempt to start SNI was aborted as path {sni_path} was not found, "
 | 
			
		||||
            f"please start it yourself if it is not running")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def _snes_connect(ctx: Context, address: str):
 | 
			
		||||
    address = f"ws://{address}" if "://" not in address else address
 | 
			
		||||
 | 
			
		||||
    logger.info("Connecting to SNI at %s ..." % address)
 | 
			
		||||
    snes_logger.info("Connecting to SNI at %s ..." % address)
 | 
			
		||||
    seen_problems = set()
 | 
			
		||||
    succesful = False
 | 
			
		||||
    while not succesful:
 | 
			
		||||
| 
						 | 
				
			
			@ -444,7 +457,7 @@ async def _snes_connect(ctx: Context, address: str):
 | 
			
		|||
            # only tell the user about new problems, otherwise silently lay in wait for a working connection
 | 
			
		||||
            if problem not in seen_problems:
 | 
			
		||||
                seen_problems.add(problem)
 | 
			
		||||
                logger.error(f"Error connecting to SNI ({problem})")
 | 
			
		||||
                snes_logger.error(f"Error connecting to SNI ({problem})")
 | 
			
		||||
 | 
			
		||||
                if len(seen_problems) == 1:
 | 
			
		||||
                    # this is the first problem. Let's try launching SNI if it isn't already running
 | 
			
		||||
| 
						 | 
				
			
			@ -467,7 +480,7 @@ async def get_snes_devices(ctx: Context):
 | 
			
		|||
    devices = reply['Results'] if 'Results' in reply and len(reply['Results']) > 0 else None
 | 
			
		||||
 | 
			
		||||
    if not devices:
 | 
			
		||||
        logger.info('No SNES device found. Please connect a SNES device to SNI.')
 | 
			
		||||
        snes_logger.info('No SNES device found. Please connect a SNES device to SNI.')
 | 
			
		||||
        while not devices:
 | 
			
		||||
            await asyncio.sleep(1)
 | 
			
		||||
            await socket.send(dumps(DeviceList_Request))
 | 
			
		||||
| 
						 | 
				
			
			@ -482,7 +495,7 @@ async def get_snes_devices(ctx: Context):
 | 
			
		|||
async def snes_connect(ctx: Context, address):
 | 
			
		||||
    global SNES_RECONNECT_DELAY
 | 
			
		||||
    if ctx.snes_socket is not None and ctx.snes_state == SNESState.SNES_CONNECTED:
 | 
			
		||||
        logger.error('Already connected to snes')
 | 
			
		||||
        snes_logger.error('Already connected to snes')
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    recv_task = None
 | 
			
		||||
| 
						 | 
				
			
			@ -505,7 +518,7 @@ async def snes_connect(ctx: Context, address):
 | 
			
		|||
            await snes_disconnect(ctx)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        logger.info("Attaching to " + device)
 | 
			
		||||
        snes_logger.info("Attaching to " + device)
 | 
			
		||||
 | 
			
		||||
        Attach_Request = {
 | 
			
		||||
            "Opcode": "Attach",
 | 
			
		||||
| 
						 | 
				
			
			@ -530,9 +543,9 @@ async def snes_connect(ctx: Context, address):
 | 
			
		|||
                ctx.snes_socket = None
 | 
			
		||||
            ctx.snes_state = SNESState.SNES_DISCONNECTED
 | 
			
		||||
        if not ctx.snes_reconnect_address:
 | 
			
		||||
            logger.error("Error connecting to snes (%s)" % e)
 | 
			
		||||
            snes_logger.error("Error connecting to snes (%s)" % e)
 | 
			
		||||
        else:
 | 
			
		||||
            logger.error(f"Error connecting to snes, attempt again in {SNES_RECONNECT_DELAY}s")
 | 
			
		||||
            snes_logger.error(f"Error connecting to snes, attempt again in {SNES_RECONNECT_DELAY}s")
 | 
			
		||||
            asyncio.create_task(snes_autoreconnect(ctx))
 | 
			
		||||
        SNES_RECONNECT_DELAY *= 2
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -559,11 +572,11 @@ async def snes_recv_loop(ctx: Context):
 | 
			
		|||
    try:
 | 
			
		||||
        async for msg in ctx.snes_socket:
 | 
			
		||||
            ctx.snes_recv_queue.put_nowait(msg)
 | 
			
		||||
        logger.warning("Snes disconnected")
 | 
			
		||||
        snes_logger.warning("Snes disconnected")
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        if not isinstance(e, websockets.WebSocketException):
 | 
			
		||||
            logger.exception(e)
 | 
			
		||||
        logger.error("Lost connection to the snes, type /snes to reconnect")
 | 
			
		||||
            snes_logger.exception(e)
 | 
			
		||||
        snes_logger.error("Lost connection to the snes, type /snes to reconnect")
 | 
			
		||||
    finally:
 | 
			
		||||
        socket, ctx.snes_socket = ctx.snes_socket, None
 | 
			
		||||
        if socket is not None and not socket.closed:
 | 
			
		||||
| 
						 | 
				
			
			@ -576,7 +589,7 @@ async def snes_recv_loop(ctx: Context):
 | 
			
		|||
        ctx.rom = None
 | 
			
		||||
 | 
			
		||||
        if ctx.snes_reconnect_address:
 | 
			
		||||
            logger.info(f"...reconnecting in {SNES_RECONNECT_DELAY}s")
 | 
			
		||||
            snes_logger.info(f"...reconnecting in {SNES_RECONNECT_DELAY}s")
 | 
			
		||||
            asyncio.create_task(snes_autoreconnect(ctx))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -605,10 +618,10 @@ async def snes_read(ctx: Context, address, size):
 | 
			
		|||
                break
 | 
			
		||||
 | 
			
		||||
        if len(data) != size:
 | 
			
		||||
            logger.error('Error reading %s, requested %d bytes, received %d' % (hex(address), size, len(data)))
 | 
			
		||||
            snes_logger.error('Error reading %s, requested %d bytes, received %d' % (hex(address), size, len(data)))
 | 
			
		||||
            if len(data):
 | 
			
		||||
                logger.error(str(data))
 | 
			
		||||
                logger.warning('Communication Failure with SNI')
 | 
			
		||||
                snes_logger.error(str(data))
 | 
			
		||||
                snes_logger.warning('Communication Failure with SNI')
 | 
			
		||||
            if ctx.snes_socket is not None and not ctx.snes_socket.closed:
 | 
			
		||||
                await ctx.snes_socket.close()
 | 
			
		||||
            return None
 | 
			
		||||
| 
						 | 
				
			
			@ -634,7 +647,7 @@ async def snes_write(ctx: Context, write_list):
 | 
			
		|||
                    await ctx.snes_socket.send(dumps(PutAddress_Request))
 | 
			
		||||
                    await ctx.snes_socket.send(data)
 | 
			
		||||
                else:
 | 
			
		||||
                    logger.warning(f"Could not send data to SNES: {data}")
 | 
			
		||||
                    snes_logger.warning(f"Could not send data to SNES: {data}")
 | 
			
		||||
        except websockets.ConnectionClosed:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -673,7 +686,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
 | 
			
		|||
        new_locations.append(location_id)
 | 
			
		||||
        ctx.locations_checked.add(location_id)
 | 
			
		||||
        location = ctx.location_name_getter(location_id)
 | 
			
		||||
        logger.info(f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})')
 | 
			
		||||
        snes_logger.info(f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})')
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        if roomid in location_shop_ids:
 | 
			
		||||
| 
						 | 
				
			
			@ -682,7 +695,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
 | 
			
		|||
                if int(b) and (Shops.SHOP_ID_START + cnt) not in ctx.locations_checked:
 | 
			
		||||
                    new_check(Shops.SHOP_ID_START + cnt)
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        logger.info(f"Exception: {e}")
 | 
			
		||||
        snes_logger.info(f"Exception: {e}")
 | 
			
		||||
 | 
			
		||||
    for location_id, (loc_roomid, loc_mask) in location_table_uw_id.items():
 | 
			
		||||
        try:
 | 
			
		||||
| 
						 | 
				
			
			@ -691,7 +704,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
 | 
			
		|||
                    roomdata << 4) & loc_mask != 0:
 | 
			
		||||
                new_check(location_id)
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            logger.exception(f"Exception: {e}")
 | 
			
		||||
            snes_logger.exception(f"Exception: {e}")
 | 
			
		||||
 | 
			
		||||
    uw_begin = 0x129
 | 
			
		||||
    ow_end = uw_end = 0
 | 
			
		||||
| 
						 | 
				
			
			@ -774,7 +787,7 @@ async def game_watcher(ctx: Context):
 | 
			
		|||
                await ctx.server_auth(False)
 | 
			
		||||
 | 
			
		||||
        if ctx.auth and ctx.auth != ctx.rom:
 | 
			
		||||
            logger.warning("ROM change detected, please reconnect to the multiworld server")
 | 
			
		||||
            snes_logger.warning("ROM change detected, please reconnect to the multiworld server")
 | 
			
		||||
            await ctx.disconnect()
 | 
			
		||||
 | 
			
		||||
        gamemode = await snes_read(ctx, WRAM_START + 0x10, 1)
 | 
			
		||||
| 
						 | 
				
			
			@ -857,6 +870,8 @@ async def main():
 | 
			
		|||
    parser.add_argument('--loglevel', default='info', choices=['debug', 'info', 'warning', 'error', 'critical'])
 | 
			
		||||
    parser.add_argument('--founditems', default=False, action='store_true',
 | 
			
		||||
                        help='Show items found by other players for themselves.')
 | 
			
		||||
    if not Utils.is_frozen():  # Frozen state has no cmd window in the first place
 | 
			
		||||
        parser.add_argument('--nogui', default=False, action='store_true', help="Turns off Client GUI.")
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    logging.basicConfig(format='%(message)s', level=getattr(logging, args.loglevel.upper(), logging.INFO))
 | 
			
		||||
    if args.diff_file:
 | 
			
		||||
| 
						 | 
				
			
			@ -875,22 +890,33 @@ async def main():
 | 
			
		|||
        asyncio.create_task(run_game(adjustedromfile if adjusted else romfile))
 | 
			
		||||
 | 
			
		||||
    ctx = Context(args.snes, args.connect, args.password)
 | 
			
		||||
    input_task = asyncio.create_task(console_loop(ctx), name="Input")
 | 
			
		||||
 | 
			
		||||
    if ctx.server_task is None:
 | 
			
		||||
        ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
 | 
			
		||||
    asyncio.create_task(snes_connect(ctx, ctx.snes_address))
 | 
			
		||||
 | 
			
		||||
    if Utils.is_frozen() or "--nogui" not in sys.argv:
 | 
			
		||||
        input_task = None
 | 
			
		||||
        from kvui import LttPManager
 | 
			
		||||
        ui_app = LttPManager(ctx)
 | 
			
		||||
        ctx.ui = ui_app
 | 
			
		||||
        ui_task = asyncio.create_task(ui_app.async_run(), name="UI")
 | 
			
		||||
    else:
 | 
			
		||||
        input_task = asyncio.create_task(console_loop(ctx), name="Input")
 | 
			
		||||
        ui_task = None
 | 
			
		||||
 | 
			
		||||
    snes_connect_task = asyncio.create_task(snes_connect(ctx, ctx.snes_address))
 | 
			
		||||
    watcher_task = asyncio.create_task(game_watcher(ctx), name="GameWatcher")
 | 
			
		||||
 | 
			
		||||
    await ctx.exit_event.wait()
 | 
			
		||||
    if snes_connect_task:
 | 
			
		||||
        snes_connect_task.cancel()
 | 
			
		||||
    ctx.server_address = None
 | 
			
		||||
    ctx.snes_reconnect_address = None
 | 
			
		||||
 | 
			
		||||
    await watcher_task
 | 
			
		||||
 | 
			
		||||
    if ctx.server is not None and not ctx.server.socket.closed:
 | 
			
		||||
    if ctx.server and not ctx.server.socket.closed:
 | 
			
		||||
        await ctx.server.socket.close()
 | 
			
		||||
    if ctx.server_task is not None:
 | 
			
		||||
    if ctx.server_task:
 | 
			
		||||
        await ctx.server_task
 | 
			
		||||
 | 
			
		||||
    if ctx.snes_socket is not None and not ctx.snes_socket.closed:
 | 
			
		||||
| 
						 | 
				
			
			@ -900,7 +926,11 @@ async def main():
 | 
			
		|||
        ctx.input_queue.put_nowait(None)
 | 
			
		||||
        ctx.input_requests -= 1
 | 
			
		||||
 | 
			
		||||
    await input_task
 | 
			
		||||
    if ui_task:
 | 
			
		||||
        await ui_task
 | 
			
		||||
 | 
			
		||||
    if input_task:
 | 
			
		||||
        input_task.cancel()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,80 +0,0 @@
 | 
			
		|||
#define sourcepath "build_factorio\exe.win-amd64-3.8\"
 | 
			
		||||
#define MyAppName "Archipelago Factorio Client"
 | 
			
		||||
#define MyAppExeName "ArchipelagoGraphicalFactorioClient.exe"
 | 
			
		||||
#define MyAppIcon "data/icon.ico"
 | 
			
		||||
 | 
			
		||||
[Setup]
 | 
			
		||||
; NOTE: The value of AppId uniquely identifies this application.
 | 
			
		||||
; Do not use the same AppId value in installers for other applications.
 | 
			
		||||
AppId={{D13CEBD0-F1D5-4435-A4A6-5243F934613F}}
 | 
			
		||||
AppName={#MyAppName}
 | 
			
		||||
AppVerName={#MyAppName}
 | 
			
		||||
DefaultDirName={commonappdata}\{#MyAppName}
 | 
			
		||||
DisableProgramGroupPage=yes
 | 
			
		||||
DefaultGroupName=Archipelago
 | 
			
		||||
OutputDir=setups
 | 
			
		||||
OutputBaseFilename=Setup {#MyAppName}
 | 
			
		||||
Compression=lzma2
 | 
			
		||||
SolidCompression=yes
 | 
			
		||||
LZMANumBlockThreads=8
 | 
			
		||||
ArchitecturesInstallIn64BitMode=x64
 | 
			
		||||
ChangesAssociations=yes
 | 
			
		||||
ArchitecturesAllowed=x64
 | 
			
		||||
AllowNoIcons=yes
 | 
			
		||||
SetupIconFile={#MyAppIcon}
 | 
			
		||||
UninstallDisplayIcon={app}\{#MyAppExeName}
 | 
			
		||||
SignTool= signtool
 | 
			
		||||
LicenseFile= LICENSE
 | 
			
		||||
WizardStyle= modern
 | 
			
		||||
SetupLogging=yes
 | 
			
		||||
 | 
			
		||||
[Languages]
 | 
			
		||||
Name: "english"; MessagesFile: "compiler:Default.isl"
 | 
			
		||||
 | 
			
		||||
[Tasks]
 | 
			
		||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[Dirs]
 | 
			
		||||
NAME: "{app}"; Flags: setntfscompression; Permissions: everyone-modify users-modify authusers-modify;
 | 
			
		||||
 | 
			
		||||
[Files]
 | 
			
		||||
Source: "vc_redist.x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall
 | 
			
		||||
Source: "{#sourcepath}*"; Excludes: "*.sfc, *.log, data\sprites\alttpr"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
 | 
			
		||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
 | 
			
		||||
 | 
			
		||||
[Icons]
 | 
			
		||||
Name: "{group}\{#MyAppName} Folder"; Filename: "{app}";
 | 
			
		||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}";
 | 
			
		||||
Name: "{commondesktop}\{#MyAppName} Folder"; Filename: "{app}"; Tasks: desktopicon
 | 
			
		||||
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
 | 
			
		||||
 | 
			
		||||
[Run]
 | 
			
		||||
Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/passive /norestart"; Check: IsVCRedist64BitNeeded; StatusMsg: "Installing VC++ redistributable..."
 | 
			
		||||
 | 
			
		||||
[UninstallDelete]
 | 
			
		||||
Type: dirifempty; Name: "{app}"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[Code]
 | 
			
		||||
// See: https://stackoverflow.com/a/51614652/2287576
 | 
			
		||||
function IsVCRedist64BitNeeded(): boolean;
 | 
			
		||||
var
 | 
			
		||||
  strVersion: string;
 | 
			
		||||
begin
 | 
			
		||||
  if (RegQueryStringValue(HKEY_LOCAL_MACHINE,
 | 
			
		||||
    'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Version', strVersion)) then
 | 
			
		||||
  begin
 | 
			
		||||
    // Is the installed version at least the packaged one ?
 | 
			
		||||
    Log('VC Redist x64 Version : found ' + strVersion);
 | 
			
		||||
    Result := (CompareStr(strVersion, 'v14.29.30037') < 0);
 | 
			
		||||
  end
 | 
			
		||||
  else
 | 
			
		||||
  begin
 | 
			
		||||
    // Not even an old version installed
 | 
			
		||||
    Log('VC Redist x64 is not already installed');
 | 
			
		||||
    Result := True;
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
#define sourcepath "build\exe.win-amd64-3.8\"
 | 
			
		||||
#define MyAppName "Archipelago"
 | 
			
		||||
#define MyAppExeName "ArchipelagoLttPClient.exe"
 | 
			
		||||
#define MyAppExeName "ArchipelagoServer.exe"
 | 
			
		||||
#define MyAppIcon "data/icon.ico"
 | 
			
		||||
 | 
			
		||||
[Setup]
 | 
			
		||||
| 
						 | 
				
			
			@ -34,40 +34,65 @@ Name: "english"; MessagesFile: "compiler:Default.isl"
 | 
			
		|||
[Tasks]
 | 
			
		||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}";
 | 
			
		||||
 | 
			
		||||
[Types]
 | 
			
		||||
Name: "full"; Description: "Full installation"
 | 
			
		||||
Name: "hosting"; Description: "Installation for hosting purposes"
 | 
			
		||||
Name: "playing"; Description: "Installation for playing purposes"
 | 
			
		||||
Name: "custom"; Description: "Custom installation"; Flags: iscustom
 | 
			
		||||
 | 
			
		||||
[Components]
 | 
			
		||||
Name: "core"; Description: "Core Files"; Types: full hosting playing custom; Flags: fixed
 | 
			
		||||
Name: "generator"; Description: "Generator"; Types: full hosting
 | 
			
		||||
Name: "server"; Description: "Server"; Types: full hosting
 | 
			
		||||
Name: "client"; Description: "Clients"; Types: full playing
 | 
			
		||||
Name: "client/lttp"; Description: "A Link to the Past"; Types: full playing hosting
 | 
			
		||||
Name: "client/factorio"; Description: "Factorio"; Types: full playing
 | 
			
		||||
 | 
			
		||||
[Dirs]
 | 
			
		||||
NAME: "{app}"; Flags: setntfscompression; Permissions: everyone-modify users-modify authusers-modify;
 | 
			
		||||
 | 
			
		||||
[Files]
 | 
			
		||||
Source: "{code:GetROMPath}"; DestDir: "{app}"; DestName: "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"; Flags: external
 | 
			
		||||
Source: "{#sourcepath}*"; Excludes: "*.sfc, *.log, data\sprites\alttpr"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
 | 
			
		||||
Source: "{code:GetROMPath}"; DestDir: "{app}"; DestName: "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"; Flags: external; Components: client/lttp or server
 | 
			
		||||
Source: "{#sourcepath}*"; Excludes: "*.sfc, *.log, data\sprites\alttpr, SNI, EnemizerCLI, *exe"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
 | 
			
		||||
Source: "{#sourcepath}\SNI"; Excludes: "*.sfc, *.log"; DestDir: "{app}\SNI"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: client/lttp
 | 
			
		||||
Source: "{#sourcepath}\EnemizerCLI"; Excludes: "*.sfc, *.log"; DestDir: "{app}\EnemizerCLI"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: generator
 | 
			
		||||
 | 
			
		||||
Source: "{#sourcepath}\ArchipelagoGenerate.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: generator
 | 
			
		||||
Source: "{#sourcepath}\ArchipelagoServer.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: server
 | 
			
		||||
Source: "{#sourcepath}\ArchipelagoFactorioClient.exe";  DestDir: "{app}"; Flags: ignoreversion; Components: client/factorio
 | 
			
		||||
Source: "{#sourcepath}\ArchipelagoLttPClient.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: client/lttp
 | 
			
		||||
Source: "{#sourcepath}\ArchipelagoLttPAdjuster.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: client/lttp
 | 
			
		||||
Source: "vc_redist.x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall
 | 
			
		||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
 | 
			
		||||
 | 
			
		||||
[Icons]
 | 
			
		||||
Name: "{group}\{#MyAppName} Folder"; Filename: "{app}";
 | 
			
		||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}";
 | 
			
		||||
Name: "{group}\{#MyAppName} Server"; Filename: "{app}\{#MyAppExeName}"; Components: server
 | 
			
		||||
Name: "{group}\{#MyAppName} LttP Client"; Filename: "{app}\ArchipelagoLttPClient.exe"; Components: client/lttp
 | 
			
		||||
Name: "{group}\{#MyAppName} Factorio Client"; Filename: "{app}\ArchipelagoFactorioClient.exe"; Components: client/factorio
 | 
			
		||||
Name: "{commondesktop}\{#MyAppName} Folder"; Filename: "{app}"; Tasks: desktopicon
 | 
			
		||||
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
 | 
			
		||||
Name: "{commondesktop}\{#MyAppName} Server"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon; Components: server
 | 
			
		||||
Name: "{commondesktop}\{#MyAppName} LttP Client"; Filename: "{app}\ArchipelagoLttPClient.exe"; Tasks: desktopicon; Components: client/lttp
 | 
			
		||||
Name: "{commondesktop}\{#MyAppName} Factorio Client"; Filename: "{app}\ArchipelagoFactorioClient.exe"; Tasks: desktopicon; Components: client/factorio
 | 
			
		||||
 | 
			
		||||
[Run]
 | 
			
		||||
 | 
			
		||||
Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/passive /norestart"; Check: IsVCRedist64BitNeeded; StatusMsg: "Installing VC++ redistributable..."
 | 
			
		||||
Filename: "{app}\ArchipelagoLttPAdjuster"; Parameters: "--update_sprites"; StatusMsg: "Updating Sprite Library..."
 | 
			
		||||
Filename: "{app}\ArchipelagoLttPAdjuster"; Parameters: "--update_sprites"; StatusMsg: "Updating Sprite Library..."; Components: client/lttp or server
 | 
			
		||||
 | 
			
		||||
[UninstallDelete]
 | 
			
		||||
Type: dirifempty; Name: "{app}"
 | 
			
		||||
 | 
			
		||||
[Registry]
 | 
			
		||||
 | 
			
		||||
Root: HKCR; Subkey: ".apbp";                                 ValueData: "{#MyAppName}patch";        Flags: uninsdeletevalue; ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}patch";                     ValueData: "Archipelago Binary Patch";       Flags: uninsdeletekey;   ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}patch\DefaultIcon";         ValueData: "{app}\{#MyAppExeName},0";                           ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}patch\shell\open\command";  ValueData: """{app}\{#MyAppExeName}"" ""%1""";                  ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: ".apbp";                                 ValueData: "{#MyAppName}patch";        Flags: uninsdeletevalue; ValueType: string;  ValueName: ""; Components: client/lttp
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}patch";                     ValueData: "Archipelago Binary Patch"; Flags: uninsdeletekey;   ValueType: string;  ValueName: ""; Components: client/lttp
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}patch\DefaultIcon";         ValueData: "{app}\{#MyAppExeName},0";                           ValueType: string;  ValueName: ""; Components: client/lttp
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}patch\shell\open\command";  ValueData: """{app}\{#MyAppExeName}"" ""%1""";                  ValueType: string;  ValueName: ""; Components: client/lttp
 | 
			
		||||
 | 
			
		||||
Root: HKCR; Subkey: ".archipelago";                                ValueData: "{#MyAppName}multidata";        Flags: uninsdeletevalue; ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}multidata";                     ValueData: "Archipelago Server Data";       Flags: uninsdeletekey;   ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}multidata\DefaultIcon";         ValueData: "{app}\ArchipelagoServer.exe,0";                           ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}multidata\shell\open\command";  ValueData: """{app}\ArchipelagoServer.exe"" ""%1""";                  ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: ".archipelago";                              ValueData: "{#MyAppName}multidata";        Flags: uninsdeletevalue; ValueType: string;  ValueName: ""; Components: server
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}multidata";                     ValueData: "Archipelago Server Data";       Flags: uninsdeletekey;  ValueType: string;  ValueName: ""; Components: server
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}multidata\DefaultIcon";         ValueData: "{app}\ArchipelagoServer.exe,0";                         ValueType: string;  ValueName: ""; Components: server
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}multidata\shell\open\command";  ValueData: """{app}\ArchipelagoServer.exe"" ""%1""";                ValueType: string;  ValueName: ""; Components: server
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,141 +0,0 @@
 | 
			
		|||
#define sourcepath "build\exe.win-amd64-3.9\"
 | 
			
		||||
#define MyAppName "Archipelago"
 | 
			
		||||
#define MyAppExeName "ArchipelagoLttPClient.exe"
 | 
			
		||||
#define MyAppIcon "data/icon.ico"
 | 
			
		||||
 | 
			
		||||
[Setup]
 | 
			
		||||
; NOTE: The value of AppId uniquely identifies this application.
 | 
			
		||||
; Do not use the same AppId value in installers for other applications.
 | 
			
		||||
AppId={{918BA46A-FAB8-460C-9DFF-AE691E1C865B}}
 | 
			
		||||
AppName={#MyAppName}
 | 
			
		||||
AppVerName={#MyAppName}
 | 
			
		||||
DefaultDirName={commonappdata}\{#MyAppName}
 | 
			
		||||
DisableProgramGroupPage=yes
 | 
			
		||||
DefaultGroupName=Archipelago
 | 
			
		||||
OutputDir=setups
 | 
			
		||||
OutputBaseFilename=Setup {#MyAppName}
 | 
			
		||||
Compression=lzma2
 | 
			
		||||
SolidCompression=yes
 | 
			
		||||
LZMANumBlockThreads=8
 | 
			
		||||
ArchitecturesInstallIn64BitMode=x64
 | 
			
		||||
ChangesAssociations=yes
 | 
			
		||||
ArchitecturesAllowed=x64
 | 
			
		||||
AllowNoIcons=yes
 | 
			
		||||
SetupIconFile={#MyAppIcon}
 | 
			
		||||
UninstallDisplayIcon={app}\{#MyAppExeName}
 | 
			
		||||
SignTool= signtool
 | 
			
		||||
LicenseFile= LICENSE
 | 
			
		||||
WizardStyle= modern
 | 
			
		||||
SetupLogging=yes
 | 
			
		||||
 | 
			
		||||
[Languages]
 | 
			
		||||
Name: "english"; MessagesFile: "compiler:Default.isl"
 | 
			
		||||
 | 
			
		||||
[Tasks]
 | 
			
		||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[Dirs]
 | 
			
		||||
NAME: "{app}"; Flags: setntfscompression; Permissions: everyone-modify users-modify authusers-modify;
 | 
			
		||||
 | 
			
		||||
[Files]
 | 
			
		||||
Source: "{code:GetROMPath}"; DestDir: "{app}"; DestName: "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"; Flags: external
 | 
			
		||||
Source: "{#sourcepath}*"; Excludes: "*.sfc, *.log, data\sprites\alttpr"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
 | 
			
		||||
Source: "vc_redist.x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall
 | 
			
		||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
 | 
			
		||||
 | 
			
		||||
[Icons]
 | 
			
		||||
Name: "{group}\{#MyAppName} Folder"; Filename: "{app}";
 | 
			
		||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}";
 | 
			
		||||
Name: "{commondesktop}\{#MyAppName} Folder"; Filename: "{app}"; Tasks: desktopicon
 | 
			
		||||
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
 | 
			
		||||
 | 
			
		||||
[Run]
 | 
			
		||||
Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/passive /norestart"; Check: IsVCRedist64BitNeeded; StatusMsg: "Installing VC++ redistributable..."
 | 
			
		||||
Filename: "{app}\ArchipelagoLttPAdjuster"; Parameters: "--update_sprites"; StatusMsg: "Updating Sprite Library..."
 | 
			
		||||
 | 
			
		||||
[UninstallDelete]
 | 
			
		||||
Type: dirifempty; Name: "{app}"
 | 
			
		||||
 | 
			
		||||
[Registry]
 | 
			
		||||
 | 
			
		||||
Root: HKCR; Subkey: ".apbp";                                 ValueData: "{#MyAppName}patch";        Flags: uninsdeletevalue; ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}patch";                     ValueData: "Archipelago Binary Patch";       Flags: uninsdeletekey;   ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}patch\DefaultIcon";         ValueData: "{app}\{#MyAppExeName},0";                           ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}patch\shell\open\command";  ValueData: """{app}\{#MyAppExeName}"" ""%1""";                  ValueType: string;  ValueName: ""
 | 
			
		||||
 | 
			
		||||
Root: HKCR; Subkey: ".archipelago";                                ValueData: "{#MyAppName}multidata";        Flags: uninsdeletevalue; ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}multidata";                     ValueData: "Archipelago Server Data";       Flags: uninsdeletekey;   ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}multidata\DefaultIcon";         ValueData: "{app}\ArchipelagoServer.exe,0";                           ValueType: string;  ValueName: ""
 | 
			
		||||
Root: HKCR; Subkey: "{#MyAppName}multidata\shell\open\command";  ValueData: """{app}\ArchipelagoServer.exe"" ""%1""";                  ValueType: string;  ValueName: ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[Code]
 | 
			
		||||
// See: https://stackoverflow.com/a/51614652/2287576
 | 
			
		||||
function IsVCRedist64BitNeeded(): boolean;
 | 
			
		||||
var
 | 
			
		||||
  strVersion: string;
 | 
			
		||||
begin
 | 
			
		||||
  if (RegQueryStringValue(HKEY_LOCAL_MACHINE,
 | 
			
		||||
    'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64', 'Version', strVersion)) then
 | 
			
		||||
  begin
 | 
			
		||||
    // Is the installed version at least the packaged one ?
 | 
			
		||||
    Log('VC Redist x64 Version : found ' + strVersion);
 | 
			
		||||
    Result := (CompareStr(strVersion, 'v14.29.30037') < 0);
 | 
			
		||||
  end
 | 
			
		||||
  else
 | 
			
		||||
  begin
 | 
			
		||||
    // Not even an old version installed
 | 
			
		||||
    Log('VC Redist x64 is not already installed');
 | 
			
		||||
    Result := True;
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
var ROMFilePage: TInputFileWizardPage;
 | 
			
		||||
var R : longint;
 | 
			
		||||
var rom: string;
 | 
			
		||||
 | 
			
		||||
procedure InitializeWizard();
 | 
			
		||||
begin
 | 
			
		||||
  rom := FileSearch('Zelda no Densetsu - Kamigami no Triforce (Japan).sfc', WizardDirValue());
 | 
			
		||||
  if Length(rom) > 0 then
 | 
			
		||||
    begin
 | 
			
		||||
      log('existing ROM found');
 | 
			
		||||
      log(IntToStr(CompareStr(GetMD5OfFile(rom), '03a63945398191337e896e5771f77173')));
 | 
			
		||||
      if CompareStr(GetMD5OfFile(rom), '03a63945398191337e896e5771f77173') = 0 then
 | 
			
		||||
        begin
 | 
			
		||||
        log('existing ROM verified');
 | 
			
		||||
        exit;
 | 
			
		||||
        end;
 | 
			
		||||
      log('existing ROM failed verification');
 | 
			
		||||
    end;
 | 
			
		||||
  rom := ''
 | 
			
		||||
  ROMFilePage :=
 | 
			
		||||
    CreateInputFilePage(
 | 
			
		||||
      wpLicense,
 | 
			
		||||
      'Select ROM File',
 | 
			
		||||
      'Where is your Zelda no Densetsu - Kamigami no Triforce (Japan).sfc located?',
 | 
			
		||||
      'Select the file, then click Next.');
 | 
			
		||||
 | 
			
		||||
  ROMFilePage.Add(
 | 
			
		||||
    'Location of ROM file:',         
 | 
			
		||||
    'SNES ROM files|*.sfc|All files|*.*', 
 | 
			
		||||
    '.sfc');                             
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function GetROMPath(Param: string): string;
 | 
			
		||||
begin
 | 
			
		||||
  if Length(rom) > 0 then
 | 
			
		||||
    Result := rom
 | 
			
		||||
  else if Assigned(RomFilePage) then
 | 
			
		||||
    begin
 | 
			
		||||
      R := CompareStr(GetMD5OfFile(ROMFilePage.Values[0]), '03a63945398191337e896e5771f77173')
 | 
			
		||||
      if R <> 0 then
 | 
			
		||||
        MsgBox('ROM validation failed. Very likely wrong file.', mbInformation, MB_OK);
 | 
			
		||||
  
 | 
			
		||||
      Result := ROMFilePage.Values[0]
 | 
			
		||||
    end
 | 
			
		||||
  else
 | 
			
		||||
    Result := '';
 | 
			
		||||
 end;
 | 
			
		||||
							
								
								
									
										9
									
								
								kvui.py
								
								
								
								
							
							
						
						
									
										9
									
								
								kvui.py
								
								
								
								
							| 
						 | 
				
			
			@ -83,9 +83,12 @@ class FactorioManager(GameManager):
 | 
			
		|||
    ]
 | 
			
		||||
    title = "Archipelago Factorio Client"
 | 
			
		||||
 | 
			
		||||
    def __init__(self, ctx):
 | 
			
		||||
        super(FactorioManager, self).__init__(ctx)
 | 
			
		||||
 | 
			
		||||
class LttPManager(GameManager):
 | 
			
		||||
    logging_pairs = [
 | 
			
		||||
        ("Client", "Archipelago"),
 | 
			
		||||
        ("SNES", "SNES"),
 | 
			
		||||
    ]
 | 
			
		||||
    title = "Archipelago LttP Client"
 | 
			
		||||
 | 
			
		||||
class LogtoUI(logging.Handler):
 | 
			
		||||
    def __init__(self, on_log):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										107
									
								
								setup.py
								
								
								
								
							
							
						
						
									
										107
									
								
								setup.py
								
								
								
								
							| 
						 | 
				
			
			@ -4,12 +4,13 @@ import sys
 | 
			
		|||
import sysconfig
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
import cx_Freeze
 | 
			
		||||
from kivy_deps import sdl2, glew
 | 
			
		||||
 | 
			
		||||
is_64bits = sys.maxsize > 2 ** 32
 | 
			
		||||
 | 
			
		||||
folder = "exe.{platform}-{version}".format(platform=sysconfig.get_platform(),
 | 
			
		||||
arch_folder = "exe.{platform}-{version}".format(platform=sysconfig.get_platform(),
 | 
			
		||||
                                           version=sysconfig.get_python_version())
 | 
			
		||||
buildfolder = Path("build", folder)
 | 
			
		||||
buildfolder = Path("build", arch_folder)
 | 
			
		||||
sbuildfolder = str(buildfolder)
 | 
			
		||||
libfolder = Path(buildfolder, "lib")
 | 
			
		||||
library = Path(libfolder, "library.zip")
 | 
			
		||||
| 
						 | 
				
			
			@ -56,20 +57,31 @@ def manifest_creation(folder):
 | 
			
		|||
    print("Created Manifest")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def remove_sprites_from_folder(folder):
 | 
			
		||||
    for file in os.listdir(folder):
 | 
			
		||||
        if file != ".gitignore":
 | 
			
		||||
            os.remove(folder / file)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
scripts = {
 | 
			
		||||
    "LttPClient.py": "ArchipelagoLttPClient",
 | 
			
		||||
    "MultiServer.py": "ArchipelagoServer",
 | 
			
		||||
    "Generate.py": "ArchipelagoGenerate",
 | 
			
		||||
    "LttPAdjuster.py": "ArchipelagoLttPAdjuster"
 | 
			
		||||
    # Core
 | 
			
		||||
    "MultiServer.py": ("ArchipelagoServer", False),
 | 
			
		||||
    "Generate.py": ("ArchipelagoGenerate", False),
 | 
			
		||||
    # LttP
 | 
			
		||||
    "LttPClient.py": ("ArchipelagoLttPClient", True),
 | 
			
		||||
    "LttPAdjuster.py": ("ArchipelagoLttPAdjuster", True),
 | 
			
		||||
    # Factorio
 | 
			
		||||
    "FactorioClient.py": ("ArchipelagoFactorioClient", True),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
exes = []
 | 
			
		||||
 | 
			
		||||
for script, scriptname in scripts.items():
 | 
			
		||||
for script, (scriptname, gui) in scripts.items():
 | 
			
		||||
    exes.append(cx_Freeze.Executable(
 | 
			
		||||
        script=script,
 | 
			
		||||
        target_name=scriptname + ("" if sys.platform == "linux" else ".exe"),
 | 
			
		||||
        icon=icon,
 | 
			
		||||
        base="Win32GUI" if sys.platform == "win32" and gui else None
 | 
			
		||||
    ))
 | 
			
		||||
 | 
			
		||||
import datetime
 | 
			
		||||
| 
						 | 
				
			
			@ -83,14 +95,14 @@ cx_Freeze.setup(
 | 
			
		|||
    executables=exes,
 | 
			
		||||
    options={
 | 
			
		||||
        "build_exe": {
 | 
			
		||||
            "packages": ["websockets", "worlds"],
 | 
			
		||||
            "packages": ["websockets", "worlds", "kivy"],
 | 
			
		||||
            "includes": [],
 | 
			
		||||
            "excludes": ["numpy", "Cython", "PySide2", "PIL",
 | 
			
		||||
                         "pandas"],
 | 
			
		||||
            "zip_include_packages": ["*"],
 | 
			
		||||
            "zip_exclude_packages": ["worlds"],
 | 
			
		||||
            "zip_exclude_packages": ["worlds", "kivy"],
 | 
			
		||||
            "include_files": [],
 | 
			
		||||
            "include_msvcr": True,
 | 
			
		||||
            "include_msvcr": False,
 | 
			
		||||
            "replace_paths": [("*", "")],
 | 
			
		||||
            "optimize": 1,
 | 
			
		||||
            "build_exe": buildfolder
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +124,9 @@ def installfile(path, keep_content=False):
 | 
			
		|||
    else:
 | 
			
		||||
        print('Warning,', path, 'not found')
 | 
			
		||||
 | 
			
		||||
for folder in sdl2.dep_bins+glew.dep_bins:
 | 
			
		||||
    shutil.copytree(folder, libfolder, dirs_exist_ok=True)
 | 
			
		||||
    print('copying', folder, '->', libfolder)
 | 
			
		||||
 | 
			
		||||
extra_data = ["LICENSE", "data", "EnemizerCLI", "host.yaml", "SNI", "meta.yaml"]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -138,76 +153,6 @@ if signtool:
 | 
			
		|||
    print(f"Signing SNI")
 | 
			
		||||
    os.system(signtool + os.path.join(buildfolder, "SNI", "SNI.exe"))
 | 
			
		||||
 | 
			
		||||
alttpr_sprites_folder = buildfolder / "data" / "sprites" / "alttpr"
 | 
			
		||||
for file in os.listdir(alttpr_sprites_folder):
 | 
			
		||||
    if file != ".gitignore":
 | 
			
		||||
        os.remove(alttpr_sprites_folder / file)
 | 
			
		||||
 | 
			
		||||
manifest_creation(buildfolder)
 | 
			
		||||
 | 
			
		||||
buildfolder = Path("build_factorio", folder)
 | 
			
		||||
sbuildfolder = str(buildfolder)
 | 
			
		||||
libfolder = Path(buildfolder, "lib")
 | 
			
		||||
library = Path(libfolder, "library.zip")
 | 
			
		||||
print("Outputting Factorio Client to: " + sbuildfolder)
 | 
			
		||||
 | 
			
		||||
os.makedirs(buildfolder, exist_ok=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
exes = [
 | 
			
		||||
    cx_Freeze.Executable(
 | 
			
		||||
    script="FactorioClient.py",
 | 
			
		||||
    target_name="ArchipelagoFactorioClient" + ("" if sys.platform == "linux" else ".exe"),
 | 
			
		||||
    icon=icon,
 | 
			
		||||
    base="Win32GUI" if sys.platform == "win32" else None
 | 
			
		||||
)]
 | 
			
		||||
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
buildtime = datetime.datetime.utcnow()
 | 
			
		||||
 | 
			
		||||
cx_Freeze.setup(
 | 
			
		||||
    name="Archipelago Factorio Client",
 | 
			
		||||
    version=f"{buildtime.year}.{buildtime.month}.{buildtime.day}.{buildtime.hour}",
 | 
			
		||||
    description="Archipelago Factorio Client",
 | 
			
		||||
    executables=exes,
 | 
			
		||||
    options={
 | 
			
		||||
        "build_exe": {
 | 
			
		||||
            "packages": ["websockets", "kivy", "worlds"],
 | 
			
		||||
            "includes": [],
 | 
			
		||||
            "excludes": ["numpy", "Cython", "PySide2", "PIL",
 | 
			
		||||
                         "pandas"],
 | 
			
		||||
            "zip_include_packages": ["*"],
 | 
			
		||||
            "zip_exclude_packages": ["kivy", "worlds"],
 | 
			
		||||
            "include_files": [],
 | 
			
		||||
            "include_msvcr": True,
 | 
			
		||||
            "replace_paths": [("*", "")],
 | 
			
		||||
            "optimize": 1,
 | 
			
		||||
            "build_exe": buildfolder
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extra_data = ["LICENSE", "data", "host.yaml", "meta.yaml"]
 | 
			
		||||
from kivy_deps import sdl2, glew
 | 
			
		||||
for folder in sdl2.dep_bins+glew.dep_bins:
 | 
			
		||||
    shutil.copytree(folder, buildfolder, dirs_exist_ok=True)
 | 
			
		||||
for data in extra_data:
 | 
			
		||||
    installfile(Path(data))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
os.makedirs(buildfolder / "Players", exist_ok=True)
 | 
			
		||||
shutil.copyfile("playerSettings.yaml", buildfolder / "Players" / "weightedSettings.yaml")
 | 
			
		||||
 | 
			
		||||
if signtool:
 | 
			
		||||
    for exe in exes:
 | 
			
		||||
        print(f"Signing {exe.target_name}")
 | 
			
		||||
        os.system(signtool + os.path.join(buildfolder, exe.target_name))
 | 
			
		||||
 | 
			
		||||
alttpr_sprites_folder = buildfolder / "data" / "sprites" / "alttpr"
 | 
			
		||||
for file in os.listdir(alttpr_sprites_folder):
 | 
			
		||||
    if file != ".gitignore":
 | 
			
		||||
        os.remove(alttpr_sprites_folder / file)
 | 
			
		||||
remove_sprites_from_folder(buildfolder / "data" / "sprites" / "alttpr")
 | 
			
		||||
 | 
			
		||||
manifest_creation(buildfolder)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue