Skip to content

Commit

Permalink
Archipelago.js 1.1.0 Changes (#190)
Browse files Browse the repository at this point in the history
  • Loading branch information
ThePhar authored Jul 9, 2023
1 parent 811d338 commit f2a4b2e
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 117 deletions.
100 changes: 69 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
`<script type="module"></script>` 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
Expand Down Expand Up @@ -135,8 +141,9 @@ Archipelago.js can also run in the browser. Here's an example that works in most
</html>
```

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

Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand Down Expand Up @@ -260,14 +277,27 @@ 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.

```ts
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.
Expand All @@ -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.

Expand Down Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
19 changes: 8 additions & 11 deletions src/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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
Expand All @@ -38,7 +35,7 @@ export class Client<TSlotData = SlotData> {
#status: ConnectionStatus = CONNECTION_STATUS.DISCONNECTED;
#emitter = new EventEmitter();
#dataManager: DataManager<TSlotData> = new DataManager<TSlotData>(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);
Expand All @@ -58,9 +55,9 @@ export class Client<TSlotData = SlotData> {
}

/**
* 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;
}

Expand Down Expand Up @@ -232,7 +229,7 @@ export class Client<TSlotData = SlotData> {

// 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);
Expand Down Expand Up @@ -379,10 +376,10 @@ export class Client<TSlotData = SlotData> {
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;
Expand Down
5 changes: 4 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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";
37 changes: 27 additions & 10 deletions src/managers/DataManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -18,7 +17,7 @@ import { Player } from "../types/Player";
export class DataManager<TSlotData> {
#client: Client<TSlotData>;
#dataPackage = new Map<string, GamePackage>();
#players = new Map<number, Player>();
#players: Player[] = [];
#games: string[] = [];
#hintCost = 0;
#hintPoints = 0;
Expand Down Expand Up @@ -55,9 +54,9 @@ export class DataManager<TSlotData> {
}

/**
* Returns a map of all `players`, keyed by player id.
* Returns an array of all `players`, keyed by player id.
*/
public get players(): ReadonlyMap<number, Player> {
public get players(): ReadonlyArray<Player> {
return this.#players;
}

Expand Down Expand Up @@ -184,16 +183,35 @@ export class DataManager<TSlotData> {
}

#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;
Expand Down Expand Up @@ -224,9 +242,8 @@ export class DataManager<TSlotData> {
}

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;
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/managers/HintManager.ts → src/managers/HintsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<unknown>;
#hints: Hint[] = [];

Expand Down
Loading

0 comments on commit f2a4b2e

Please sign in to comment.