Send AP text into Factorio worlds
This commit is contained in:
		
							parent
							
								
									a995627e98
								
							
						
					
					
						commit
						ee30914b2c
					
				| 
						 | 
				
			
			@ -129,7 +129,7 @@ class CommonContext():
 | 
			
		|||
        self.input_requests = 0
 | 
			
		||||
 | 
			
		||||
        # game state
 | 
			
		||||
        self.player_names: typing.Dict[int: str] = {}
 | 
			
		||||
        self.player_names: typing.Dict[int: str] = {0: "Server"}
 | 
			
		||||
        self.exit_event = asyncio.Event()
 | 
			
		||||
        self.watcher_event = asyncio.Event()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -195,6 +195,7 @@ class CommonContext():
 | 
			
		|||
 | 
			
		||||
    def consume_players_package(self, package: typing.List[tuple]):
 | 
			
		||||
        self.player_names = {slot: name for team, slot, name, orig_name in package if self.team == team}
 | 
			
		||||
        self.player_names[0] = "Server"
 | 
			
		||||
 | 
			
		||||
    def event_invalid_slot(self):
 | 
			
		||||
        raise Exception('Invalid Slot; please verify that you have connected to the correct world.')
 | 
			
		||||
| 
						 | 
				
			
			@ -213,6 +214,14 @@ class CommonContext():
 | 
			
		|||
        await self.disconnect()
 | 
			
		||||
        self.server_task = asyncio.create_task(server_loop(self, address))
 | 
			
		||||
 | 
			
		||||
    def on_print(self, args: dict):
 | 
			
		||||
        logger.info(args["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.
 | 
			
		||||
        logger.info(self.jsontotextparser(args["data"]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def server_loop(ctx: CommonContext, address=None):
 | 
			
		||||
    ui_node = getattr(ctx, "ui_node", None)
 | 
			
		||||
| 
						 | 
				
			
			@ -394,12 +403,10 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
 | 
			
		|||
            ctx.hint_points = args['hint_points']
 | 
			
		||||
 | 
			
		||||
    elif cmd == 'Print':
 | 
			
		||||
        logger.info(args["text"])
 | 
			
		||||
        ctx.on_print(args)
 | 
			
		||||
 | 
			
		||||
    elif cmd == 'PrintJSON':
 | 
			
		||||
        if not ctx.found_items and args.get("type", None) == "ItemSend" and args["receiving"] == args["sending"]:
 | 
			
		||||
            pass  # don't want info on other player's local pickups.
 | 
			
		||||
        logger.info(ctx.jsontotextparser(args["data"]))
 | 
			
		||||
        ctx.on_print_json(args)
 | 
			
		||||
 | 
			
		||||
    elif cmd == 'InvalidArguments':
 | 
			
		||||
        logger.warning(f"Invalid Arguments: {args['text']}")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,16 +2,18 @@ import os
 | 
			
		|||
import logging
 | 
			
		||||
import json
 | 
			
		||||
import string
 | 
			
		||||
import copy
 | 
			
		||||
from concurrent.futures import ThreadPoolExecutor
 | 
			
		||||
 | 
			
		||||
import colorama
 | 
			
		||||
import asyncio
 | 
			
		||||
from queue import Queue, Empty
 | 
			
		||||
from CommonClient import CommonContext, server_loop, console_loop, ClientCommandProcessor
 | 
			
		||||
from CommonClient import CommonContext, server_loop, console_loop, ClientCommandProcessor, logger
 | 
			
		||||
from MultiServer import mark_raw
 | 
			
		||||
 | 
			
		||||
import Utils
 | 
			
		||||
import random
 | 
			
		||||
from NetUtils import RawJSONtoTextParser, NetworkItem
 | 
			
		||||
 | 
			
		||||
from worlds.factorio.Technologies import lookup_id_to_name
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +63,7 @@ class FactorioContext(CommonContext):
 | 
			
		|||
        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:
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +78,18 @@ class FactorioContext(CommonContext):
 | 
			
		|||
                               'uuid': Utils.get_unique_identifier(), 'game': "Factorio"
 | 
			
		||||
                               }])
 | 
			
		||||
 | 
			
		||||
    def on_print(self, args: dict):
 | 
			
		||||
        logger.info(args["text"])
 | 
			
		||||
        if self.rcon_client:
 | 
			
		||||
            self.rcon_client.send_command(f"Archipelago: {args['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.
 | 
			
		||||
        copy_data = copy.deepcopy(args["data"]) # jsontotextparser is destructive currently
 | 
			
		||||
        logger.info(self.jsontotextparser(args["data"]))
 | 
			
		||||
        if self.rcon_client:
 | 
			
		||||
            self.rcon_client.send_command(f"Archipelago: {self.raw_json_text_parser(copy_data)}")
 | 
			
		||||
 | 
			
		||||
async def game_watcher(ctx: FactorioContext):
 | 
			
		||||
    bridge_logger = logging.getLogger("FactorioWatcher")
 | 
			
		||||
| 
						 | 
				
			
			@ -146,8 +161,9 @@ async def factorio_server_watcher(ctx: FactorioContext):
 | 
			
		|||
                    ctx.rcon_client.send_command("/sc game.print('Starting Archipelago Bridge')")
 | 
			
		||||
            if ctx.rcon_client:
 | 
			
		||||
                while ctx.send_index < len(ctx.items_received):
 | 
			
		||||
                    item_id = ctx.items_received[ctx.send_index].item
 | 
			
		||||
                    player_name = ctx.player_names[ctx.send_index].player
 | 
			
		||||
                    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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								NetUtils.py
								
								
								
								
							
							
						
						
									
										19
									
								
								NetUtils.py
								
								
								
								
							| 
						 | 
				
			
			@ -9,6 +9,7 @@ import websockets
 | 
			
		|||
 | 
			
		||||
from Utils import Version
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JSONMessagePart(typing.TypedDict, total=False):
 | 
			
		||||
    text: str
 | 
			
		||||
    # optional
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +19,6 @@ class JSONMessagePart(typing.TypedDict, total=False):
 | 
			
		|||
    found: bool
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClientStatus(enum.IntEnum):
 | 
			
		||||
    CLIENT_UNKNOWN = 0
 | 
			
		||||
    CLIENT_CONNECTED = 5
 | 
			
		||||
| 
						 | 
				
			
			@ -61,10 +61,12 @@ _encode = JSONEncoder(
 | 
			
		|||
def encode(obj):
 | 
			
		||||
    return _encode(_scan_for_TypedTuples(obj))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_any_version(data: dict) -> Version:
 | 
			
		||||
    data = {key.lower(): value for key, value in data.items()}  # .NET version classes have capitalized keys
 | 
			
		||||
    return Version(int(data["major"]), int(data["minor"]), int(data["build"]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
whitelist = {"NetworkPlayer": NetworkPlayer,
 | 
			
		||||
             "NetworkItem": NetworkItem,
 | 
			
		||||
             }
 | 
			
		||||
| 
						 | 
				
			
			@ -73,6 +75,7 @@ custom_hooks = {
 | 
			
		|||
    "Version": get_any_version
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _object_hook(o: typing.Any) -> typing.Any:
 | 
			
		||||
    if isinstance(o, dict):
 | 
			
		||||
        hook = custom_hooks.get(o.get("class", None), None)
 | 
			
		||||
| 
						 | 
				
			
			@ -151,11 +154,16 @@ class HandlerMeta(type):
 | 
			
		|||
        handlers = attrs["handlers"] = {}
 | 
			
		||||
        trigger: str = "_handle_"
 | 
			
		||||
        for base in bases:
 | 
			
		||||
            handlers.update(base.commands)
 | 
			
		||||
            handlers.update(base.handlers)
 | 
			
		||||
        handlers.update({handler_name[len(trigger):]: method for handler_name, method in attrs.items() if
 | 
			
		||||
                         handler_name.startswith(trigger)})
 | 
			
		||||
 | 
			
		||||
        orig_init = attrs.get('__init__', None)
 | 
			
		||||
        if not orig_init:
 | 
			
		||||
            for base in bases:
 | 
			
		||||
                orig_init = getattr(base, '__init__', None)
 | 
			
		||||
                if orig_init:
 | 
			
		||||
                    break
 | 
			
		||||
 | 
			
		||||
        def __init__(self, *args, **kwargs):
 | 
			
		||||
            # turn functions into bound methods
 | 
			
		||||
| 
						 | 
				
			
			@ -167,6 +175,7 @@ class HandlerMeta(type):
 | 
			
		|||
        attrs['__init__'] = __init__
 | 
			
		||||
        return super(HandlerMeta, mcs).__new__(mcs, name, bases, attrs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JSONTypes(str, enum.Enum):
 | 
			
		||||
    color = "color"
 | 
			
		||||
    text = "text"
 | 
			
		||||
| 
						 | 
				
			
			@ -178,6 +187,7 @@ class JSONTypes(str, enum.Enum):
 | 
			
		|||
    location_id = "location_id"
 | 
			
		||||
    entrance_name = "entrance_name"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JSONtoTextParser(metaclass=HandlerMeta):
 | 
			
		||||
    def __init__(self, ctx):
 | 
			
		||||
        self.ctx = ctx
 | 
			
		||||
| 
						 | 
				
			
			@ -236,6 +246,11 @@ class JSONtoTextParser(metaclass=HandlerMeta):
 | 
			
		|||
        return self._handle_color(node)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RawJSONtoTextParser(JSONtoTextParser):
 | 
			
		||||
    def _handle_color(self, node: JSONMessagePart):
 | 
			
		||||
        return self._handle_text(node)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
color_codes = {'reset': 0, 'bold': 1, 'underline': 4, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34,
 | 
			
		||||
               'magenta': 35, 'cyan': 36, 'white': 37, 'black_bg': 40, 'red_bg': 41, 'green_bg': 42, 'yellow_bg': 43,
 | 
			
		||||
               'blue_bg': 44, 'purple_bg': 45, 'cyan_bg': 46, 'white_bg': 47}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue