Clients: UX improvements (#615)
This commit is contained in:
		| @@ -127,6 +127,7 @@ class CommonContext(): | ||||
|     items_handling: typing.Optional[int] = None | ||||
|     slot_info: typing.Dict[int, NetworkSlot] | ||||
|     current_energy_link_value: int = 0  # to display in UI, gets set by server | ||||
|     _messagebox = None | ||||
|  | ||||
|     def __init__(self, server_address, password): | ||||
|         # server state | ||||
| @@ -356,6 +357,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 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): | ||||
|         """Import kivy UI system and start running it as self.ui_task.""" | ||||
|         from kvui import GameManager | ||||
| @@ -418,14 +440,22 @@ async def server_loop(ctx: CommonContext, address=None): | ||||
|             for msg in decode(data): | ||||
|                 await process_server_cmd(ctx, msg) | ||||
|         logger.warning('Disconnected from multiworld server, type /connect to reconnect') | ||||
|     except ConnectionRefusedError: | ||||
|         logger.exception('Connection refused by the server. May not be running Archipelago on that address or port.') | ||||
|     except websockets.InvalidURI: | ||||
|         logger.exception('Failed to connect to the multiworld server (invalid URI)') | ||||
|     except OSError: | ||||
|         logger.exception('Failed to connect to the multiworld server') | ||||
|     except Exception: | ||||
|         logger.exception('Lost connection to the multiworld server, type /connect to reconnect') | ||||
|     except ConnectionRefusedError as e: | ||||
|         msg = 'Connection refused by the server. May not be running Archipelago on that address or port.' | ||||
|         logger.exception(msg, extra={'compact_gui': True}) | ||||
|         ctx.gui_error(msg, e) | ||||
|     except websockets.InvalidURI as e: | ||||
|         msg = 'Failed to connect to the multiworld server (invalid URI)' | ||||
|         logger.exception(msg, extra={'compact_gui': True}) | ||||
|         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: | ||||
|         await ctx.connection_closed() | ||||
|         if ctx.server_address: | ||||
| @@ -448,7 +478,9 @@ async def process_server_cmd(ctx: CommonContext, args: dict): | ||||
|         raise | ||||
|     if cmd == 'RoomInfo': | ||||
|         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: | ||||
|             logger.info('--------------------------------') | ||||
|             logger.info('Room Information:') | ||||
|   | ||||
| @@ -150,7 +150,9 @@ async def game_watcher(ctx: FactorioContext): | ||||
|                 next_bridge = time.perf_counter() + 1 | ||||
|                 ctx.awaiting_bridge = False | ||||
|                 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}") | ||||
|                 elif data["seed_name"] != ctx.seed_name: | ||||
|                     bridge_logger.warning( | ||||
| @@ -342,8 +344,10 @@ async def factorio_spinup_server(ctx: FactorioContext) -> bool: | ||||
|             await asyncio.sleep(0.01) | ||||
|  | ||||
|     except Exception as e: | ||||
|         logger.exception(e) | ||||
|         logger.error("Aborted Factorio Server Bridge") | ||||
|         logger.exception(e, extra={"compact_gui": True}) | ||||
|         msg = "Aborted Factorio Server Bridge" | ||||
|         logger.error(msg) | ||||
|         ctx.gui_error(msg, e) | ||||
|         ctx.exit_event.set() | ||||
|  | ||||
|     else: | ||||
|   | ||||
							
								
								
									
										13
									
								
								kvui.py
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								kvui.py
									
									
									
									
									
								
							| @@ -464,8 +464,19 @@ class LogtoUI(logging.Handler): | ||||
|         super(LogtoUI, self).__init__(logging.INFO) | ||||
|         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: | ||||
|         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): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 black-sliver
					black-sliver