From f2a4b2ed2fad44e9af2e59be8d0c0614fd38fffe Mon Sep 17 00:00:00 2001 From: Zach Parks Date: Sun, 9 Jul 2023 13:01:28 -0500 Subject: [PATCH] Archipelago.js 1.1.0 Changes (#190) --- README.md | 100 ++++++++++++------ package.json | 2 +- src/Client.ts | 19 ++-- src/index.ts | 5 +- src/managers/DataManager.ts | 37 +++++-- .../{HintManager.ts => HintsManager.ts} | 4 +- src/managers/ItemsManager.ts | 97 ++++++++++++----- src/managers/LocationsManager.ts | 62 ++++++----- src/managers/PlayersManager.ts | 23 +++- src/types/Player.ts | 12 ++- src/types/index.ts | 1 + 11 files changed, 245 insertions(+), 117 deletions(-) rename src/managers/{HintManager.ts => HintsManager.ts} (96%) diff --git a/README.md b/README.md index 3f9be50..c753190 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,12 @@ A general purpose library for communicating with Archipelago servers in Node.js or in the browser. +You can install it from npm or use a CDN to use it in browser. + +- NPM: `npm install archipelago.js` +- CDN: `import { /* ... */ } from "https://unpkg.com/archipelago.js/dist/archipelago.min.js";` in a + `` block. + ## Archipelago.js Node.js Quick Start Guide Archipelago.js is a JavaScript library that runs in Node or the browser that allows you to connect to an Archipelago @@ -135,8 +141,9 @@ Archipelago.js can also run in the browser. Here's an example that works in most ``` -In this example, the Archipelago client is included as a script from the https://unpkg.com/archipelago.js CDN. You can -also use a locally hosted version of the library if you prefer. +In this example, the Archipelago client is included as a script from the +https://unpkg.com/archipelago.js/dist/archipelago.min.js CDN. You can also use a locally hosted version of the library +if you prefer. ### Handling Server Events @@ -188,6 +195,23 @@ send. client.send(syncPacket); ``` +### Player + +Player objects returned from `PlayersManager` contain the following data and helper functions for easy item and location +name lookups: + +- `name`: The slot name for this player. +- `alias`: The aliased name for this player. +- `slot`: The slot number for this player. +- `team`: The team number for this player. +- `game`: The name of the game this player is playing. +- `type`: Whether this player is a spectator, actual player, or item link group. +- `group_members`: If this player is an item link group, this is the ids of all players that belong to this group. +- `item(itemId)`: A function that returns the name for a given item id in the game of this player. + - Example: `const itemName = player.item(1000);` +- `location(locationId)`: A function that returns the name for a given location id in the game of this player. + - Example: `const locationName = player.location(1000);` + ### LocationsManager The `LocationsManager` class in archipelago.js provides functionality for managing locations within the game. Here are @@ -208,27 +232,20 @@ some tips for working with the `LocationsManager`: ``` 3. **Retrieve Location Name**: Use the `name` method to retrieve the name of a location based on its ID and game name. - If the location or game is not found, it will return a default message. + If the location or game is not found, it will return an "Unknown Location" string instead. ```ts const locationName = client.locations.name("your-game-name", locationId); ``` -4. **Retrieve Location ID**: Use the `id` method to retrieve the ID of a location based on its name and game name. If - the location or game is not found, it will throw an error. - - ```ts - const locationId = client.locations.id("your-game-name", "location-name"); - ``` - -5. **Retrieve Location Group**: Use the `group` method to retrieve an array of location names belonging to a specific +4. **Retrieve Location Group**: Use the `group` method to retrieve an array of location names belonging to a specific group in a game. If the game or group is not found, it will return an empty array. ```ts const locationGroup = client.locations.group("your-game-name", "group-name"); ``` -6. **Automatically Release All Locations**: Use the `autoRelease` method to send all missing locations as checked. +5. **Automatically Release All Locations**: Use the `autoRelease` method to send all missing locations as checked. ```ts client.locations.autoRelease(); @@ -260,7 +277,7 @@ game. Here are some helpful methods for working with the `PlayersManager`: const playerGame = client.players.game(playerId); ``` -4. **Retrieve Group Members**: Use the members method to retrieve an array of player IDs belonging to an item links +4. **Retrieve Group Members**: Use the `members` method to retrieve an array of player IDs belonging to an item links group. If the id is of someone who is not an item links group or the group is not found, it will return an empty array. @@ -268,6 +285,19 @@ game. Here are some helpful methods for working with the `PlayersManager`: const groupMembers = client.players.members(groupId); ``` +5. **Retrieve all Players**: Use the `all` method to return an array of all `Player` objects that are in this room. + + ```ts + const players = client.players.all; + ``` + +6. **Retrieve a specific Player**: Use the `get` method to return a `Player` object with that id. Returns `undefined` if + player does not exist. + + ```ts + const playerOne = client.players.get(1); + ``` + **Special Cases**: The methods in PlayersManager handle some special cases. For example, if the player ID is `0`, it represents the server (Archipelago), and the methods will return appropriate values for these cases. See documentation for full exceptions. @@ -277,57 +307,50 @@ for full exceptions. The `DataManager` class in archipelago.js is responsible for managing room session data and the data package. Here are some tips for working with the `DataManager`: -1. **Retrieve Player Information**: Use the `players` property to access a map of all players, keyed by their player - IDs. - - ```ts - const player = client.data.players.get(playerId); - ``` - -2. **Retrieve Games List**: Use the `games` property to get an array of all games present in the room. +1. **Retrieve Games List**: Use the `games` property to get an array of all games present in the room. ```ts const gamesList = client.data.games; ``` -3. **Retrieve Hint Cost**: Use the `hintCost` property to get the number of hint points required to receive a hint. +2. **Retrieve Hint Cost**: Use the `hintCost` property to get the number of hint points required to receive a hint. ```ts const hintCost = client.data.hintCost; ``` -4. **Retrieve Hint Points**: Use the `hintPoints` property to get the number of hint points the player has. +3. **Retrieve Hint Points**: Use the `hintPoints` property to get the number of hint points the player has. ```ts const hintPoints = client.data.hintPoints; ``` -5. **Retrieve Slot Data**: Use the `slotData` property to access the slot data for the game. +4. **Retrieve Slot Data**: Use the `slotData` property to access the slot data for the game. ```ts const slotData = client.data.slotData; ``` -6. **Retrieve Slot and Team**: Use the `slot` and `team` properties to get the player's slot and team. +5. **Retrieve Slot and Team**: Use the `slot` and `team` properties to get the player's slot and team. ```ts const slot = client.data.slot; const team = client.data.team; ``` -7. **Retrieve Seed**: Use the `seed` property to get the seed for the room. +6. **Retrieve Seed**: Use the `seed` property to get the seed for the room. ```ts const seed = client.data.seed; ``` -8. **Retrieve Permissions**: Use the `permissions` property to get the current permissions for the room. +7. **Retrieve Permissions**: Use the `permissions` property to get the current permissions for the room. ```ts const permissions = client.data.permissions; ``` -9. **Send Set Operations**: Use the `set` method to send a series of set operations using the `SetOperationBuilder` +8. **Send Set Operations**: Use the `set` method to send a series of set operations using the `SetOperationBuilder` object to the server. This method returns a promise that resolves with a `SetReplyPacket` if `wantReply` was requested. @@ -369,10 +392,25 @@ the `ItemsManager`: const itemGroup = client.items.group(gameName, groupName); ``` -### HintManager +4. **Retrieve all received items**: Use the `received` property to retrieve an array of all items that have been sent + by the server. + + ```ts + const allItems = client.items.received; + ``` + +5. **Retrieve ReceivedItem index**: Returns the `index` of the next expected item to be received from the server. Any + items with a lower index are stored in `ItemsManager.received`. Useful for tracking if new items have been received + or to check if a de-sync event occurred. + + ```ts + const receivedItemIndex = client.items.index; + ``` + +### HintsManager -The `HintManager` class in archipelago.js is responsible for managing hint events for a specific player slot. Here are -some tips for working with the `HintManager`: +The `HintsManager` class in archipelago.js is responsible for managing hint events for a specific player slot. Here are +some tips for working with the `HintsManager`: 1. **Get Relevant Hints**: Use the `mine` property to access an array of hints that are relevant to the player slot. diff --git a/package.json b/package.json index f6b7839..3bc1cd4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "archipelago.js", - "version": "1.0.2", + "version": "1.1.0", "description": "A general-purpose client library for communicating with Archipelago game servers, written for Node.js.", "license": "MIT", "main": "dist/index.js", diff --git a/src/Client.ts b/src/Client.ts index 485b96e..0618cf5 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -7,7 +7,7 @@ import { CLIENT_PACKET_TYPE, SERVER_PACKET_TYPE, ServerPacketType } from "./cons import { CONNECTION_STATUS, ConnectionStatus } from "./consts/ConnectionStatus"; import { PRINT_JSON_TYPE } from "./consts/PrintJSONType"; import { DataManager } from "./managers/DataManager"; -import { HintManager } from "./managers/HintManager"; +import { HintsManager } from "./managers/HintsManager"; import { ItemsManager } from "./managers/ItemsManager"; import { LocationsManager } from "./managers/LocationsManager"; import { PlayersManager } from "./managers/PlayersManager"; @@ -24,10 +24,7 @@ import { RetrievedPacket } from "./packets/RetrievedPacket"; import { RoomInfoPacket } from "./packets/RoomInfoPacket"; import { RoomUpdatePacket } from "./packets/RoomUpdatePacket"; import { SetReplyPacket } from "./packets/SetReplyPacket"; -import { ConnectionInformation } from "./types/ConnectionInformation"; -import { VALID_JSON_MESSAGE_TYPE } from "./types/JSONMessagePart"; -import { NetworkVersion } from "./types/NetworkVersion"; -import { SlotData } from "./types/SlotData"; +import { ConnectionInformation, NetworkVersion, SlotData, VALID_JSON_MESSAGE_TYPE } from "./types"; /** * The client that connects to an Archipelago server and facilitates communication, listens for events, and manages @@ -38,7 +35,7 @@ export class Client { #status: ConnectionStatus = CONNECTION_STATUS.DISCONNECTED; #emitter = new EventEmitter(); #dataManager: DataManager = new DataManager(this); - #hintManager: HintManager = new HintManager(this); + #hintManager: HintsManager = new HintsManager(this); #itemsManager: ItemsManager = new ItemsManager(this); #locationsManager: LocationsManager = new LocationsManager(this); #playersManager: PlayersManager = new PlayersManager(this); @@ -58,9 +55,9 @@ export class Client { } /** - * Get the {@link HintManager} helper object. See {@link HintManager} for additional information. + * Get the {@link HintsManager} helper object. See {@link HintsManager} for additional information. */ - public get hints(): HintManager { + public get hints(): HintsManager { return this.#hintManager; } @@ -232,7 +229,7 @@ export class Client { // Reinitialize our Managers. this.#dataManager = new DataManager(this); - this.#hintManager = new HintManager(this); + this.#hintManager = new HintsManager(this); this.#itemsManager = new ItemsManager(this); this.#locationsManager = new LocationsManager(this); this.#playersManager = new PlayersManager(this); @@ -379,10 +376,10 @@ export class Client { return string + this.players.alias(parseInt(piece.text)); case VALID_JSON_MESSAGE_TYPE.LOCATION_ID: - return string + this.locations.name(this.players.game(piece.player), parseInt(piece.text)); + return string + this.players.get(piece.player)?.location(parseInt(piece.text)); case VALID_JSON_MESSAGE_TYPE.ITEM_ID: - return string + this.items.name(this.players.game(piece.player), parseInt(piece.text)); + return string + this.players.get(piece.player)?.item(parseInt(piece.text)); default: return string + piece.text; diff --git a/src/index.ts b/src/index.ts index f8485d1..8e64f5b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,7 +13,7 @@ export * from "./consts/Permission"; export * from "./consts/PrintJSONType"; export * from "./consts/SlotType"; export * from "./managers/DataManager"; -export * from "./managers/HintManager"; +export * from "./managers/HintsManager"; export * from "./managers/ItemsManager"; export * from "./managers/LocationsManager"; export * from "./managers/PlayersManager"; @@ -42,3 +42,6 @@ export * from "./packets/SetPacket"; export * from "./packets/SetReplyPacket"; export * from "./packets/StatusUpdatePacket"; export * from "./packets/SyncPacket"; + +// Export types. +export * from "./types"; diff --git a/src/managers/DataManager.ts b/src/managers/DataManager.ts index 0eea1c5..64bd4cd 100644 --- a/src/managers/DataManager.ts +++ b/src/managers/DataManager.ts @@ -2,14 +2,13 @@ import { Client } from "../Client"; import { SetOperationsBuilder } from "../builders/SetOperationsBuilder"; import { SERVER_PACKET_TYPE } from "../consts/CommandPacketType"; import { PERMISSION, Permissions } from "../consts/Permission"; +import { SLOT_TYPE } from "../consts/SlotType"; import { ConnectedPacket } from "../packets/ConnectedPacket"; import { DataPackagePacket } from "../packets/DataPackagePacket"; import { RoomInfoPacket } from "../packets/RoomInfoPacket"; import { RoomUpdatePacket } from "../packets/RoomUpdatePacket"; import { SetReplyPacket } from "../packets/SetReplyPacket"; -import { GamePackage } from "../types/GamePackage"; -import { NetworkSlot } from "../types/NetworkSlot"; -import { Player } from "../types/Player"; +import { GamePackage, NetworkSlot, Player } from "../types"; /** * Manages and watches for events regarding session data and the data package. Most other mangers use this information @@ -18,7 +17,7 @@ import { Player } from "../types/Player"; export class DataManager { #client: Client; #dataPackage = new Map(); - #players = new Map(); + #players: Player[] = []; #games: string[] = []; #hintCost = 0; #hintPoints = 0; @@ -55,9 +54,9 @@ export class DataManager { } /** - * Returns a map of all `players`, keyed by player id. + * Returns an array of all `players`, keyed by player id. */ - public get players(): ReadonlyMap { + public get players(): ReadonlyArray { return this.#players; } @@ -184,16 +183,35 @@ export class DataManager { } #onConnected(packet: ConnectedPacket): void { + // Archipelago player for slot 0 is implicitly the server. + const players: Player[] = [ + { + name: "Archipelago", + slot: 0, + game: "Archipelago", + team: 0, + type: SLOT_TYPE.SPECTATOR, + alias: "Archipelago", + group_members: [], + item: (id) => this.#client.items.name(0, id), + location: (id) => this.#client.locations.name(0, id), + }, + ]; + + // Add all players. for (const networkPlayer of packet.players) { const player: Player = { ...networkPlayer, // Can always assume this info will be filled out. ...(packet.slot_info[networkPlayer.slot] as NetworkSlot), + item: (id) => this.#client.items.name(networkPlayer.slot, id), + location: (id) => this.#client.locations.name(networkPlayer.slot, id), }; - this.#players.set(player.slot, player); + players[player.slot] = player; } + this.#players = players; this.#slot = packet.slot; this.#team = packet.team; this.#hintPoints = packet.hint_points ?? 0; @@ -224,9 +242,8 @@ export class DataManager { } if (packet.players) { - for (const networkPlayer of packet.players) { - const player = this.#players.get(networkPlayer.slot) as Player; - this.#players.set(player.slot, { ...player, ...networkPlayer }); + for (const player of packet.players) { + this.#players[player.slot] = { ...this.#players[player.slot], ...player } as Player; } } } diff --git a/src/managers/HintManager.ts b/src/managers/HintsManager.ts similarity index 96% rename from src/managers/HintManager.ts rename to src/managers/HintsManager.ts index 362c932..ecd5494 100644 --- a/src/managers/HintManager.ts +++ b/src/managers/HintsManager.ts @@ -2,13 +2,13 @@ import { Client } from "../Client"; import { CLIENT_PACKET_TYPE, SERVER_PACKET_TYPE } from "../consts/CommandPacketType"; import { RetrievedPacket } from "../packets/RetrievedPacket"; import { SetReplyPacket } from "../packets/SetReplyPacket"; -import { Hint } from "../types/Hint"; +import { Hint } from "../types"; /** * Manages and watches for hint events to this player slot and provides helper functions to make working with hints * easier. */ -export class HintManager { +export class HintsManager { #client: Client; #hints: Hint[] = []; diff --git a/src/managers/ItemsManager.ts b/src/managers/ItemsManager.ts index ecce5d9..0d38cd4 100644 --- a/src/managers/ItemsManager.ts +++ b/src/managers/ItemsManager.ts @@ -1,10 +1,15 @@ import { Client } from "../Client"; +import { CLIENT_PACKET_TYPE, SERVER_PACKET_TYPE } from "../consts/CommandPacketType"; +import { ReceivedItemsPacket } from "../packets/ReceivedItemsPacket"; +import { NetworkItem } from "../types"; /** * Manages and watches for events regarding item data and provides helper functions to make working with items easier. */ export class ItemsManager { #client: Client; + #items: NetworkItem[] = []; + #index = 0; /** * Creates a new {@link ItemsManager} and sets up events on the {@link Client} to listen for to start @@ -14,55 +19,63 @@ export class ItemsManager { */ public constructor(client: Client) { this.#client = client; + this.#client.addListener(SERVER_PACKET_TYPE.RECEIVED_ITEMS, this.#onReceivedItems.bind(this)); } + /** + * Returns the `name` of a given item `id`. + * + * @param player The `id` of the player this item belongs to. + * @param id The `id` of this item. + * @returns Returns the name of the item or `Unknown Item: ` if item or player is not in data. + * + * @throws Throws an error if `player` or `id` is not a safe integer. + */ + public name(player: number, id: number): string; + /** * Returns the `name` of a given item `id`. * * @param game The `name` of the game this item belongs to. * @param id The `id` of this item. - * @returns Returns the name of the item or `Unknown Item: ` if item or game is not in data package. + * @returns Returns the name of the item or `Unknown Item: ` if item or player is not in data. * * @throws Throws an error if `id` is not a safe integer. */ - public name(game: string, id: number): string { + public name(game: string, id: number): string; + + public name(value: string | number, id: number): string { if (isNaN(id) || !Number.isSafeInteger(id)) { throw new Error(`'id' must be a safe integer. Received: ${id}`); } - const gameData = this.#client.data.package.get(game); - if (!gameData) { - return `Unknown ${game} Item: ${id}`; - } + let game: string; + if (typeof value === "string") { + game = value; + } else { + if (isNaN(value) || !Number.isSafeInteger(value)) { + throw new Error(`'player' must be a safe integer. Received: ${id}`); + } - const name = gameData.item_id_to_name[id]; - if (!name) { - return `Unknown ${game} Item: ${id}`; - } + const player = this.#client.players.get(value); + if (!player) { + return `Unknown Item: ${id}`; + } - return name; - } + game = player.game; + } - /** - * Returns the `id` of a given item `name`. - * - * @param game The `name` of the game this item belongs to. - * @param name The `name` of this item. - * - * @throws Throws an error if unable to find the `id` for an item or unable to find game in data package. - */ - public id(game: string, name: string): number { const gameData = this.#client.data.package.get(game); if (!gameData) { - throw new Error(`Unknown game: ${game}`); + return `Unknown Item: ${id}`; } - const id = gameData.item_name_to_id[name]; - if (!id) { - throw new Error(`Unknown item name: ${name}`); + const name = gameData.item_id_to_name[id]; + if (!name) { + return `Unknown Item: ${id}`; } - return id; + return name; } /** @@ -76,7 +89,7 @@ export class ItemsManager { public group(game: string, name: string): string[] { const gameData = this.#client.data.package.get(game); if (!gameData) { - throw new Error(`Unknown game: ${game}`); + throw new Error(`Unknown Game: ${game}`); } const group = gameData.item_name_groups[name]; @@ -86,4 +99,34 @@ export class ItemsManager { return group; } + + /** + * Returns the current item index. If this value is larger than expected, that means new items have been received. + */ + public get index(): number { + return this.#index; + } + + /** + * Returns an array of all items that have been received. + */ + public get received(): ReadonlyArray { + return this.#items; + } + + #onReceivedItems(packet: ReceivedItemsPacket): void { + // De-sync occurred! Attempt a re-sync before continuing. + if (packet.index > this.#index) { + this.#index = 0; + this.#client.send({ + cmd: CLIENT_PACKET_TYPE.SYNC, + }); + return; + } + + let index = packet.index; + for (const item of packet.items) { + this.#items[index++] = item; + } + } } diff --git a/src/managers/LocationsManager.ts b/src/managers/LocationsManager.ts index 3779209..a28cf76 100644 --- a/src/managers/LocationsManager.ts +++ b/src/managers/LocationsManager.ts @@ -65,54 +65,60 @@ export class LocationsManager { }); } + /** + * Returns the `name` of a given location `id`. + * + * @param player The `id` of the player this location belongs to. + * @param id The `id` of this location. + * @returns Returns the name of the location or `Unknown Location: ` if location or player is not in data. + * + * @throws Throws an error if `player` or `id` is not a safe integer. + */ + public name(player: number, id: number): string; + /** * Returns the `name` of a given location `id`. * * @param game The `name` of the game this location belongs to. * @param id The `id` of this location. - * @returns Returns the name of the location or `Unknown Location: ` if location or game is not in data - * package. + * @returns Returns the name of the location or `Unknown Location: ` if location or player is not in data. * * @throws Throws an error if `id` is not a safe integer. */ - public name(game: string, id: number): string { + public name(game: string, id: number): string; + + public name(value: string | number, id: number): string { if (isNaN(id) || !Number.isSafeInteger(id)) { throw new Error(`'id' must be a safe integer. Received: ${id}`); } - const gameData = this.#client.data.package.get(game); - if (!gameData) { - return `Unknown ${game} Location: ${id}`; - } + let game: string; + if (typeof value === "string") { + game = value; + } else { + if (isNaN(value) || !Number.isSafeInteger(value)) { + throw new Error(`'player' must be a safe integer. Received: ${id}`); + } - const name = gameData.location_id_to_name[id]; - if (!name) { - return `Unknown ${game} Location: ${id}`; - } + const player = this.#client.players.get(value); + if (!player) { + return `Unknown Location: ${id}`; + } - return name; - } + game = player.game; + } - /** - * Returns the `id` of a given location `name`. - * - * @param game The `name` of the game this location belongs to. - * @param name The `name` of this location. - * - * @throws Throws an error if unable to find the `id` for a location or unable to find game in data package. - */ - public id(game: string, name: string): number { const gameData = this.#client.data.package.get(game); if (!gameData) { - throw new Error(`Unknown game: ${game}`); + return `Unknown Location: ${id}`; } - const id = gameData.location_name_to_id[name]; - if (!id) { - throw new Error(`Unknown location name: ${name}`); + const name = gameData.location_id_to_name[id]; + if (!name) { + return `Unknown Location: ${id}`; } - return id; + return name; } /** @@ -126,7 +132,7 @@ export class LocationsManager { public group(game: string, name: string): string[] { const gameData = this.#client.data.package.get(game); if (!gameData) { - throw new Error(`Unknown game: ${game}`); + throw new Error(`Unknown Game: ${game}`); } const group = gameData.location_name_groups[name]; diff --git a/src/managers/PlayersManager.ts b/src/managers/PlayersManager.ts index 256dfb5..a4c350e 100644 --- a/src/managers/PlayersManager.ts +++ b/src/managers/PlayersManager.ts @@ -1,4 +1,5 @@ import { Client } from "../Client"; +import { Player } from "../types"; /** * Manages and watches for events regarding player data and provides helper functions to make working with players @@ -17,6 +18,20 @@ export class PlayersManager { this.#client = client; } + /** + * Returns an array of all `players`, keyed by player id. + */ + public get all(): ReadonlyArray { + return this.#client.data.players; + } + + /** + * Returns a specific `player` by player id. Returns undefined if player does not exist. + */ + public get(id: number): Player | undefined { + return this.#client.data.players[id]; + } + /** * Returns the `name` of a given player `id`. Returns "Unknown Player #" if player does not exist in the room. * @@ -32,7 +47,7 @@ export class PlayersManager { return "Archipelago"; } - const name = this.#client.data.players.get(id)?.name; + const name = this.get(id)?.name; if (!name) { throw new Error(`Unable to find player by id: ${id}`); } @@ -55,7 +70,7 @@ export class PlayersManager { return "Archipelago"; } - const alias = this.#client.data.players.get(id)?.alias; + const alias = this.get(id)?.alias; if (!alias) { throw new Error(`Unable to find player by id: ${id}`); } @@ -78,7 +93,7 @@ export class PlayersManager { return "Archipelago"; } - const game = this.#client.data.players.get(id)?.game; + const game = this.get(id)?.game; if (!game) { throw new Error(`Unable to find player by id: ${id}`); } @@ -93,7 +108,7 @@ export class PlayersManager { * @param id The slot `id` of a {@link SlotType.GROUP} player. */ public members(id: number): number[] { - const members = this.#client.data.players.get(id)?.group_members; + const members = this.get(id)?.group_members; if (!members) { return []; } diff --git a/src/types/Player.ts b/src/types/Player.ts index 1e40786..e26f34c 100644 --- a/src/types/Player.ts +++ b/src/types/Player.ts @@ -2,6 +2,14 @@ import { NetworkPlayer } from "./NetworkPlayer"; import { NetworkSlot } from "./NetworkSlot"; /** - * An object that contains information about a player. Combination of {@link NetworkPlayer} and {@link NetworkSlot}. + * An object that contains information about a player. Combination of {@link NetworkPlayer}, {@link NetworkSlot} and + * some helper functions. */ -export type Player = NetworkPlayer & NetworkSlot; +export type Player = NetworkPlayer & + NetworkSlot & { + /** Helper function for looking up an item name for this player. */ + item: (id: number) => string; + + /** Helper function for looking up a location name for this player. */ + location: (id: number) => string; + }; diff --git a/src/types/index.ts b/src/types/index.ts index 7e498a4..2433347 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -9,6 +9,7 @@ export * from "./JSONSerializableData"; export * from "./NetworkItem"; export * from "./NetworkPlayer"; export * from "./NetworkSlot"; +export * from "./NetworkVersion"; export * from "./ObjectValues"; export * from "./Player"; export * from "./SlotData";