Clients: centralize UI and input behaviour
This commit is contained in:
parent
dc10421531
commit
d1eda38745
|
@ -119,9 +119,11 @@ class CommonContext():
|
|||
starting_reconnect_delay: int = 5
|
||||
current_reconnect_delay: int = starting_reconnect_delay
|
||||
command_processor: int = ClientCommandProcessor
|
||||
game = None
|
||||
game: typing.Optional[str] = None
|
||||
ui = None
|
||||
keep_alive_task = None
|
||||
ui_task: typing.Optional[asyncio.Task] = None
|
||||
input_task: typing.Optional[asyncio.Task] = None
|
||||
keep_alive_task: typing.Optional[asyncio.Task] = None
|
||||
items_handling: typing.Optional[int] = None
|
||||
current_energy_link_value = 0 # to display in UI, gets set by server
|
||||
|
||||
|
@ -309,6 +311,10 @@ class CommonContext():
|
|||
self.input_queue.put_nowait(None)
|
||||
self.input_requests -= 1
|
||||
self.keep_alive_task.cancel()
|
||||
if self.ui_task:
|
||||
await self.ui_task
|
||||
if self.input_task:
|
||||
self.input_task.cancel()
|
||||
|
||||
# DeathLink hooks
|
||||
|
||||
|
@ -343,6 +349,27 @@ class CommonContext():
|
|||
if old_tags != self.tags and self.server and not self.server.socket.closed:
|
||||
await self.send_msgs([{"cmd": "ConnectUpdate", "tags": self.tags}])
|
||||
|
||||
def run_gui(self):
|
||||
"""Import kivy UI system and start running it as self.ui_task."""
|
||||
from kvui import GameManager
|
||||
|
||||
class TextManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
]
|
||||
base_title = "Archipelago Text Client"
|
||||
|
||||
self.ui = TextManager(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
|
||||
def run_cli(self):
|
||||
if sys.stdin:
|
||||
# steam overlay breaks when starting console_loop
|
||||
if 'gameoverlayrenderer' in os.environ.get('LD_PRELOAD', ''):
|
||||
logger.info("Skipping terminal input, due to conflicting Steam Overlay detected. Please use GUI only.")
|
||||
else:
|
||||
self.input_task = asyncio.create_task(console_loop(self), name="Input")
|
||||
|
||||
|
||||
async def keep_alive(ctx: CommonContext, seconds_between_checks=100):
|
||||
"""some ISPs/network configurations drop TCP connections if no payload is sent (ignore TCP-keep-alive)
|
||||
|
@ -565,7 +592,6 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
|
|||
|
||||
|
||||
async def console_loop(ctx: CommonContext):
|
||||
import sys
|
||||
commandprocessor = ctx.command_processor(ctx)
|
||||
queue = asyncio.Queue()
|
||||
stream_input(sys.stdin, queue)
|
||||
|
@ -620,26 +646,14 @@ if __name__ == '__main__':
|
|||
async def main(args):
|
||||
ctx = TextContext(args.connect, args.password)
|
||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="server loop")
|
||||
input_task = None
|
||||
steam_overlay = False
|
||||
|
||||
if gui_enabled:
|
||||
from kvui import TextManager
|
||||
ctx.ui = TextManager(ctx)
|
||||
ui_task = asyncio.create_task(ctx.ui.async_run(), name="UI")
|
||||
steam_overlay = 'gameoverlayrenderer' in os.environ.get('LD_PRELOAD', '')
|
||||
else:
|
||||
ui_task = None
|
||||
if sys.stdin and not steam_overlay: # steam overlay breaks when starting console_loop
|
||||
input_task = asyncio.create_task(console_loop(ctx), name="Input")
|
||||
ctx.run_gui()
|
||||
ctx.run_cli()
|
||||
|
||||
await ctx.exit_event.wait()
|
||||
|
||||
await ctx.shutdown()
|
||||
if ui_task:
|
||||
await ui_task
|
||||
|
||||
if input_task:
|
||||
input_task.cancel()
|
||||
|
||||
import colorama
|
||||
|
||||
|
@ -648,7 +662,5 @@ if __name__ == '__main__':
|
|||
args, rest = parser.parse_known_args()
|
||||
colorama.init()
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main(args))
|
||||
loop.close()
|
||||
asyncio.run(main(args))
|
||||
colorama.deinit()
|
||||
|
|
32
FF1Client.py
32
FF1Client.py
|
@ -102,6 +102,18 @@ class FF1Context(CommonContext):
|
|||
f"{receiving_player_name}"
|
||||
self._set_message(msg, item.item)
|
||||
|
||||
def run_gui(self):
|
||||
from kvui import GameManager
|
||||
|
||||
class FF1Manager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
]
|
||||
base_title = "Archipelago Final Fantasy 1 Client"
|
||||
|
||||
self.ui = FF1Manager(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
|
||||
|
||||
def get_payload(ctx: FF1Context):
|
||||
current_time = time.time()
|
||||
|
@ -232,14 +244,8 @@ if __name__ == '__main__':
|
|||
ctx = FF1Context(args.connect, args.password)
|
||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
|
||||
if gui_enabled:
|
||||
input_task = None
|
||||
from kvui import FF1Manager
|
||||
ctx.ui = FF1Manager(ctx)
|
||||
ui_task = asyncio.create_task(ctx.ui.async_run(), name="UI")
|
||||
else:
|
||||
input_task = asyncio.create_task(console_loop(ctx), name="Input")
|
||||
ui_task = None
|
||||
|
||||
ctx.run_gui()
|
||||
ctx.run_cli()
|
||||
ctx.nes_sync_task = asyncio.create_task(nes_sync_task(ctx), name="NES Sync")
|
||||
|
||||
await ctx.exit_event.wait()
|
||||
|
@ -250,12 +256,6 @@ if __name__ == '__main__':
|
|||
if ctx.nes_sync_task:
|
||||
await ctx.nes_sync_task
|
||||
|
||||
if ui_task:
|
||||
await ui_task
|
||||
|
||||
if input_task:
|
||||
input_task.cancel()
|
||||
|
||||
|
||||
import colorama
|
||||
|
||||
|
@ -263,7 +263,5 @@ if __name__ == '__main__':
|
|||
args, rest = parser.parse_known_args()
|
||||
colorama.init()
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main(args))
|
||||
loop.close()
|
||||
asyncio.run(main(args))
|
||||
colorama.deinit()
|
||||
|
|
|
@ -125,6 +125,20 @@ class FactorioContext(CommonContext):
|
|||
f"{Utils.format_SI_prefix(args['value'])}J remaining.")
|
||||
self.rcon_client.send_command(f"/ap-energylink {gained}")
|
||||
|
||||
def run_gui(self):
|
||||
from kvui import GameManager
|
||||
|
||||
class FactorioManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago"),
|
||||
("FactorioServer", "Factorio Server Log"),
|
||||
("FactorioWatcher", "Bridge Data Log"),
|
||||
]
|
||||
base_title = "Archipelago Factorio Client"
|
||||
|
||||
self.ui = FactorioManager(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
|
||||
|
||||
async def game_watcher(ctx: FactorioContext):
|
||||
bridge_logger = logging.getLogger("FactorioWatcher")
|
||||
|
@ -346,15 +360,11 @@ async def factorio_spinup_server(ctx: FactorioContext) -> bool:
|
|||
async def main(args):
|
||||
ctx = FactorioContext(args.connect, args.password)
|
||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
|
||||
input_task = None
|
||||
|
||||
if gui_enabled:
|
||||
from kvui import FactorioManager
|
||||
ctx.ui = FactorioManager(ctx)
|
||||
ui_task = asyncio.create_task(ctx.ui.async_run(), name="UI")
|
||||
else:
|
||||
ui_task = None
|
||||
if sys.stdin:
|
||||
input_task = asyncio.create_task(console_loop(ctx), name="Input")
|
||||
ctx.run_gui()
|
||||
ctx.run_cli()
|
||||
|
||||
factorio_server_task = asyncio.create_task(factorio_spinup_server(ctx), name="FactorioSpinupServer")
|
||||
successful_launch = await factorio_server_task
|
||||
if successful_launch:
|
||||
|
@ -370,12 +380,6 @@ async def main(args):
|
|||
|
||||
await ctx.shutdown()
|
||||
|
||||
if ui_task:
|
||||
await ui_task
|
||||
|
||||
if input_task:
|
||||
input_task.cancel()
|
||||
|
||||
|
||||
class FactorioJSONtoTextParser(JSONtoTextParser):
|
||||
def _handle_color(self, node: JSONMessagePart):
|
||||
|
@ -416,7 +420,5 @@ if __name__ == '__main__':
|
|||
|
||||
server_args = ("--rcon-port", rcon_port, "--rcon-password", rcon_password, *rest)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main(args))
|
||||
loop.close()
|
||||
asyncio.run(main(args))
|
||||
colorama.deinit()
|
||||
|
|
33
OoTClient.py
33
OoTClient.py
|
@ -48,9 +48,11 @@ deathlink_sent_this_death: we interacted with the multiworld on this death, wait
|
|||
|
||||
oot_loc_name_to_id = network_data_package["games"]["Ocarina of Time"]["location_name_to_id"]
|
||||
|
||||
|
||||
def get_item_value(ap_id):
|
||||
return ap_id - 66000
|
||||
|
||||
|
||||
class OoTCommandProcessor(ClientCommandProcessor):
|
||||
def __init__(self, ctx):
|
||||
super().__init__(ctx)
|
||||
|
@ -91,6 +93,18 @@ class OoTContext(CommonContext):
|
|||
self.deathlink_pending = True
|
||||
super().on_deathlink(data)
|
||||
|
||||
def run_gui(self):
|
||||
from kvui import GameManager
|
||||
|
||||
class OoTManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
]
|
||||
base_title = "Archipelago Ocarina of Time Client"
|
||||
|
||||
self.ui = OoTManager(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
|
||||
|
||||
def get_payload(ctx: OoTContext):
|
||||
if ctx.deathlink_enabled and ctx.deathlink_pending:
|
||||
|
@ -253,13 +267,8 @@ if __name__ == '__main__':
|
|||
ctx = OoTContext(args.connect, args.password)
|
||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="Server Loop")
|
||||
if gui_enabled:
|
||||
input_task = None
|
||||
from kvui import OoTManager
|
||||
ctx.ui = OoTManager(ctx)
|
||||
ui_task = asyncio.create_task(ctx.ui.async_run(), name="UI")
|
||||
else:
|
||||
input_task = asyncio.create_task(console_loop(ctx), name="Input")
|
||||
ui_task = None
|
||||
ctx.run_gui()
|
||||
ctx.run_cli()
|
||||
|
||||
ctx.n64_sync_task = asyncio.create_task(n64_sync_task(ctx), name="N64 Sync")
|
||||
|
||||
|
@ -271,17 +280,9 @@ if __name__ == '__main__':
|
|||
if ctx.n64_sync_task:
|
||||
await ctx.n64_sync_task
|
||||
|
||||
if ui_task:
|
||||
await ui_task
|
||||
|
||||
if input_task:
|
||||
input_task.cancel()
|
||||
|
||||
import colorama
|
||||
|
||||
colorama.init()
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main())
|
||||
loop.close()
|
||||
asyncio.run(main())
|
||||
colorama.deinit()
|
||||
|
|
36
SNIClient.py
36
SNIClient.py
|
@ -186,6 +186,19 @@ class Context(CommonContext):
|
|||
# Once the games handled by SNIClient gets made to be remote items, this will no longer be needed.
|
||||
asyncio.create_task(self.send_msgs([{"cmd": "LocationScouts", "locations": list(new_locations)}]))
|
||||
|
||||
def run_gui(self):
|
||||
from kvui import GameManager
|
||||
|
||||
class SNIManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago"),
|
||||
("SNES", "SNES"),
|
||||
]
|
||||
base_title = "Archipelago SNI Client"
|
||||
|
||||
self.ui = SNIManager(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
|
||||
|
||||
async def deathlink_kill_player(ctx: Context):
|
||||
ctx.death_state = DeathState.killing_player
|
||||
|
@ -1291,15 +1304,10 @@ async def main():
|
|||
ctx = Context(args.snes, args.connect, args.password)
|
||||
if ctx.server_task is None:
|
||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
|
||||
input_task = None
|
||||
|
||||
if gui_enabled:
|
||||
from kvui import SNIManager
|
||||
ctx.ui = SNIManager(ctx)
|
||||
ui_task = asyncio.create_task(ctx.ui.async_run(), name="UI")
|
||||
else:
|
||||
ui_task = None
|
||||
if sys.stdin:
|
||||
input_task = asyncio.create_task(console_loop(ctx), name="Input")
|
||||
ctx.run_gui()
|
||||
ctx.run_cli()
|
||||
|
||||
snes_connect_task = asyncio.create_task(snes_connect(ctx, ctx.snes_address), name="SNES Connect")
|
||||
watcher_task = asyncio.create_task(game_watcher(ctx), name="GameWatcher")
|
||||
|
@ -1315,12 +1323,6 @@ async def main():
|
|||
await watcher_task
|
||||
await ctx.shutdown()
|
||||
|
||||
if ui_task:
|
||||
await ui_task
|
||||
|
||||
if input_task:
|
||||
input_task.cancel()
|
||||
|
||||
|
||||
def get_alttp_settings(romfile: str):
|
||||
lastSettings = Utils.get_adjuster_settings(GAME_ALTTP)
|
||||
|
@ -1432,7 +1434,7 @@ def get_alttp_settings(romfile: str):
|
|||
if hasattr(lastSettings, "world"):
|
||||
delattr(lastSettings, "world")
|
||||
else:
|
||||
adjusted = False;
|
||||
adjusted = False
|
||||
if adjusted:
|
||||
try:
|
||||
shutil.move(adjustedromfile, romfile)
|
||||
|
@ -1446,7 +1448,5 @@ def get_alttp_settings(romfile: str):
|
|||
|
||||
if __name__ == '__main__':
|
||||
colorama.init()
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main())
|
||||
loop.close()
|
||||
asyncio.run(main())
|
||||
colorama.deinit()
|
||||
|
|
37
kvui.py
37
kvui.py
|
@ -369,15 +369,6 @@ class GameManager(App):
|
|||
self.energy_link_label.text = f"EL: {Utils.format_SI_prefix(self.ctx.current_energy_link_value)}J"
|
||||
|
||||
|
||||
class FactorioManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago"),
|
||||
("FactorioServer", "Factorio Server Log"),
|
||||
("FactorioWatcher", "Bridge Data Log"),
|
||||
]
|
||||
base_title = "Archipelago Factorio Client"
|
||||
|
||||
|
||||
class ChecksFinderManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
|
@ -385,34 +376,6 @@ class ChecksFinderManager(GameManager):
|
|||
base_title = "Archipelago ChecksFinder Client"
|
||||
|
||||
|
||||
class SNIManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago"),
|
||||
("SNES", "SNES"),
|
||||
]
|
||||
base_title = "Archipelago SNI Client"
|
||||
|
||||
|
||||
class TextManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
]
|
||||
base_title = "Archipelago Text Client"
|
||||
|
||||
|
||||
class FF1Manager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
]
|
||||
base_title = "Archipelago Final Fantasy 1 Client"
|
||||
|
||||
class OoTManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
]
|
||||
base_title = "Archipelago Ocarina of Time Client"
|
||||
|
||||
|
||||
class LogtoUI(logging.Handler):
|
||||
def __init__(self, on_log):
|
||||
super(LogtoUI, self).__init__(logging.INFO)
|
||||
|
|
Loading…
Reference in New Issue