UNPKG

@haelp/teto

Version:

A typescript-based controllable TETR.IO client.

109 lines (108 loc) 3.67 kB
import { polyfills } from "../utils/index.mjs"; /** * Manages network IGE cancelling */ export class IGEHandler { /** @hidden */ players; /** @hidden */ iid = 0; /** @hidden */ extract(data) { return JSON.parse(data); } /** @hidden */ stringify(data) { return JSON.stringify(data); } /** * Manages network IGE cancelling * @param players - list of player ids */ constructor(players){ this.players = new polyfills.Map(); players.forEach((player)=>{ this.players.set(player, this.stringify({ incoming: 0, outgoing: [] })); }); } /** * Sends a message to a player. * @param options - info on sending player * @param options.playerID - The ID of the player to send the message to. * @param options.amount - The amount of the message. * @throws {Error} If the player is not found. */ send({ playerID, amount }) { if (amount === 0) return; const player = this.players.get(playerID); const iid = ++this.iid; if (!player) throw new Error(`player not found: player with id ${playerID} not in ${[ ...this.players.keys() ].join(", ")}`); this.players.set(playerID, JSON.stringify({ incoming: JSON.parse(player).incoming, outgoing: [ ...this.extract(player).outgoing, { iid, amount } ] })); // console.log( // "send", // playerID, // Object.fromEntries( // [...this.players.entries()].map(([k, v]) => [k, this.extract(v)]) // ) // ); } /** * Receives a garbage from a player and processes it. * @param garbage - garbage object of data * @param garbage.playerID - The ID of the player sending the garbage. * @param garbage.ackiid - The IID of the last acknowledged item. * @param garbage.iid - The IID of the incoming item. * @param garbage.amount - The amount of the incoming item. * @returns The remaining amount after processing the message. * @throws {Error} If the player is not found. */ receive({ playerID, ackiid, iid, amount }) { const player = this.players.get(playerID); if (!player) throw new Error(`player not found: player with id ${playerID} not in ${[ ...this.players.keys() ].join(", ")}`); const p = this.extract(player); const incomingIID = Math.max(iid, p.incoming ?? 0); const newIGEs = []; let runningAmount = amount; p.outgoing.forEach((item)=>{ if (item.iid <= ackiid) return; const amt = Math.min(item.amount, runningAmount); item.amount -= amt; runningAmount -= amt; if (item.amount > 0) newIGEs.push(item); }); this.players.set(playerID, this.stringify({ incoming: incomingIID, outgoing: newIGEs })); // console.log( // "receive", // playerID, // Object.fromEntries( // [...this.players.entries()].map(([k, v]) => [k, this.extract(v)]) // ) // ); return runningAmount; } snapshot() { return { players: Object.fromEntries(this.players.entries()), iid: this.iid }; } fromSnapshot(snapshot) { this.players = new polyfills.Map(Object.entries(snapshot.players).map(([k, v])=>[ Number(k), v ])); this.iid = snapshot.iid; } } //# sourceMappingURL=ige.js.map