Merge together FactorioClient.py and FactorioClientGUI.py
Add cmd arguments Add kivy style file, allowing users to modify it
This commit is contained in:
parent
5c8a076790
commit
573fde4bbc
|
@ -8,12 +8,8 @@ import websockets
|
||||||
|
|
||||||
import Utils
|
import Utils
|
||||||
from MultiServer import CommandProcessor
|
from MultiServer import CommandProcessor
|
||||||
|
|
||||||
from NetUtils import Endpoint, decode, NetworkItem, encode, JSONtoTextParser, color, ClientStatus
|
from NetUtils import Endpoint, decode, NetworkItem, encode, JSONtoTextParser, color, ClientStatus
|
||||||
from Utils import Version
|
from Utils import Version
|
||||||
|
|
||||||
# logging note:
|
|
||||||
# logging.* gets send to only the text console, logger.* gets send to the WebUI as well, if it's initialized.
|
|
||||||
from worlds import network_data_package, AutoWorldRegister
|
from worlds import network_data_package, AutoWorldRegister
|
||||||
|
|
||||||
logger = logging.getLogger("Client")
|
logger = logging.getLogger("Client")
|
||||||
|
@ -93,7 +89,7 @@ class CommonContext():
|
||||||
command_processor = ClientCommandProcessor
|
command_processor = ClientCommandProcessor
|
||||||
game: None
|
game: None
|
||||||
|
|
||||||
def __init__(self, server_address, password, found_items: bool):
|
def __init__(self, server_address, password):
|
||||||
# server state
|
# server state
|
||||||
self.server_address = server_address
|
self.server_address = server_address
|
||||||
self.password = password
|
self.password = password
|
||||||
|
@ -104,7 +100,6 @@ class CommonContext():
|
||||||
# own state
|
# own state
|
||||||
self.finished_game = False
|
self.finished_game = False
|
||||||
self.ready = False
|
self.ready = False
|
||||||
self.found_items = found_items
|
|
||||||
self.team = None
|
self.team = None
|
||||||
self.slot = None
|
self.slot = None
|
||||||
self.auth = None
|
self.auth = None
|
||||||
|
|
|
@ -20,23 +20,116 @@ from NetUtils import RawJSONtoTextParser, NetworkItem, ClientStatus, JSONtoTextP
|
||||||
|
|
||||||
from worlds.factorio.Technologies import lookup_id_to_name
|
from worlds.factorio.Technologies import lookup_id_to_name
|
||||||
|
|
||||||
rcon_port = 24242
|
os.makedirs("logs", exist_ok=True)
|
||||||
rcon_password = ''.join(random.choice(string.ascii_letters) for x in range(32))
|
|
||||||
|
|
||||||
logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO)
|
# Log to file in gui case
|
||||||
factorio_server_logger = logging.getLogger("FactorioServer")
|
if getattr(sys, "frozen", False) and not "--nogui" in sys.argv:
|
||||||
options = Utils.get_options()
|
logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO,
|
||||||
executable = options["factorio_options"]["executable"]
|
filename=os.path.join("logs", "FactorioClient.txt"), filemode="w")
|
||||||
bin_dir = os.path.dirname(executable)
|
else:
|
||||||
if not os.path.isdir(bin_dir):
|
logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO)
|
||||||
raise FileNotFoundError(bin_dir)
|
logging.getLogger().addHandler(logging.FileHandler(os.path.join("logs", "FactorioClient.txt"), "w"))
|
||||||
if not os.path.exists(executable):
|
|
||||||
if os.path.exists(executable + ".exe"):
|
|
||||||
executable = executable + ".exe"
|
|
||||||
else:
|
|
||||||
raise FileNotFoundError(executable)
|
|
||||||
|
|
||||||
server_args = ("--rcon-port", rcon_port, "--rcon-password", rcon_password, *sys.argv[1:])
|
gui_enabled = Utils.is_frozen() or "--nogui" not in sys.argv
|
||||||
|
|
||||||
|
if gui_enabled:
|
||||||
|
os.environ["KIVY_NO_CONSOLELOG"] = "1"
|
||||||
|
os.environ["KIVY_NO_FILELOG"] = "1"
|
||||||
|
os.environ["KIVY_NO_ARGS"] = "1"
|
||||||
|
from kivy.app import App
|
||||||
|
from kivy.base import ExceptionHandler, ExceptionManager, Config
|
||||||
|
from kivy.uix.gridlayout import GridLayout
|
||||||
|
from kivy.uix.textinput import TextInput
|
||||||
|
from kivy.uix.recycleview import RecycleView
|
||||||
|
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
|
||||||
|
from kivy.lang import Builder
|
||||||
|
|
||||||
|
|
||||||
|
class FactorioManager(App):
|
||||||
|
def __init__(self, ctx):
|
||||||
|
super(FactorioManager, self).__init__()
|
||||||
|
self.ctx = ctx
|
||||||
|
self.commandprocessor = ctx.command_processor(ctx)
|
||||||
|
self.icon = r"data/icon.png"
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
self.grid = GridLayout()
|
||||||
|
self.grid.cols = 1
|
||||||
|
|
||||||
|
self.tabs = TabbedPanel()
|
||||||
|
self.tabs.default_tab_text = "All"
|
||||||
|
self.title = "Archipelago Factorio Client"
|
||||||
|
pairs = [
|
||||||
|
("Client", "Archipelago"),
|
||||||
|
("FactorioServer", "Factorio Server Log"),
|
||||||
|
("FactorioWatcher", "Bridge Data Log"),
|
||||||
|
]
|
||||||
|
self.tabs.default_tab_content = UILog(*(logging.getLogger(logger_name) for logger_name, name in pairs))
|
||||||
|
for logger_name, display_name in pairs:
|
||||||
|
bridge_logger = logging.getLogger(logger_name)
|
||||||
|
panel = TabbedPanelItem(text=display_name)
|
||||||
|
panel.content = UILog(bridge_logger)
|
||||||
|
self.tabs.add_widget(panel)
|
||||||
|
|
||||||
|
self.grid.add_widget(self.tabs)
|
||||||
|
textinput = TextInput(size_hint_y=None, height=30, multiline=False)
|
||||||
|
textinput.bind(on_text_validate=self.on_message)
|
||||||
|
self.grid.add_widget(textinput)
|
||||||
|
self.commandprocessor("/help")
|
||||||
|
return self.grid
|
||||||
|
|
||||||
|
def on_stop(self):
|
||||||
|
self.ctx.exit_event.set()
|
||||||
|
|
||||||
|
def on_message(self, textinput: TextInput):
|
||||||
|
try:
|
||||||
|
input_text = textinput.text.strip()
|
||||||
|
textinput.text = ""
|
||||||
|
|
||||||
|
if self.ctx.input_requests > 0:
|
||||||
|
self.ctx.input_requests -= 1
|
||||||
|
self.ctx.input_queue.put_nowait(input_text)
|
||||||
|
elif input_text:
|
||||||
|
self.commandprocessor(input_text)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
|
||||||
|
def on_address(self, text: str):
|
||||||
|
print(text)
|
||||||
|
|
||||||
|
|
||||||
|
class LogtoUI(logging.Handler):
|
||||||
|
def __init__(self, on_log):
|
||||||
|
super(LogtoUI, self).__init__(logging.DEBUG)
|
||||||
|
self.on_log = on_log
|
||||||
|
|
||||||
|
def handle(self, record: logging.LogRecord) -> None:
|
||||||
|
self.on_log(record)
|
||||||
|
|
||||||
|
|
||||||
|
class UILog(RecycleView):
|
||||||
|
cols = 1
|
||||||
|
|
||||||
|
def __init__(self, *loggers_to_handle, **kwargs):
|
||||||
|
super(UILog, self).__init__(**kwargs)
|
||||||
|
self.data = []
|
||||||
|
for logger in loggers_to_handle:
|
||||||
|
logger.addHandler(LogtoUI(self.on_log))
|
||||||
|
|
||||||
|
def on_log(self, record: logging.LogRecord) -> None:
|
||||||
|
self.data.append({"text": record.getMessage()})
|
||||||
|
|
||||||
|
|
||||||
|
class E(ExceptionHandler):
|
||||||
|
def handle_exception(self, inst):
|
||||||
|
logger.exception(inst)
|
||||||
|
return ExceptionManager.RAISE
|
||||||
|
|
||||||
|
|
||||||
|
ExceptionManager.add_handler(E())
|
||||||
|
|
||||||
|
Config.set("input", "mouse", "mouse,disable_multitouch")
|
||||||
|
Builder.load_file(Utils.local_path("data", "client.kv"))
|
||||||
|
|
||||||
|
|
||||||
class FactorioCommandProcessor(ClientCommandProcessor):
|
class FactorioCommandProcessor(ClientCommandProcessor):
|
||||||
|
@ -66,8 +159,8 @@ class FactorioContext(CommonContext):
|
||||||
command_processor = FactorioCommandProcessor
|
command_processor = FactorioCommandProcessor
|
||||||
game = "Factorio"
|
game = "Factorio"
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, server_address, password):
|
||||||
super(FactorioContext, self).__init__(*args, **kwargs)
|
super(FactorioContext, self).__init__(server_address, password)
|
||||||
self.send_index = 0
|
self.send_index = 0
|
||||||
self.rcon_client = None
|
self.rcon_client = None
|
||||||
self.awaiting_bridge = False
|
self.awaiting_bridge = False
|
||||||
|
@ -92,8 +185,6 @@ class FactorioContext(CommonContext):
|
||||||
f"{cleaned_text}\")")
|
f"{cleaned_text}\")")
|
||||||
|
|
||||||
def on_print_json(self, args: dict):
|
def on_print_json(self, args: dict):
|
||||||
if not self.found_items and args.get("type", None) == "ItemSend" and args["receiving"] == args["sending"]:
|
|
||||||
pass # don't want info on other player's local pickups.
|
|
||||||
text = self.raw_json_text_parser(copy.deepcopy(args["data"]))
|
text = self.raw_json_text_parser(copy.deepcopy(args["data"]))
|
||||||
logger.info(text)
|
logger.info(text)
|
||||||
if self.rcon_client:
|
if self.rcon_client:
|
||||||
|
@ -118,7 +209,8 @@ async def game_watcher(ctx: FactorioContext):
|
||||||
if data["slot_name"] != ctx.auth:
|
if data["slot_name"] != ctx.auth:
|
||||||
logger.warning(f"Connected World is not the expected one {data['slot_name']} != {ctx.auth}")
|
logger.warning(f"Connected World is not the expected one {data['slot_name']} != {ctx.auth}")
|
||||||
elif data["seed_name"] != ctx.seed_name:
|
elif data["seed_name"] != ctx.seed_name:
|
||||||
logger.warning(f"Connected Multiworld is not the expected one {data['seed_name']} != {ctx.seed_name}")
|
logger.warning(
|
||||||
|
f"Connected Multiworld is not the expected one {data['seed_name']} != {ctx.seed_name}")
|
||||||
else:
|
else:
|
||||||
data = data["info"]
|
data = data["info"]
|
||||||
research_data = data["research_done"]
|
research_data = data["research_done"]
|
||||||
|
@ -246,7 +338,6 @@ async def factorio_spinup_server(ctx: FactorioContext):
|
||||||
rcon_client = factorio_rcon.RCONClient("localhost", rcon_port, rcon_password)
|
rcon_client = factorio_rcon.RCONClient("localhost", rcon_port, rcon_password)
|
||||||
get_info(ctx, rcon_client)
|
get_info(ctx, rcon_client)
|
||||||
|
|
||||||
|
|
||||||
await asyncio.sleep(0.01)
|
await asyncio.sleep(0.01)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -261,12 +352,12 @@ async def factorio_spinup_server(ctx: FactorioContext):
|
||||||
factorio_process.terminate()
|
factorio_process.terminate()
|
||||||
|
|
||||||
|
|
||||||
async def main(ui=None):
|
async def main(args):
|
||||||
ctx = FactorioContext(None, None, True)
|
ctx = FactorioContext(args.connect, args.password)
|
||||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
|
ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
|
||||||
if ui:
|
if gui_enabled:
|
||||||
input_task = None
|
input_task = None
|
||||||
ui_app = ui(ctx)
|
ui_app = FactorioManager(ctx)
|
||||||
ui_task = asyncio.create_task(ui_app.async_run(), name="UI")
|
ui_task = asyncio.create_task(ui_app.async_run(), name="UI")
|
||||||
else:
|
else:
|
||||||
input_task = asyncio.create_task(console_loop(ctx), name="Input")
|
input_task = asyncio.create_task(console_loop(ctx), name="Input")
|
||||||
|
@ -314,8 +405,36 @@ class FactorioJSONtoTextParser(JSONtoTextParser):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--rcon-port', default='24242', type=int, help='Port to use to communicate with Factorio')
|
||||||
|
parser.add_argument('--connect', default=None, help='Address of the multiworld host.')
|
||||||
|
parser.add_argument('--password', default=None, help='Password of the multiworld host.')
|
||||||
|
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.")
|
||||||
|
parser.add_argument('factorio_server_args', nargs='*', help="All remaining arguments get passed "
|
||||||
|
"into the Factorio server startup.")
|
||||||
|
args = parser.parse_args()
|
||||||
colorama.init()
|
colorama.init()
|
||||||
|
rcon_port = args.rcon_port
|
||||||
|
rcon_password = ''.join(random.choice(string.ascii_letters) for x in range(32))
|
||||||
|
|
||||||
|
factorio_server_logger = logging.getLogger("FactorioServer")
|
||||||
|
options = Utils.get_options()
|
||||||
|
executable = options["factorio_options"]["executable"]
|
||||||
|
bin_dir = os.path.dirname(executable)
|
||||||
|
if not os.path.isdir(bin_dir):
|
||||||
|
raise FileNotFoundError(bin_dir)
|
||||||
|
if not os.path.exists(executable):
|
||||||
|
if os.path.exists(executable + ".exe"):
|
||||||
|
executable = executable + ".exe"
|
||||||
|
else:
|
||||||
|
raise FileNotFoundError(executable)
|
||||||
|
|
||||||
|
server_args = ("--rcon-port", rcon_port, "--rcon-password", rcon_password, *args.factorio_server_args)
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
loop.run_until_complete(main())
|
loop.run_until_complete(main(args))
|
||||||
loop.close()
|
loop.close()
|
||||||
colorama.deinit()
|
colorama.deinit()
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
os.makedirs("logs", exist_ok=True)
|
|
||||||
if getattr(sys, "frozen", False):
|
|
||||||
logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO,
|
|
||||||
filename=os.path.join("logs", "FactorioClient.txt"), filemode="w")
|
|
||||||
else:
|
|
||||||
logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO)
|
|
||||||
logging.getLogger().addHandler(logging.FileHandler(os.path.join("logs", "FactorioClient.txt"), "w"))
|
|
||||||
os.environ["KIVY_NO_CONSOLELOG"] = "1"
|
|
||||||
os.environ["KIVY_NO_FILELOG"] = "1"
|
|
||||||
os.environ["KIVY_NO_ARGS"] = "1"
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from CommonClient import logger
|
|
||||||
from FactorioClient import main
|
|
||||||
|
|
||||||
|
|
||||||
from kivy.app import App
|
|
||||||
from kivy.uix.label import Label
|
|
||||||
from kivy.base import ExceptionHandler, ExceptionManager, Config
|
|
||||||
from kivy.uix.gridlayout import GridLayout
|
|
||||||
from kivy.uix.textinput import TextInput
|
|
||||||
from kivy.uix.recycleview import RecycleView
|
|
||||||
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
|
|
||||||
from kivy.lang import Builder
|
|
||||||
|
|
||||||
|
|
||||||
class FactorioManager(App):
|
|
||||||
def __init__(self, ctx):
|
|
||||||
super(FactorioManager, self).__init__()
|
|
||||||
self.ctx = ctx
|
|
||||||
self.commandprocessor = ctx.command_processor(ctx)
|
|
||||||
self.icon = r"data/icon.png"
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
self.grid = GridLayout()
|
|
||||||
self.grid.cols = 1
|
|
||||||
self.tabs = TabbedPanel()
|
|
||||||
self.tabs.default_tab_text = "All"
|
|
||||||
self.title = "Archipelago Factorio Client"
|
|
||||||
pairs = [
|
|
||||||
("Client", "Archipelago"),
|
|
||||||
("FactorioServer", "Factorio Server Log"),
|
|
||||||
("FactorioWatcher", "Bridge Data Log"),
|
|
||||||
]
|
|
||||||
self.tabs.default_tab_content = UILog(*(logging.getLogger(logger_name) for logger_name, name in pairs))
|
|
||||||
for logger_name, display_name in pairs:
|
|
||||||
bridge_logger = logging.getLogger(logger_name)
|
|
||||||
panel = TabbedPanelItem(text=display_name)
|
|
||||||
panel.content = UILog(bridge_logger)
|
|
||||||
self.tabs.add_widget(panel)
|
|
||||||
|
|
||||||
self.grid.add_widget(self.tabs)
|
|
||||||
textinput = TextInput(size_hint_y=None, height=30, multiline=False)
|
|
||||||
textinput.bind(on_text_validate=self.on_message)
|
|
||||||
self.grid.add_widget(textinput)
|
|
||||||
self.commandprocessor("/help")
|
|
||||||
return self.grid
|
|
||||||
|
|
||||||
def on_stop(self):
|
|
||||||
self.ctx.exit_event.set()
|
|
||||||
|
|
||||||
def on_message(self, textinput: TextInput):
|
|
||||||
try:
|
|
||||||
input_text = textinput.text.strip()
|
|
||||||
textinput.text = ""
|
|
||||||
|
|
||||||
if self.ctx.input_requests > 0:
|
|
||||||
self.ctx.input_requests -= 1
|
|
||||||
self.ctx.input_queue.put_nowait(input_text)
|
|
||||||
elif input_text:
|
|
||||||
self.commandprocessor(input_text)
|
|
||||||
except Exception as e:
|
|
||||||
logger.exception(e)
|
|
||||||
|
|
||||||
|
|
||||||
class LogtoUI(logging.Handler):
|
|
||||||
def __init__(self, on_log):
|
|
||||||
super(LogtoUI, self).__init__(logging.DEBUG)
|
|
||||||
self.on_log = on_log
|
|
||||||
|
|
||||||
def handle(self, record: logging.LogRecord) -> None:
|
|
||||||
self.on_log(record)
|
|
||||||
|
|
||||||
|
|
||||||
class UILog(RecycleView):
|
|
||||||
cols = 1
|
|
||||||
|
|
||||||
def __init__(self, *loggers_to_handle, **kwargs):
|
|
||||||
super(UILog, self).__init__(**kwargs)
|
|
||||||
self.data = []
|
|
||||||
for logger in loggers_to_handle:
|
|
||||||
logger.addHandler(LogtoUI(self.on_log))
|
|
||||||
|
|
||||||
def on_log(self, record: logging.LogRecord) -> None:
|
|
||||||
self.data.append({"text": record.getMessage()})
|
|
||||||
|
|
||||||
|
|
||||||
class E(ExceptionHandler):
|
|
||||||
def handle_exception(self, inst):
|
|
||||||
logger.exception(inst)
|
|
||||||
return ExceptionManager.RAISE
|
|
||||||
|
|
||||||
ExceptionManager.add_handler(E())
|
|
||||||
|
|
||||||
|
|
||||||
Config.set("input", "mouse", "mouse,disable_multitouch")
|
|
||||||
Builder.load_string('''
|
|
||||||
<TabbedPanel>
|
|
||||||
tab_width: 200
|
|
||||||
<Row@Label>:
|
|
||||||
canvas.before:
|
|
||||||
Color:
|
|
||||||
rgba: 0.2, 0.2, 0.2, 1
|
|
||||||
Rectangle:
|
|
||||||
size: self.size
|
|
||||||
pos: self.pos
|
|
||||||
text_size: self.width, None
|
|
||||||
size_hint_y: None
|
|
||||||
height: self.texture_size[1]
|
|
||||||
font_size: dp(20)
|
|
||||||
<UILog>:
|
|
||||||
viewclass: 'Row'
|
|
||||||
scroll_y: 0
|
|
||||||
effect_cls: "ScrollEffect"
|
|
||||||
RecycleBoxLayout:
|
|
||||||
default_size: None, dp(20)
|
|
||||||
default_size_hint: 1, None
|
|
||||||
size_hint_y: None
|
|
||||||
height: self.minimum_height
|
|
||||||
orientation: 'vertical'
|
|
||||||
spacing: dp(3)
|
|
||||||
''')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
ui_app = FactorioManager
|
|
||||||
loop.run_until_complete(main(ui_app))
|
|
||||||
loop.close()
|
|
|
@ -59,8 +59,8 @@ class Context(CommonContext):
|
||||||
command_processor = LttPCommandProcessor
|
command_processor = LttPCommandProcessor
|
||||||
game = "A Link to the Past"
|
game = "A Link to the Past"
|
||||||
|
|
||||||
def __init__(self, snes_address, server_address, password, found_items):
|
def __init__(self, snes_address, server_address, password):
|
||||||
super(Context, self).__init__(server_address, password, found_items)
|
super(Context, self).__init__(server_address, password)
|
||||||
|
|
||||||
# snes stuff
|
# snes stuff
|
||||||
self.snes_address = snes_address
|
self.snes_address = snes_address
|
||||||
|
|
4
Utils.py
4
Utils.py
|
@ -84,7 +84,7 @@ def cache_argsless(function):
|
||||||
return _wrap
|
return _wrap
|
||||||
|
|
||||||
|
|
||||||
def is_bundled() -> bool:
|
def is_frozen() -> bool:
|
||||||
return getattr(sys, 'frozen', False)
|
return getattr(sys, 'frozen', False)
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ def local_path(*path):
|
||||||
if local_path.cached_path:
|
if local_path.cached_path:
|
||||||
return os.path.join(local_path.cached_path, *path)
|
return os.path.join(local_path.cached_path, *path)
|
||||||
|
|
||||||
elif is_bundled():
|
elif is_frozen():
|
||||||
if hasattr(sys, "_MEIPASS"):
|
if hasattr(sys, "_MEIPASS"):
|
||||||
# we are running in a PyInstaller bundle
|
# we are running in a PyInstaller bundle
|
||||||
local_path.cached_path = sys._MEIPASS # pylint: disable=protected-access,no-member
|
local_path.cached_path = sys._MEIPASS # pylint: disable=protected-access,no-member
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
<TabbedPanel>
|
||||||
|
tab_width: 200
|
||||||
|
<Row@Label>:
|
||||||
|
canvas.before:
|
||||||
|
Color:
|
||||||
|
rgba: 0.2, 0.2, 0.2, 1
|
||||||
|
Rectangle:
|
||||||
|
size: self.size
|
||||||
|
pos: self.pos
|
||||||
|
text_size: self.width, None
|
||||||
|
size_hint_y: None
|
||||||
|
height: self.texture_size[1]
|
||||||
|
font_size: dp(20)
|
||||||
|
<UILog>:
|
||||||
|
viewclass: 'Row'
|
||||||
|
scroll_y: 0
|
||||||
|
effect_cls: "ScrollEffect"
|
||||||
|
RecycleBoxLayout:
|
||||||
|
default_size: None, dp(20)
|
||||||
|
default_size_hint: 1, None
|
||||||
|
size_hint_y: None
|
||||||
|
height: self.minimum_height
|
||||||
|
orientation: 'vertical'
|
||||||
|
spacing: dp(3)
|
23
setup.py
23
setup.py
|
@ -60,8 +60,7 @@ scripts = {"LttPClient.py": "ArchipelagoLttPClient",
|
||||||
"MultiMystery.py": "ArchipelagoMultiMystery",
|
"MultiMystery.py": "ArchipelagoMultiMystery",
|
||||||
"MultiServer.py": "ArchipelagoServer",
|
"MultiServer.py": "ArchipelagoServer",
|
||||||
"Mystery.py": "ArchipelagoMystery",
|
"Mystery.py": "ArchipelagoMystery",
|
||||||
"LttPAdjuster.py": "ArchipelagoLttPAdjuster",
|
"LttPAdjuster.py": "ArchipelagoLttPAdjuster"}
|
||||||
"FactorioClient.py": "ArchipelagoFactorioClient"}
|
|
||||||
|
|
||||||
exes = []
|
exes = []
|
||||||
|
|
||||||
|
@ -153,22 +152,14 @@ print("Outputting Factorio Client to: " + sbuildfolder)
|
||||||
|
|
||||||
os.makedirs(buildfolder, exist_ok=True)
|
os.makedirs(buildfolder, exist_ok=True)
|
||||||
|
|
||||||
scripts = {"FactorioClient.py": "ArchipelagoConsoleFactorioClient"}
|
|
||||||
|
|
||||||
exes = []
|
exes = [
|
||||||
|
cx_Freeze.Executable(
|
||||||
for script, scriptname in scripts.items():
|
script="FactorioClient.py",
|
||||||
exes.append(cx_Freeze.Executable(
|
target_name="ArchipelagoFactorioClient" + ("" if sys.platform == "linux" else ".exe"),
|
||||||
script=script,
|
|
||||||
target_name=scriptname + ("" if sys.platform == "linux" else ".exe"),
|
|
||||||
icon=icon,
|
icon=icon,
|
||||||
))
|
base="Win32GUI" if sys.platform == "win32" else None
|
||||||
exes.append(cx_Freeze.Executable(
|
)]
|
||||||
script="FactorioClientGUI.py",
|
|
||||||
target_name="ArchipelagoGraphicalFactorioClient" + ("" if sys.platform == "linux" else ".exe"),
|
|
||||||
icon=icon,
|
|
||||||
base="Win32GUI"
|
|
||||||
))
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ from worlds.alttp.Text import KingsReturn_texts, Sanctuary_texts, Kakariko_texts
|
||||||
DeathMountain_texts, \
|
DeathMountain_texts, \
|
||||||
LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts, Lumberjacks_texts, \
|
LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts, Lumberjacks_texts, \
|
||||||
SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names
|
SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names
|
||||||
from Utils import output_path, local_path, int16_as_bytes, int32_as_bytes, snes_to_pc, is_bundled
|
from Utils import output_path, local_path, int16_as_bytes, int32_as_bytes, snes_to_pc, is_frozen
|
||||||
from worlds.alttp.Items import ItemFactory, item_table
|
from worlds.alttp.Items import ItemFactory, item_table
|
||||||
from worlds.alttp.EntranceShuffle import door_addresses
|
from worlds.alttp.EntranceShuffle import door_addresses
|
||||||
import Patch
|
import Patch
|
||||||
|
@ -1843,7 +1843,7 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr
|
||||||
option_name: True
|
option_name: True
|
||||||
}
|
}
|
||||||
|
|
||||||
data_dir = local_path("data") if is_bundled() else None
|
data_dir = local_path("data") if is_frozen() else None
|
||||||
offsets_array = build_offset_collections(options, data_dir)
|
offsets_array = build_offset_collections(options, data_dir)
|
||||||
restore_maseya_colors(rom, offsets_array)
|
restore_maseya_colors(rom, offsets_array)
|
||||||
if mode == 'default':
|
if mode == 'default':
|
||||||
|
|
|
@ -11,7 +11,8 @@ def set_rules(world):
|
||||||
apply_or_ruleset(world.world, world.player, logicset)
|
apply_or_ruleset(world.world, world.player, logicset)
|
||||||
|
|
||||||
|
|
||||||
tautology = lambda state: True
|
def tautology(state):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def add_or_rule_check_first(world, location: str, player: int, conditionsets):
|
def add_or_rule_check_first(world, location: str, player: int, conditionsets):
|
||||||
|
|
Loading…
Reference in New Issue