CommonClient: add more docstrings and comments #3821
This commit is contained in:
parent
3205e9b3a0
commit
7337309426
|
@ -45,10 +45,21 @@ def get_ssl_context():
|
||||||
|
|
||||||
|
|
||||||
class ClientCommandProcessor(CommandProcessor):
|
class ClientCommandProcessor(CommandProcessor):
|
||||||
|
"""
|
||||||
|
The Command Processor will parse every method of the class that starts with "_cmd_" as a command to be called
|
||||||
|
when parsing user input, i.e. _cmd_exit will be called when the user sends the command "/exit".
|
||||||
|
|
||||||
|
The decorator @mark_raw can be imported from MultiServer and tells the parser to only split on the first
|
||||||
|
space after the command i.e. "/exit one two three" will be passed in as method("one two three") with mark_raw
|
||||||
|
and method("one", "two", "three") without.
|
||||||
|
|
||||||
|
In addition all docstrings for command methods will be displayed to the user on launch and when using "/help"
|
||||||
|
"""
|
||||||
def __init__(self, ctx: CommonContext):
|
def __init__(self, ctx: CommonContext):
|
||||||
self.ctx = ctx
|
self.ctx = ctx
|
||||||
|
|
||||||
def output(self, text: str):
|
def output(self, text: str):
|
||||||
|
"""Helper function to abstract logging to the CommonClient UI"""
|
||||||
logger.info(text)
|
logger.info(text)
|
||||||
|
|
||||||
def _cmd_exit(self) -> bool:
|
def _cmd_exit(self) -> bool:
|
||||||
|
@ -164,13 +175,14 @@ class ClientCommandProcessor(CommandProcessor):
|
||||||
async_start(self.ctx.send_msgs([{"cmd": "StatusUpdate", "status": state}]), name="send StatusUpdate")
|
async_start(self.ctx.send_msgs([{"cmd": "StatusUpdate", "status": state}]), name="send StatusUpdate")
|
||||||
|
|
||||||
def default(self, raw: str):
|
def default(self, raw: str):
|
||||||
|
"""The default message parser to be used when parsing any messages that do not match a command"""
|
||||||
raw = self.ctx.on_user_say(raw)
|
raw = self.ctx.on_user_say(raw)
|
||||||
if raw:
|
if raw:
|
||||||
async_start(self.ctx.send_msgs([{"cmd": "Say", "text": raw}]), name="send Say")
|
async_start(self.ctx.send_msgs([{"cmd": "Say", "text": raw}]), name="send Say")
|
||||||
|
|
||||||
|
|
||||||
class CommonContext:
|
class CommonContext:
|
||||||
# Should be adjusted as needed in subclasses
|
# The following attributes are used to Connect and should be adjusted as needed in subclasses
|
||||||
tags: typing.Set[str] = {"AP"}
|
tags: typing.Set[str] = {"AP"}
|
||||||
game: typing.Optional[str] = None
|
game: typing.Optional[str] = None
|
||||||
items_handling: typing.Optional[int] = None
|
items_handling: typing.Optional[int] = None
|
||||||
|
@ -429,7 +441,10 @@ class CommonContext:
|
||||||
self.auth = await self.console_input()
|
self.auth = await self.console_input()
|
||||||
|
|
||||||
async def send_connect(self, **kwargs: typing.Any) -> None:
|
async def send_connect(self, **kwargs: typing.Any) -> None:
|
||||||
""" send `Connect` packet to log in to server """
|
"""
|
||||||
|
Send a `Connect` packet to log in to the server,
|
||||||
|
additional keyword args can override any value in the connection packet
|
||||||
|
"""
|
||||||
payload = {
|
payload = {
|
||||||
'cmd': 'Connect',
|
'cmd': 'Connect',
|
||||||
'password': self.password, 'name': self.auth, 'version': Utils.version_tuple,
|
'password': self.password, 'name': self.auth, 'version': Utils.version_tuple,
|
||||||
|
@ -459,6 +474,7 @@ class CommonContext:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def slot_concerns_self(self, slot) -> bool:
|
def slot_concerns_self(self, slot) -> bool:
|
||||||
|
"""Helper function to abstract player groups, should be used instead of checking slot == self.slot directly."""
|
||||||
if slot == self.slot:
|
if slot == self.slot:
|
||||||
return True
|
return True
|
||||||
if slot in self.slot_info:
|
if slot in self.slot_info:
|
||||||
|
@ -466,6 +482,7 @@ class CommonContext:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def is_echoed_chat(self, print_json_packet: dict) -> bool:
|
def is_echoed_chat(self, print_json_packet: dict) -> bool:
|
||||||
|
"""Helper function for filtering out messages sent by self."""
|
||||||
return print_json_packet.get("type", "") == "Chat" \
|
return print_json_packet.get("type", "") == "Chat" \
|
||||||
and print_json_packet.get("team", None) == self.team \
|
and print_json_packet.get("team", None) == self.team \
|
||||||
and print_json_packet.get("slot", None) == self.slot
|
and print_json_packet.get("slot", None) == self.slot
|
||||||
|
@ -504,6 +521,7 @@ class CommonContext:
|
||||||
self.ui.print_json([{"text": text, "type": "color", "color": "orange"}])
|
self.ui.print_json([{"text": text, "type": "color", "color": "orange"}])
|
||||||
|
|
||||||
def update_permissions(self, permissions: typing.Dict[str, int]):
|
def update_permissions(self, permissions: typing.Dict[str, int]):
|
||||||
|
"""Internal method to parse and save server permissions from RoomInfo"""
|
||||||
for permission_name, permission_flag in permissions.items():
|
for permission_name, permission_flag in permissions.items():
|
||||||
try:
|
try:
|
||||||
flag = Permission(permission_flag)
|
flag = Permission(permission_flag)
|
||||||
|
@ -613,6 +631,7 @@ class CommonContext:
|
||||||
logger.info(f"DeathLink: Received from {data['source']}")
|
logger.info(f"DeathLink: Received from {data['source']}")
|
||||||
|
|
||||||
async def send_death(self, death_text: str = ""):
|
async def send_death(self, death_text: str = ""):
|
||||||
|
"""Helper function to send a deathlink using death_text as the unique death cause string."""
|
||||||
if self.server and self.server.socket:
|
if self.server and self.server.socket:
|
||||||
logger.info("DeathLink: Sending death to your friends...")
|
logger.info("DeathLink: Sending death to your friends...")
|
||||||
self.last_death_link = time.time()
|
self.last_death_link = time.time()
|
||||||
|
@ -626,6 +645,7 @@ class CommonContext:
|
||||||
}])
|
}])
|
||||||
|
|
||||||
async def update_death_link(self, death_link: bool):
|
async def update_death_link(self, death_link: bool):
|
||||||
|
"""Helper function to set Death Link connection tag on/off and update the connection if already connected."""
|
||||||
old_tags = self.tags.copy()
|
old_tags = self.tags.copy()
|
||||||
if death_link:
|
if death_link:
|
||||||
self.tags.add("DeathLink")
|
self.tags.add("DeathLink")
|
||||||
|
@ -635,7 +655,7 @@ class CommonContext:
|
||||||
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]) -> typing.Optional["kvui.MessageBox"]:
|
def gui_error(self, title: str, text: typing.Union[Exception, str]) -> typing.Optional["kvui.MessageBox"]:
|
||||||
"""Displays an error messagebox"""
|
"""Displays an error messagebox in the loaded Kivy UI. Override if using a different UI framework"""
|
||||||
if not self.ui:
|
if not self.ui:
|
||||||
return None
|
return None
|
||||||
title = title or "Error"
|
title = title or "Error"
|
||||||
|
@ -987,6 +1007,7 @@ async def console_loop(ctx: CommonContext):
|
||||||
|
|
||||||
|
|
||||||
def get_base_parser(description: typing.Optional[str] = None):
|
def get_base_parser(description: typing.Optional[str] = None):
|
||||||
|
"""Base argument parser to be reused for components subclassing off of CommonClient"""
|
||||||
import argparse
|
import argparse
|
||||||
parser = argparse.ArgumentParser(description=description)
|
parser = argparse.ArgumentParser(description=description)
|
||||||
parser.add_argument('--connect', default=None, help='Address of the multiworld host.')
|
parser.add_argument('--connect', default=None, help='Address of the multiworld host.')
|
||||||
|
@ -1037,6 +1058,7 @@ def run_as_textclient(*args):
|
||||||
parser.add_argument("url", nargs="?", help="Archipelago connection url")
|
parser.add_argument("url", nargs="?", help="Archipelago connection url")
|
||||||
args = parser.parse_args(args)
|
args = parser.parse_args(args)
|
||||||
|
|
||||||
|
# handle if text client is launched using the "archipelago://name:pass@host:port" url from webhost
|
||||||
if args.url:
|
if args.url:
|
||||||
url = urllib.parse.urlparse(args.url)
|
url = urllib.parse.urlparse(args.url)
|
||||||
if url.scheme == "archipelago":
|
if url.scheme == "archipelago":
|
||||||
|
@ -1048,6 +1070,7 @@ def run_as_textclient(*args):
|
||||||
else:
|
else:
|
||||||
parser.error(f"bad url, found {args.url}, expected url in form of archipelago://archipelago.gg:38281")
|
parser.error(f"bad url, found {args.url}, expected url in form of archipelago://archipelago.gg:38281")
|
||||||
|
|
||||||
|
# use colorama to display colored text highlighting on windows
|
||||||
colorama.init()
|
colorama.init()
|
||||||
|
|
||||||
asyncio.run(main(args))
|
asyncio.run(main(args))
|
||||||
|
|
Loading…
Reference in New Issue