Clients: UX improvements (#615)
This commit is contained in:
parent
25bea47872
commit
fbf993566d
|
@ -127,6 +127,7 @@ class CommonContext():
|
||||||
items_handling: typing.Optional[int] = None
|
items_handling: typing.Optional[int] = None
|
||||||
slot_info: typing.Dict[int, NetworkSlot]
|
slot_info: typing.Dict[int, NetworkSlot]
|
||||||
current_energy_link_value: int = 0 # to display in UI, gets set by server
|
current_energy_link_value: int = 0 # to display in UI, gets set by server
|
||||||
|
_messagebox = None
|
||||||
|
|
||||||
def __init__(self, server_address, password):
|
def __init__(self, server_address, password):
|
||||||
# server state
|
# server state
|
||||||
|
@ -356,6 +357,27 @@ class CommonContext():
|
||||||
if old_tags != self.tags and self.server and not self.server.socket.closed:
|
if old_tags != self.tags and self.server and not self.server.socket.closed:
|
||||||
await self.send_msgs([{"cmd": "ConnectUpdate", "tags": self.tags}])
|
await self.send_msgs([{"cmd": "ConnectUpdate", "tags": self.tags}])
|
||||||
|
|
||||||
|
def gui_error(self, title: str, text: typing.Union[Exception, str]):
|
||||||
|
"""Displays an error messagebox"""
|
||||||
|
if not self.ui:
|
||||||
|
return
|
||||||
|
title = title or "Error"
|
||||||
|
from kvui import MessageBox
|
||||||
|
if self._messagebox:
|
||||||
|
self._messagebox.dismiss()
|
||||||
|
# make "Multiple exceptions" look nice
|
||||||
|
text = str(text).replace('[Errno', '\n[Errno').strip()
|
||||||
|
# split long messages into title and text
|
||||||
|
parts = title.split('. ', 1)
|
||||||
|
if len(parts) == 1:
|
||||||
|
parts = title.split(', ', 1)
|
||||||
|
if len(parts) > 1:
|
||||||
|
text = parts[1] + '\n\n' + text
|
||||||
|
title = parts[0]
|
||||||
|
# display error
|
||||||
|
self._messagebox = MessageBox(title, text, error=True)
|
||||||
|
self._messagebox.open()
|
||||||
|
|
||||||
def run_gui(self):
|
def run_gui(self):
|
||||||
"""Import kivy UI system and start running it as self.ui_task."""
|
"""Import kivy UI system and start running it as self.ui_task."""
|
||||||
from kvui import GameManager
|
from kvui import GameManager
|
||||||
|
@ -418,14 +440,22 @@ async def server_loop(ctx: CommonContext, address=None):
|
||||||
for msg in decode(data):
|
for msg in decode(data):
|
||||||
await process_server_cmd(ctx, msg)
|
await process_server_cmd(ctx, msg)
|
||||||
logger.warning('Disconnected from multiworld server, type /connect to reconnect')
|
logger.warning('Disconnected from multiworld server, type /connect to reconnect')
|
||||||
except ConnectionRefusedError:
|
except ConnectionRefusedError as e:
|
||||||
logger.exception('Connection refused by the server. May not be running Archipelago on that address or port.')
|
msg = 'Connection refused by the server. May not be running Archipelago on that address or port.'
|
||||||
except websockets.InvalidURI:
|
logger.exception(msg, extra={'compact_gui': True})
|
||||||
logger.exception('Failed to connect to the multiworld server (invalid URI)')
|
ctx.gui_error(msg, e)
|
||||||
except OSError:
|
except websockets.InvalidURI as e:
|
||||||
logger.exception('Failed to connect to the multiworld server')
|
msg = 'Failed to connect to the multiworld server (invalid URI)'
|
||||||
except Exception:
|
logger.exception(msg, extra={'compact_gui': True})
|
||||||
logger.exception('Lost connection to the multiworld server, type /connect to reconnect')
|
ctx.gui_error(msg, e)
|
||||||
|
except OSError as e:
|
||||||
|
msg = 'Failed to connect to the multiworld server'
|
||||||
|
logger.exception(msg, extra={'compact_gui': True})
|
||||||
|
ctx.gui_error(msg, e)
|
||||||
|
except Exception as e:
|
||||||
|
msg = 'Lost connection to the multiworld server, type /connect to reconnect'
|
||||||
|
logger.exception(msg, extra={'compact_gui': True})
|
||||||
|
ctx.gui_error(msg, e)
|
||||||
finally:
|
finally:
|
||||||
await ctx.connection_closed()
|
await ctx.connection_closed()
|
||||||
if ctx.server_address:
|
if ctx.server_address:
|
||||||
|
@ -448,7 +478,9 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
|
||||||
raise
|
raise
|
||||||
if cmd == 'RoomInfo':
|
if cmd == 'RoomInfo':
|
||||||
if ctx.seed_name and ctx.seed_name != args["seed_name"]:
|
if ctx.seed_name and ctx.seed_name != args["seed_name"]:
|
||||||
logger.info("The server is running a different multiworld than your client is. (invalid seed_name)")
|
msg = "The server is running a different multiworld than your client is. (invalid seed_name)"
|
||||||
|
logger.info(msg, extra={'compact_gui': True})
|
||||||
|
ctx.gui_error('Error', msg)
|
||||||
else:
|
else:
|
||||||
logger.info('--------------------------------')
|
logger.info('--------------------------------')
|
||||||
logger.info('Room Information:')
|
logger.info('Room Information:')
|
||||||
|
|
|
@ -150,7 +150,9 @@ async def game_watcher(ctx: FactorioContext):
|
||||||
next_bridge = time.perf_counter() + 1
|
next_bridge = time.perf_counter() + 1
|
||||||
ctx.awaiting_bridge = False
|
ctx.awaiting_bridge = False
|
||||||
data = json.loads(ctx.rcon_client.send_command("/ap-sync"))
|
data = json.loads(ctx.rcon_client.send_command("/ap-sync"))
|
||||||
if data["slot_name"] != ctx.auth:
|
if not ctx.auth:
|
||||||
|
pass # auth failed, wait for new attempt
|
||||||
|
elif data["slot_name"] != ctx.auth:
|
||||||
bridge_logger.warning(f"Connected World is not the expected one {data['slot_name']} != {ctx.auth}")
|
bridge_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:
|
||||||
bridge_logger.warning(
|
bridge_logger.warning(
|
||||||
|
@ -342,8 +344,10 @@ async def factorio_spinup_server(ctx: FactorioContext) -> bool:
|
||||||
await asyncio.sleep(0.01)
|
await asyncio.sleep(0.01)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
logger.exception(e, extra={"compact_gui": True})
|
||||||
logger.error("Aborted Factorio Server Bridge")
|
msg = "Aborted Factorio Server Bridge"
|
||||||
|
logger.error(msg)
|
||||||
|
ctx.gui_error(msg, e)
|
||||||
ctx.exit_event.set()
|
ctx.exit_event.set()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
13
kvui.py
13
kvui.py
|
@ -464,8 +464,19 @@ class LogtoUI(logging.Handler):
|
||||||
super(LogtoUI, self).__init__(logging.INFO)
|
super(LogtoUI, self).__init__(logging.INFO)
|
||||||
self.on_log = on_log
|
self.on_log = on_log
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def format_compact(record: logging.LogRecord) -> str:
|
||||||
|
if isinstance(record.msg, Exception):
|
||||||
|
return str(record.msg)
|
||||||
|
return (f'{record.exc_info[1]}\n' if record.exc_info else '') + str(record.msg).split("\n")[0]
|
||||||
|
|
||||||
def handle(self, record: logging.LogRecord) -> None:
|
def handle(self, record: logging.LogRecord) -> None:
|
||||||
self.on_log(self.format(record))
|
if getattr(record, 'skip_gui', False):
|
||||||
|
pass # skip output
|
||||||
|
elif getattr(record, 'compact_gui', False):
|
||||||
|
self.on_log(self.format_compact(record))
|
||||||
|
else:
|
||||||
|
self.on_log(self.format(record))
|
||||||
|
|
||||||
|
|
||||||
class UILog(RecycleView):
|
class UILog(RecycleView):
|
||||||
|
|
Loading…
Reference in New Issue