Core: Phase out Print packets (#1364)

This commit is contained in:
Jarno 2023-02-05 22:06:38 +01:00 committed by GitHub
parent cae1e683e2
commit ff175008a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 60 deletions

View File

@ -41,7 +41,6 @@ from NetUtils import Endpoint, ClientStatus, NetworkItem, decode, encode, Networ
SlotType
min_client_version = Version(0, 1, 6)
print_command_compatability_threshold = Version(0, 3, 5) # Remove backwards compatibility around 0.3.7
colorama.init()
@ -309,6 +308,10 @@ class Context:
endpoints = (endpoint for endpoint in self.endpoints if endpoint.auth)
async_start(self.broadcast_send_encoded_msgs(endpoints, msgs))
def broadcast_text_all(self, text: str, additional_arguments: dict = {}):
logging.info("Notice (all): %s" % text)
self.broadcast_all([{**{"cmd": "PrintJSON", "data": [{ "text": text }]}, **additional_arguments}])
def broadcast_team(self, team: int, msgs: typing.List[dict]):
msgs = self.dumper(msgs)
endpoints = (endpoint for endpoint in itertools.chain.from_iterable(self.clients[team].values()))
@ -325,29 +328,18 @@ class Context:
self.clients[endpoint.team][endpoint.slot].remove(endpoint)
await on_client_disconnected(self, endpoint)
# text
def notify_all(self, text: str):
logging.info("Notice (all): %s" % text)
broadcast_text_all(self, text)
def notify_client(self, client: Client, text: str):
if not client.auth:
return
logging.info("Notice (Player %s in team %d): %s" % (client.name, client.team + 1, text))
if client.version >= print_command_compatability_threshold:
async_start(self.send_msgs(client, [{"cmd": "PrintJSON", "data": [{ "text": text }]}]))
else:
async_start(self.send_msgs(client, [{"cmd": "Print", "text": text}]))
async_start(self.send_msgs(client, [{"cmd": "PrintJSON", "data": [{ "text": text }]}]))
def notify_client_multiple(self, client: Client, texts: typing.List[str]):
if not client.auth:
return
if client.version >= print_command_compatability_threshold:
async_start(self.send_msgs(client,
[{"cmd": "PrintJSON", "data": [{ "text": text }]} for text in texts]))
else:
async_start(self.send_msgs(client, [{"cmd": "Print", "text": text} for text in texts]))
async_start(self.send_msgs(client, [{"cmd": "PrintJSON", "data": [{ "text": text }]} for text in texts]))
# loading
@ -685,7 +677,7 @@ class Context:
def on_goal_achieved(self, client: Client):
finished_msg = f'{self.get_aliased_name(client.team, client.slot)} (Team #{client.team + 1})' \
f' has completed their goal.'
self.notify_all(finished_msg)
self.broadcast_text_all(finished_msg)
if "auto" in self.collect_mode:
collect_player(self, client.team, client.slot)
if "auto" in self.release_mode:
@ -778,7 +770,7 @@ async def on_client_joined(ctx: Context, client: Client):
update_client_status(ctx, client, ClientStatus.CLIENT_CONNECTED)
version_str = '.'.join(str(x) for x in client.version)
verb = "tracking" if "Tracker" in client.tags else "playing"
ctx.notify_all(
ctx.broadcast_text_all(
f"{ctx.get_aliased_name(client.team, client.slot)} (Team #{client.team + 1}) "
f"{verb} {ctx.games[client.slot]} has joined. "
f"Client({version_str}), {client.tags}).")
@ -791,42 +783,26 @@ async def on_client_joined(ctx: Context, client: Client):
async def on_client_left(ctx: Context, client: Client):
update_client_status(ctx, client, ClientStatus.CLIENT_UNKNOWN)
ctx.notify_all(
ctx.broadcast_text_all(
"%s (Team #%d) has left the game" % (ctx.get_aliased_name(client.team, client.slot), client.team + 1))
ctx.client_connection_timers[client.team, client.slot] = datetime.datetime.now(datetime.timezone.utc)
async def countdown(ctx: Context, timer: int):
broadcast_countdown(ctx, timer, f"[Server]: Starting countdown of {timer}s")
ctx.broadcast_text_all(f"[Server]: Starting countdown of {timer}s", {"type": "Countdown", "countdown": timer})
if ctx.countdown_timer:
ctx.countdown_timer = timer # timer is already running, set it to a different time
else:
ctx.countdown_timer = timer
while ctx.countdown_timer > 0:
broadcast_countdown(ctx, ctx.countdown_timer, f"[Server]: {ctx.countdown_timer}")
ctx.broadcast_text_all(f"[Server]: {ctx.countdown_timer}",
{"type": "Countdown", "countdown": ctx.countdown_timer})
ctx.countdown_timer -= 1
await asyncio.sleep(1)
broadcast_countdown(ctx, 0, f"[Server]: GO")
ctx.broadcast_text_all(f"[Server]: GO", {"type": "Countdown", "countdown": 0})
ctx.countdown_timer = 0
def broadcast_text_all(ctx: Context, text: str, additional_arguments: dict = {}):
old_clients, new_clients = [], []
for teams in ctx.clients.values():
for clients in teams.values():
for client in clients:
new_clients.append(client) if client.version >= print_command_compatability_threshold \
else old_clients.append(client)
ctx.broadcast(old_clients, [{"cmd": "Print", "text": text }])
ctx.broadcast(new_clients, [{**{"cmd": "PrintJSON", "data": [{ "text": text }]}, **additional_arguments}])
def broadcast_countdown(ctx: Context, timer: int, message: str):
broadcast_text_all(ctx, message, {"type": "Countdown", "countdown": timer})
def get_players_string(ctx: Context):
auth_clients = {(c.team, c.slot) for c in ctx.endpoints if c.auth}
@ -894,7 +870,9 @@ def update_checked_locations(ctx: Context, team: int, slot: int):
def release_player(ctx: Context, team: int, slot: int):
"""register any locations that are in the multidata"""
all_locations = set(ctx.locations[slot])
ctx.notify_all("%s (Team #%d) has released all remaining items from their world." % (ctx.player_names[(team, slot)], team + 1))
ctx.broadcast_text_all(
"%s (Team #%d) has released all remaining items from their world." %
(ctx.player_names[(team, slot)], team + 1))
register_location_checks(ctx, team, slot, all_locations)
update_checked_locations(ctx, team, slot)
@ -907,7 +885,8 @@ def collect_player(ctx: Context, team: int, slot: int, is_group: bool = False):
if values[1] == slot:
all_locations[source_slot].add(location_id)
ctx.notify_all("%s (Team #%d) has collected their items from other worlds." % (ctx.player_names[(team, slot)], team + 1))
ctx.broadcast_text_all(
"%s (Team #%d) has collected their items from other worlds." % (ctx.player_names[(team, slot)], team + 1))
for source_player, location_ids in all_locations.items():
register_location_checks(ctx, team, source_player, location_ids, count_activity=False)
update_checked_locations(ctx, team, source_player)
@ -1177,7 +1156,7 @@ class ClientMessageProcessor(CommonCommandProcessor):
def __call__(self, raw: str) -> typing.Optional[bool]:
if not raw.startswith("!admin"):
self.ctx.notify_all(self.ctx.get_aliased_name(self.client.team, self.client.slot) + ': ' + raw)
self.ctx.broadcast_text_all(self.ctx.get_aliased_name(self.client.team, self.client.slot) + ': ' + raw)
return super(ClientMessageProcessor, self).__call__(raw)
def output(self, text):
@ -1205,8 +1184,8 @@ class ClientMessageProcessor(CommonCommandProcessor):
"!admin /option server_password"):
output = f"!admin /option server_password {('*' * random.randint(4, 16))}"
# Otherwise notify the others what is happening.
self.ctx.notify_all(self.ctx.get_aliased_name(self.client.team,
self.client.slot) + ': ' + output)
self.ctx.broadcast_text_all(
self.ctx.get_aliased_name(self.client.team, self.client.slot) + ': ' + output)
if not self.ctx.server_password:
self.output("Sorry, Remote administration is disabled")
@ -1243,7 +1222,7 @@ class ClientMessageProcessor(CommonCommandProcessor):
def _cmd_players(self) -> bool:
"""Get information about connected and missing players."""
if len(self.ctx.player_names) < 10:
self.ctx.notify_all(get_players_string(self.ctx))
self.ctx.broadcast_text_all(get_players_string(self.ctx))
else:
self.output(get_players_string(self.ctx))
return True
@ -1381,7 +1360,7 @@ class ClientMessageProcessor(CommonCommandProcessor):
new_item = NetworkItem(names[item_name], -1, self.client.slot)
get_received_items(self.ctx, self.client.team, self.client.slot, False).append(new_item)
get_received_items(self.ctx, self.client.team, self.client.slot, True).append(new_item)
self.ctx.notify_all(
self.ctx.broadcast_text_all(
'Cheat console: sending "' + item_name + '" to ' + self.ctx.get_aliased_name(self.client.team,
self.client.slot))
send_new_items(self.ctx)
@ -1682,7 +1661,7 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
client.tags = args["tags"]
if set(old_tags) != set(client.tags):
client.no_locations = 'TextOnly' in client.tags or 'Tracker' in client.tags
ctx.notify_all(
ctx.broadcast_text_all(
f"{ctx.get_aliased_name(client.team, client.slot)} (Team #{client.team + 1}) has changed tags "
f"from {old_tags} to {client.tags}.")
@ -1806,7 +1785,7 @@ class ServerCommandProcessor(CommonCommandProcessor):
super(ServerCommandProcessor, self).output(text)
def default(self, raw: str):
self.ctx.notify_all('[Server]: ' + raw)
self.ctx.broadcast_text_all('[Server]: ' + raw)
def _cmd_save(self) -> bool:
"""Save current state to multidata"""
@ -1947,7 +1926,7 @@ class ServerCommandProcessor(CommonCommandProcessor):
send_items_to(self.ctx, team, slot, *new_items)
send_new_items(self.ctx)
self.ctx.notify_all(
self.ctx.broadcast_text_all(
'Cheat console: sending ' + ('' if amount == 1 else f'{amount} of ') +
f'"{item_name}" to {self.ctx.get_aliased_name(team, slot)}')
return True

View File

@ -9,7 +9,7 @@ These steps should be followed in order to establish a gameplay connection with
5. Client sends [Connect](#Connect) packet in order to authenticate with the server.
6. Server validates the client's packet and responds with [Connected](#Connected) or [ConnectionRefused](#ConnectionRefused).
7. Server may send [ReceivedItems](#ReceivedItems) to the client, in the case that the client is missing items that are queued up for it.
8. Server sends [Print](#Print) to all players to notify them of the new client connection.
8. Server sends [PrintJSON](#PrintJSON) to all players to notify them of updates.
In the case that the client does not authenticate properly and receives a [ConnectionRefused](#ConnectionRefused) then the server will maintain the connection and allow for follow-up [Connect](#Connect) packet.
@ -54,7 +54,6 @@ These packets are are sent from the multiworld server to the client. They are no
* [ReceivedItems](#ReceivedItems)
* [LocationInfo](#LocationInfo)
* [RoomUpdate](#RoomUpdate)
* [Print](#Print)
* [PrintJSON](#PrintJSON)
* [DataPackage](#DataPackage)
* [Bounced](#Bounced)
@ -160,16 +159,8 @@ The arguments for RoomUpdate are identical to [RoomInfo](#RoomInfo) barring:
All arguments for this packet are optional, only changes are sent.
### Print
Sent to clients purely to display a message to the player.
* *Deprecation warning: clients that connect with version 0.3.5 or higher will nolonger recieve Print packets, instead all messsages are send as [PrintJSON](#PrintJSON)*
#### Arguments
| Name | Type | Notes |
| ---- | ---- | ----- |
| text | str | Message to display to player. |
### PrintJSON
Sent to clients purely to display a message to the player. This packet differs from [Print](#Print) in that the data being sent with this packet allows for more configurable or specific messaging.
Sent to clients purely to display a message to the player. The data being sent with this packet allows for configurability or specific messaging.
#### Arguments
| Name | Type | Notes |
| ---- | ---- | ----- |
@ -181,7 +172,7 @@ Sent to clients purely to display a message to the player. This packet differs f
| countdown | int | Is present if type is `Countdown`, denotes the amount of seconds remaining on the countdown. |
##### PrintJsonType
PrintJsonType indicates the type of [PrintJson](#PrintJson) packet, different types can be handled differently by the client and can also contain additional arguments. When receiving an unknown type the data's list\[[JSONMessagePart](#JSONMessagePart)\] should still be printed as normal.
PrintJsonType indicates the type of [PrintJson](#PrintJson) packet, different types can be handled differently by the client and can also contain additional arguments. When receiving an unknown or missing type the data's list\[[JSONMessagePart](#JSONMessagePart)\] should still be displayed to the player as normal text.
Currently defined types are:
| Type | Notes |