diff --git a/MultiServer.py b/MultiServer.py index 2561b0692a3c..3829220a7359 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -1900,6 +1900,48 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict): if locs and create_as_hint: ctx.save() await ctx.send_msgs(client, [{'cmd': 'LocationInfo', 'locations': locs}]) + + elif cmd == 'CreateHints': + location_player = args.get("player", client.slot) + locations = args["locations"] + status = args.get("status", HintStatus.HINT_UNSPECIFIED) + + if not locations: + await ctx.send_msgs(client, [{"cmd": "InvalidPacket", "type": "arguments", + "text": "CreateHints: No locations specified.", "original_cmd": cmd}]) + + hints = [] + + for location in locations: + if location_player != client.slot and location not in ctx.locations[location_player]: + error_text = ( + "CreateHints: One or more of the locations do not exist for the specified off-world player. " + "Please refrain from hinting other slot's locations that you don't know contain your items." + ) + await ctx.send_msgs(client, [{"cmd": "InvalidPacket", "type": "arguments", + "text": error_text, "original_cmd": cmd}]) + return + + target_item, item_player, flags = ctx.locations[location_player][location] + + if client.slot not in ctx.slot_set(item_player): + if status != HintStatus.HINT_UNSPECIFIED: + error_text = 'CreateHints: Must use "unspecified"/None status for items from other players.' + await ctx.send_msgs(client, [{"cmd": "InvalidPacket", "type": "arguments", + "text": error_text, "original_cmd": cmd}]) + return + + if client.slot != location_player: + error_text = "CreateHints: Can only create hints for own items or own locations." + await ctx.send_msgs(client, [{"cmd": "InvalidPacket", "type": "arguments", + "text": error_text, "original_cmd": cmd}]) + return + + hints += collect_hint_location_id(ctx, client.team, location_player, location, status) + + # As of writing this code, only_new=True does not update status for existing hints + ctx.notify_hints(client.team, hints, only_new=True) + ctx.save() elif cmd == 'UpdateHint': location = args["location"] diff --git a/docs/network protocol.md b/docs/network protocol.md index 4331cf971007..89926a158fae 100644 --- a/docs/network protocol.md +++ b/docs/network protocol.md @@ -272,6 +272,7 @@ These packets are sent purely from client to server. They are not accepted by cl * [Sync](#Sync) * [LocationChecks](#LocationChecks) * [LocationScouts](#LocationScouts) +* [CreateHints](#CreateHints) * [UpdateHint](#UpdateHint) * [StatusUpdate](#StatusUpdate) * [Say](#Say) @@ -343,6 +344,21 @@ This is useful in cases where an item appears in the game world, such as 'ledge | locations | list\[int\] | The ids of the locations seen by the client. May contain any number of locations, even ones sent before; duplicates do not cause issues with the Archipelago server. | | create_as_hint | int | If non-zero, the scouted locations get created and broadcasted as a player-visible hint.
If 2 only new hints are broadcast, however this does not remove them from the LocationInfo reply. | +### CreateHints + +Sent to the server to create hints for a specified list of locations. +Hints that already exist will be silently skipped and their status will not be updated. + +When creating hints for another slot's locations, the packet will fail if any of those locations don't contain items for the requesting slot. +When creating hints for your own slot's locations, non-existing locations will silently be skipped. + +#### Arguments +| Name | Type | Notes | +| ---- | ---- | ----- | +| locations | list\[int\] | The ids of the locations to create hints for. | +| player | int | The ID of the player whose locations are being hinted for. Defaults to the requesting slot. | +| status | [HintStatus](#HintStatus) | If included, sets the status of the hint to this status. Defaults to `HINT_UNSPECIFIED`. Cannot set `HINT_FOUND`. | + ### UpdateHint Sent to the server to update the status of a Hint. The client must be the 'receiving_player' of the Hint, or the update fails.