FactorioClient: Read Bridge file after a server log indicates that the file was written
This commit is contained in:
		
							parent
							
								
									0175c8ab8a
								
							
						
					
					
						commit
						252bb69808
					
				| 
						 | 
					@ -65,6 +65,7 @@ class FactorioContext(CommonContext):
 | 
				
			||||||
        super(FactorioContext, self).__init__(*args, **kwargs)
 | 
					        super(FactorioContext, self).__init__(*args, **kwargs)
 | 
				
			||||||
        self.send_index = 0
 | 
					        self.send_index = 0
 | 
				
			||||||
        self.rcon_client = None
 | 
					        self.rcon_client = None
 | 
				
			||||||
 | 
					        self.awaiting_bridge = False
 | 
				
			||||||
        self.raw_json_text_parser = RawJSONtoTextParser(self)
 | 
					        self.raw_json_text_parser = RawJSONtoTextParser(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def server_auth(self, password_requested):
 | 
					    async def server_auth(self, password_requested):
 | 
				
			||||||
| 
						 | 
					@ -86,10 +87,10 @@ class FactorioContext(CommonContext):
 | 
				
			||||||
    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"]:
 | 
					        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.
 | 
					            pass  # don't want info on other player's local pickups.
 | 
				
			||||||
        copy_data = copy.deepcopy(args["data"])  # jsontotextparser is destructive currently
 | 
					        text = self.raw_json_text_parser(args["data"])
 | 
				
			||||||
        logger.info(self.jsontotextparser(args["data"]))
 | 
					        logger.info(text)
 | 
				
			||||||
        if self.rcon_client:
 | 
					        if self.rcon_client:
 | 
				
			||||||
            cleaned_text = self.raw_json_text_parser(copy_data).replace('"', '')
 | 
					            cleaned_text = text.replace('"', '')
 | 
				
			||||||
            self.rcon_client.send_command(f"/sc game.print(\"Archipelago: {cleaned_text}\")")
 | 
					            self.rcon_client.send_command(f"/sc game.print(\"Archipelago: {cleaned_text}\")")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def game_watcher(ctx: FactorioContext, bridge_file: str):
 | 
					async def game_watcher(ctx: FactorioContext, bridge_file: str):
 | 
				
			||||||
| 
						 | 
					@ -97,27 +98,29 @@ async def game_watcher(ctx: FactorioContext, bridge_file: str):
 | 
				
			||||||
    from worlds.factorio.Technologies import lookup_id_to_name
 | 
					    from worlds.factorio.Technologies import lookup_id_to_name
 | 
				
			||||||
    bridge_counter = 0
 | 
					    bridge_counter = 0
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        while 1:
 | 
					        while not ctx.exit_event.is_set():
 | 
				
			||||||
            if os.path.exists(bridge_file):
 | 
					            if os.path.exists(bridge_file):
 | 
				
			||||||
                bridge_logger.info("Found Factorio Bridge file.")
 | 
					                bridge_logger.info("Found Factorio Bridge file.")
 | 
				
			||||||
                while 1:
 | 
					                while not ctx.exit_event.is_set():
 | 
				
			||||||
                    with open(bridge_file) as f:
 | 
					                    if ctx.awaiting_bridge:
 | 
				
			||||||
                        data = json.load(f)
 | 
					                        ctx.awaiting_bridge = False
 | 
				
			||||||
                        research_data = data["research_done"]
 | 
					                        with open(bridge_file) as f:
 | 
				
			||||||
                        research_data = {int(tech_name.split("-")[1]) for tech_name in research_data}
 | 
					                            data = json.load(f)
 | 
				
			||||||
                        victory = data["victory"]
 | 
					                            research_data = data["research_done"]
 | 
				
			||||||
                        ctx.auth = data["slot_name"]
 | 
					                            research_data = {int(tech_name.split("-")[1]) for tech_name in research_data}
 | 
				
			||||||
                        ctx.seed_name = data["seed_name"]
 | 
					                            victory = data["victory"]
 | 
				
			||||||
 | 
					                            ctx.auth = data["slot_name"]
 | 
				
			||||||
 | 
					                            ctx.seed_name = data["seed_name"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if not ctx.finished_game and victory:
 | 
					                        if not ctx.finished_game and victory:
 | 
				
			||||||
                        await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
 | 
					                            await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
 | 
				
			||||||
                        ctx.finished_game = True
 | 
					                            ctx.finished_game = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if ctx.locations_checked != research_data:
 | 
					                        if ctx.locations_checked != research_data:
 | 
				
			||||||
                        bridge_logger.info(f"New researches done: "
 | 
					                            bridge_logger.info(f"New researches done: "
 | 
				
			||||||
                                           f"{[lookup_id_to_name[rid] for rid in research_data - ctx.locations_checked]}")
 | 
					                                               f"{[lookup_id_to_name[rid] for rid in research_data - ctx.locations_checked]}")
 | 
				
			||||||
                        ctx.locations_checked = research_data
 | 
					                            ctx.locations_checked = research_data
 | 
				
			||||||
                        await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": tuple(research_data)}])
 | 
					                            await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": tuple(research_data)}])
 | 
				
			||||||
                    await asyncio.sleep(1)
 | 
					                    await asyncio.sleep(1)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                bridge_counter += 1
 | 
					                bridge_counter += 1
 | 
				
			||||||
| 
						 | 
					@ -160,8 +163,9 @@ async def factorio_server_watcher(ctx: FactorioContext):
 | 
				
			||||||
    stream_factorio_output(factorio_process.stdout, factorio_queue)
 | 
					    stream_factorio_output(factorio_process.stdout, factorio_queue)
 | 
				
			||||||
    stream_factorio_output(factorio_process.stderr, factorio_queue)
 | 
					    stream_factorio_output(factorio_process.stderr, factorio_queue)
 | 
				
			||||||
    script_folder = None
 | 
					    script_folder = None
 | 
				
			||||||
 | 
					    progression_watcher = None
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        while 1:
 | 
					        while not ctx.exit_event.is_set():
 | 
				
			||||||
            while not factorio_queue.empty():
 | 
					            while not factorio_queue.empty():
 | 
				
			||||||
                msg = factorio_queue.get()
 | 
					                msg = factorio_queue.get()
 | 
				
			||||||
                factorio_server_logger.info(msg)
 | 
					                factorio_server_logger.info(msg)
 | 
				
			||||||
| 
						 | 
					@ -177,7 +181,10 @@ async def factorio_server_watcher(ctx: FactorioContext):
 | 
				
			||||||
                    if os.path.exists(bridge_file):
 | 
					                    if os.path.exists(bridge_file):
 | 
				
			||||||
                        os.remove(bridge_file)
 | 
					                        os.remove(bridge_file)
 | 
				
			||||||
                    logging.info(f"Bridge File Path: {bridge_file}")
 | 
					                    logging.info(f"Bridge File Path: {bridge_file}")
 | 
				
			||||||
                    asyncio.create_task(game_watcher(ctx, bridge_file), name="FactorioProgressionWatcher")
 | 
					                    progression_watcher= asyncio.create_task(
 | 
				
			||||||
 | 
					                        game_watcher(ctx, bridge_file), name="FactorioProgressionWatcher")
 | 
				
			||||||
 | 
					                if not ctx.awaiting_bridge and "Archipelago Bridge File written for game tick " in msg:
 | 
				
			||||||
 | 
					                    ctx.awaiting_bridge = True
 | 
				
			||||||
            if ctx.rcon_client:
 | 
					            if ctx.rcon_client:
 | 
				
			||||||
                while ctx.send_index < len(ctx.items_received):
 | 
					                while ctx.send_index < len(ctx.items_received):
 | 
				
			||||||
                    transfer_item: NetworkItem = ctx.items_received[ctx.send_index]
 | 
					                    transfer_item: NetworkItem = ctx.items_received[ctx.send_index]
 | 
				
			||||||
| 
						 | 
					@ -192,10 +199,16 @@ async def factorio_server_watcher(ctx: FactorioContext):
 | 
				
			||||||
                    ctx.send_index += 1
 | 
					                    ctx.send_index += 1
 | 
				
			||||||
            await asyncio.sleep(1)
 | 
					            await asyncio.sleep(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    except Exception as e:
 | 
					    except Exception as e:
 | 
				
			||||||
        logging.exception(e)
 | 
					        logging.exception(e)
 | 
				
			||||||
        logging.error("Aborted Factorio Server Bridge")
 | 
					        logging.error("Aborted Factorio Server Bridge")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    finally:
 | 
				
			||||||
 | 
					        factorio_process.terminate()
 | 
				
			||||||
 | 
					        if progression_watcher:
 | 
				
			||||||
 | 
					            await progression_watcher
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def main():
 | 
					async def main():
 | 
				
			||||||
    ctx = FactorioContext(None, None, True)
 | 
					    ctx = FactorioContext(None, None, True)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,211 +3,15 @@ import logging
 | 
				
			||||||
os.makedirs("logs", exist_ok=True)
 | 
					os.makedirs("logs", exist_ok=True)
 | 
				
			||||||
logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO)
 | 
					logging.basicConfig(format='[%(name)s]: %(message)s', level=logging.INFO)
 | 
				
			||||||
logging.getLogger().addHandler(logging.FileHandler(os.path.join("logs", "FactorioClient.txt"), "w"))
 | 
					logging.getLogger().addHandler(logging.FileHandler(os.path.join("logs", "FactorioClient.txt"), "w"))
 | 
				
			||||||
import json
 | 
					 | 
				
			||||||
import string
 | 
					 | 
				
			||||||
os.environ["KIVY_NO_CONSOLELOG"] = "1"
 | 
					os.environ["KIVY_NO_CONSOLELOG"] = "1"
 | 
				
			||||||
os.environ["KIVY_NO_FILELOG"] = "1"
 | 
					os.environ["KIVY_NO_FILELOG"] = "1"
 | 
				
			||||||
os.environ["KIVY_NO_ARGS"] = "1"
 | 
					os.environ["KIVY_NO_ARGS"] = "1"
 | 
				
			||||||
from concurrent.futures import ThreadPoolExecutor
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import asyncio
 | 
					import asyncio
 | 
				
			||||||
from queue import Queue
 | 
					from CommonClient import server_loop, logger
 | 
				
			||||||
from CommonClient import CommonContext, server_loop, ClientCommandProcessor, logger
 | 
					from FactorioClient import FactorioContext, factorio_server_watcher
 | 
				
			||||||
from MultiServer import mark_raw
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Utils
 | 
					 | 
				
			||||||
import random
 | 
					 | 
				
			||||||
from NetUtils import RawJSONtoTextParser, NetworkItem, ClientStatus
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from worlds.factorio.Technologies import lookup_id_to_name
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
rcon_port = 24242
 | 
					 | 
				
			||||||
rcon_password = ''.join(random.choice(string.ascii_letters) for x in range(32))
 | 
					 | 
				
			||||||
save_name = "Archipelago"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
server_args = (save_name, "--rcon-port", rcon_port, "--rcon-password", rcon_password, *sys.argv[1:])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
threadpool = ThreadPoolExecutor(10)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class FactorioCommandProcessor(ClientCommandProcessor):
 | 
					 | 
				
			||||||
    @mark_raw
 | 
					 | 
				
			||||||
    def _cmd_factorio(self, text: str) -> bool:
 | 
					 | 
				
			||||||
        """Send the following command to the bound Factorio Server."""
 | 
					 | 
				
			||||||
        if self.ctx.rcon_client:
 | 
					 | 
				
			||||||
            result = self.ctx.rcon_client.send_command(text)
 | 
					 | 
				
			||||||
            if result:
 | 
					 | 
				
			||||||
                self.output(result)
 | 
					 | 
				
			||||||
            return True
 | 
					 | 
				
			||||||
        return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _cmd_connect(self, address: str = "") -> bool:
 | 
					 | 
				
			||||||
        """Connect to a MultiWorld Server"""
 | 
					 | 
				
			||||||
        if not self.ctx.auth:
 | 
					 | 
				
			||||||
            self.output("Cannot connect to a server with unknown own identity, bridge to Factorio first.")
 | 
					 | 
				
			||||||
        return super(FactorioCommandProcessor, self)._cmd_connect(address)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class FactorioContext(CommonContext):
 | 
					 | 
				
			||||||
    command_processor = FactorioCommandProcessor
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, *args, **kwargs):
 | 
					 | 
				
			||||||
        super(FactorioContext, self).__init__(*args, **kwargs)
 | 
					 | 
				
			||||||
        self.send_index = 0
 | 
					 | 
				
			||||||
        self.rcon_client = None
 | 
					 | 
				
			||||||
        self.raw_json_text_parser = RawJSONtoTextParser(self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def server_auth(self, password_requested):
 | 
					 | 
				
			||||||
        if password_requested and not self.password:
 | 
					 | 
				
			||||||
            await super(FactorioContext, self).server_auth(password_requested)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await self.send_msgs([{"cmd": 'Connect',
 | 
					 | 
				
			||||||
                               'password': self.password, 'name': self.auth, 'version': Utils._version_tuple,
 | 
					 | 
				
			||||||
                               'tags': ['AP'],
 | 
					 | 
				
			||||||
                               'uuid': Utils.get_unique_identifier(), 'game': "Factorio"
 | 
					 | 
				
			||||||
                               }])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def on_print(self, args: dict):
 | 
					 | 
				
			||||||
        logger.info(args["text"])
 | 
					 | 
				
			||||||
        if self.rcon_client:
 | 
					 | 
				
			||||||
            cleaned_text = args['text'].replace('"', '')
 | 
					 | 
				
			||||||
            self.rcon_client.send_command(f"/sc game.print(\"Archipelago: {cleaned_text}\")")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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(args["data"])
 | 
					 | 
				
			||||||
        logger.info(text)
 | 
					 | 
				
			||||||
        if self.rcon_client:
 | 
					 | 
				
			||||||
            cleaned_text = text.replace('"', '')
 | 
					 | 
				
			||||||
            self.rcon_client.send_command(f"/sc game.print(\"Archipelago: {cleaned_text}\")")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async def game_watcher(ctx: FactorioContext, bridge_file: str):
 | 
					 | 
				
			||||||
    bridge_logger = logging.getLogger("FactorioWatcher")
 | 
					 | 
				
			||||||
    from worlds.factorio.Technologies import lookup_id_to_name
 | 
					 | 
				
			||||||
    bridge_counter = 0
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        while not ctx.exit_event.is_set():
 | 
					 | 
				
			||||||
            if os.path.exists(bridge_file):
 | 
					 | 
				
			||||||
                bridge_logger.info("Found Factorio Bridge file.")
 | 
					 | 
				
			||||||
                while not ctx.exit_event.is_set():
 | 
					 | 
				
			||||||
                    with open(bridge_file) as f:
 | 
					 | 
				
			||||||
                        data = json.load(f)
 | 
					 | 
				
			||||||
                        research_data = data["research_done"]
 | 
					 | 
				
			||||||
                        research_data = {int(tech_name.split("-")[1]) for tech_name in research_data}
 | 
					 | 
				
			||||||
                        victory = data["victory"]
 | 
					 | 
				
			||||||
                        ctx.auth = data["slot_name"]
 | 
					 | 
				
			||||||
                        ctx.seed_name = data["seed_name"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if not ctx.finished_game and victory:
 | 
					 | 
				
			||||||
                        await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
 | 
					 | 
				
			||||||
                        ctx.finished_game = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if ctx.locations_checked != research_data:
 | 
					 | 
				
			||||||
                        bridge_logger.info(f"New researches done: "
 | 
					 | 
				
			||||||
                                           f"{[lookup_id_to_name[rid] for rid in research_data - ctx.locations_checked]}")
 | 
					 | 
				
			||||||
                        ctx.locations_checked = research_data
 | 
					 | 
				
			||||||
                        await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": tuple(research_data)}])
 | 
					 | 
				
			||||||
                    await asyncio.sleep(1)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                bridge_counter += 1
 | 
					 | 
				
			||||||
                if bridge_counter >= 60:
 | 
					 | 
				
			||||||
                    bridge_logger.info(
 | 
					 | 
				
			||||||
                        "Did not find Factorio Bridge file, "
 | 
					 | 
				
			||||||
                        "waiting for mod to run, which requires the server to run, "
 | 
					 | 
				
			||||||
                        "which requires a player to be connected.")
 | 
					 | 
				
			||||||
                    bridge_counter = 0
 | 
					 | 
				
			||||||
                await asyncio.sleep(1)
 | 
					 | 
				
			||||||
    except Exception as e:
 | 
					 | 
				
			||||||
        logging.exception(e)
 | 
					 | 
				
			||||||
        logging.error("Aborted Factorio Server Bridge")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def stream_factorio_output(pipe, queue):
 | 
					 | 
				
			||||||
    def queuer():
 | 
					 | 
				
			||||||
        while 1:
 | 
					 | 
				
			||||||
            text = pipe.readline().strip()
 | 
					 | 
				
			||||||
            if text:
 | 
					 | 
				
			||||||
                queue.put_nowait(text)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    from threading import Thread
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    thread = Thread(target=queuer, name="Factorio Output Queue", daemon=True)
 | 
					 | 
				
			||||||
    thread.start()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async def factorio_server_watcher(ctx: FactorioContext):
 | 
					 | 
				
			||||||
    import subprocess
 | 
					 | 
				
			||||||
    import factorio_rcon
 | 
					 | 
				
			||||||
    factorio_server_logger = logging.getLogger("FactorioServer")
 | 
					 | 
				
			||||||
    factorio_process = subprocess.Popen((executable, "--start-server", *(str(elem) for elem in server_args)),
 | 
					 | 
				
			||||||
                                        stderr=subprocess.PIPE,
 | 
					 | 
				
			||||||
                                        stdout=subprocess.PIPE,
 | 
					 | 
				
			||||||
                                        stdin=subprocess.DEVNULL,
 | 
					 | 
				
			||||||
                                        encoding="utf-8")
 | 
					 | 
				
			||||||
    factorio_server_logger.info("Started Factorio Server")
 | 
					 | 
				
			||||||
    factorio_queue = Queue()
 | 
					 | 
				
			||||||
    stream_factorio_output(factorio_process.stdout, factorio_queue)
 | 
					 | 
				
			||||||
    stream_factorio_output(factorio_process.stderr, factorio_queue)
 | 
					 | 
				
			||||||
    script_folder = None
 | 
					 | 
				
			||||||
    progression_watcher = None
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        while not ctx.exit_event.is_set():
 | 
					 | 
				
			||||||
            while not factorio_queue.empty():
 | 
					 | 
				
			||||||
                msg = factorio_queue.get()
 | 
					 | 
				
			||||||
                factorio_server_logger.info(msg)
 | 
					 | 
				
			||||||
                if not ctx.rcon_client and "Starting RCON interface at IP ADDR:" in msg:
 | 
					 | 
				
			||||||
                    ctx.rcon_client = factorio_rcon.RCONClient("localhost", rcon_port, rcon_password)
 | 
					 | 
				
			||||||
                    # trigger lua interface confirmation
 | 
					 | 
				
			||||||
                    ctx.rcon_client.send_command("/sc game.print('Starting Archipelago Bridge')")
 | 
					 | 
				
			||||||
                    ctx.rcon_client.send_command("/sc game.print('Starting Archipelago Bridge')")
 | 
					 | 
				
			||||||
                    ctx.rcon_client.send_command("/ap-sync")
 | 
					 | 
				
			||||||
                if not script_folder and "Write data path:" in msg:
 | 
					 | 
				
			||||||
                    script_folder = msg.split("Write data path: ", 1)[1].split("[", 1)[0].strip()
 | 
					 | 
				
			||||||
                    bridge_file = os.path.join(script_folder, "script-output", "ap_bridge.json")
 | 
					 | 
				
			||||||
                    if os.path.exists(bridge_file):
 | 
					 | 
				
			||||||
                        os.remove(bridge_file)
 | 
					 | 
				
			||||||
                    logging.info(f"Bridge File Path: {bridge_file}")
 | 
					 | 
				
			||||||
                    progression_watcher= asyncio.create_task(
 | 
					 | 
				
			||||||
                        game_watcher(ctx, bridge_file), name="FactorioProgressionWatcher")
 | 
					 | 
				
			||||||
            if ctx.rcon_client:
 | 
					 | 
				
			||||||
                while ctx.send_index < len(ctx.items_received):
 | 
					 | 
				
			||||||
                    transfer_item: NetworkItem = ctx.items_received[ctx.send_index]
 | 
					 | 
				
			||||||
                    item_id = transfer_item.item
 | 
					 | 
				
			||||||
                    player_name = ctx.player_names[transfer_item.player]
 | 
					 | 
				
			||||||
                    if item_id not in lookup_id_to_name:
 | 
					 | 
				
			||||||
                        logging.error(f"Cannot send unknown item ID: {item_id}")
 | 
					 | 
				
			||||||
                    else:
 | 
					 | 
				
			||||||
                        item_name = lookup_id_to_name[item_id]
 | 
					 | 
				
			||||||
                        factorio_server_logger.info(f"Sending {item_name} to Nauvis from {player_name}.")
 | 
					 | 
				
			||||||
                        ctx.rcon_client.send_command(f'/ap-get-technology {item_name} {player_name}')
 | 
					 | 
				
			||||||
                    ctx.send_index += 1
 | 
					 | 
				
			||||||
            await asyncio.sleep(1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    except Exception as e:
 | 
					 | 
				
			||||||
        logging.exception(e)
 | 
					 | 
				
			||||||
        logging.error("Aborted Factorio Server Bridge")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    finally:
 | 
					 | 
				
			||||||
        factorio_process.terminate()
 | 
					 | 
				
			||||||
        if progression_watcher:
 | 
					 | 
				
			||||||
            await progression_watcher
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def main():
 | 
					async def main():
 | 
				
			||||||
    ctx = FactorioContext(None, None, True)
 | 
					    ctx = FactorioContext(None, None, True)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								Main.py
								
								
								
								
							
							
						
						
									
										5
									
								
								Main.py
								
								
								
								
							| 
						 | 
					@ -502,7 +502,10 @@ def main(args, seed=None):
 | 
				
			||||||
        minimum_versions = {"server": (0, 1, 1), "clients": client_versions}
 | 
					        minimum_versions = {"server": (0, 1, 1), "clients": client_versions}
 | 
				
			||||||
        games = {}
 | 
					        games = {}
 | 
				
			||||||
        for slot in world.player_ids:
 | 
					        for slot in world.player_ids:
 | 
				
			||||||
            client_versions[slot] = (0, 0, 3)
 | 
					            if world.game[slot] == "Factorio":
 | 
				
			||||||
 | 
					                client_versions[slot] = (1, 1, 2)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                client_versions[slot] = (0, 0, 3)
 | 
				
			||||||
            games[slot] = world.game[slot]
 | 
					            games[slot] = world.game[slot]
 | 
				
			||||||
        connect_names = {base64.b64encode(rom_name).decode(): (team, slot) for
 | 
					        connect_names = {base64.b64encode(rom_name).decode(): (team, slot) for
 | 
				
			||||||
                          slot, team, rom_name in rom_names}
 | 
					                          slot, team, rom_name in rom_names}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								Utils.py
								
								
								
								
							
							
						
						
									
										2
									
								
								Utils.py
								
								
								
								
							| 
						 | 
					@ -12,7 +12,7 @@ class Version(typing.NamedTuple):
 | 
				
			||||||
    minor: int
 | 
					    minor: int
 | 
				
			||||||
    build: int
 | 
					    build: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__version__ = "0.1.1"
 | 
					__version__ = "0.1.2"
 | 
				
			||||||
_version_tuple = tuplize_version(__version__)
 | 
					_version_tuple = tuplize_version(__version__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import builtins
 | 
					import builtins
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,7 +134,7 @@ end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- for testing
 | 
					-- for testing
 | 
				
			||||||
script.on_event(defines.events.on_tick, function(event)
 | 
					script.on_event(defines.events.on_tick, function(event)
 | 
				
			||||||
    if event.tick%600 == 300 then
 | 
					    if event.tick%3600 == 300 then
 | 
				
			||||||
        dumpInfo(game.forces["player"])
 | 
					        dumpInfo(game.forces["player"])
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
| 
						 | 
					@ -186,6 +186,7 @@ function dumpInfo(force)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
    game.write_file("ap_bridge.json", game.table_to_json(data_collection), false, 0)
 | 
					    game.write_file("ap_bridge.json", game.table_to_json(data_collection), false, 0)
 | 
				
			||||||
 | 
					    log("Archipelago Bridge File written for game tick ".. game.tick .. ".")
 | 
				
			||||||
    -- game.write_file("research_done.json", game.table_to_json(data_collection), false, 0)
 | 
					    -- game.write_file("research_done.json", game.table_to_json(data_collection), false, 0)
 | 
				
			||||||
    -- game.print("Sent progress to Archipelago.")
 | 
					    -- game.print("Sent progress to Archipelago.")
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue