Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@corsaircoalition/sergeant-socket

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@corsaircoalition/sergeant-socket - npm Package Compare versions

Comparing version 2.0.0 to 2.1.0

804

out/app.js

@@ -10,346 +10,506 @@ import io from 'socket.io-client';

export class App {
botId;
gameConfig;
socket;
keyspace;
gamePhase = "initializing";
gameType;
gameState;
replay_id = "";
queueNumPlayers = 0;
forceStartSet = false;
customOptionsSet = false;
deconflicted = false;
moveCount = 0;
constructor(gameConfig, redisConfig) {
this.botId = gameConfig.BOT_ID_PREFIX + '-' + hashUserId(gameConfig.userId);
this.gameConfig = gameConfig;
this.initializeSocketConnection();
this.initializeRedisConnection(redisConfig).then(() => {
this.deconflict();
Object.defineProperty(this, "botId", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
}
initializeSocketConnection = () => {
this.socket = io(this.gameConfig.GAME_SERVER_URL, {
rejectUnauthorized: false,
Object.defineProperty(this, "gameConfig", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.socket.on('connect', this.handleConnect);
this.socket.on("error", (error) => Log.stderr(`[socket.io] ${error}`));
this.socket.on("connect_error", (error) => Log.stderr(`[socket.io] ${error}`));
this.socket.on('error_set_username', this.handleErrorSetUsername);
this.socket.on('queue_update', this.handleQueueUpdate);
this.socket.on('game_start', this.handleGameStart);
this.socket.on('game_won', this.handleGameWon);
this.socket.on('game_lost', this.handleGameLost);
this.socket.on('game_update', this.handleGameUpdate);
this.socket.on('disconnect', this.handleDisconnect);
};
initializeRedisConnection = async (redisConfig) => {
Redis.initilize(redisConfig);
Redis.subscribe(this.botId, "action", this.handleAction);
await Redis.subscribe(this.botId, "command", this.handleCommand).then((channel) => {
Log.stdout('[Redis] subscribed: ' + channel);
Object.defineProperty(this, "socket", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
};
handleCommand = (command) => {
Log.stdout(`[command] ${JSON.stringify(command)}`);
if (command.join) {
this.joinGame(command.join);
return;
}
if (command.leave) {
if (this.gamePhase === "playing" || this.gamePhase === "joined_lobby") {
this.leaveGame();
Object.defineProperty(this, "keyspace", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "gamePhase", {
enumerable: true,
configurable: true,
writable: true,
value: "initializing"
});
Object.defineProperty(this, "gameType", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "gameState", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "replay_id", {
enumerable: true,
configurable: true,
writable: true,
value: ""
});
Object.defineProperty(this, "queueNumPlayers", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "forceStartSet", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "customOptionsSet", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "deconflicted", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "moveCount", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "initializeSocketConnection", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
this.socket = io(this.gameConfig.GAME_SERVER_URL, {
rejectUnauthorized: false,
});
this.socket.on('connect', this.handleConnect);
this.socket.on("error", (error) => Log.stderr(`[socket.io] ${error}`));
this.socket.on("connect_error", (error) => Log.stderr(`[socket.io] ${error}`));
this.socket.on('error_set_username', this.handleErrorSetUsername);
this.socket.on('queue_update', this.handleQueueUpdate);
this.socket.on('game_start', this.handleGameStart);
this.socket.on('game_won', this.handleGameWon);
this.socket.on('game_lost', this.handleGameLost);
this.socket.on('game_update', this.handleGameUpdate);
this.socket.on('disconnect', this.handleDisconnect);
}
else {
Log.stderr(`[leave] not in a game`);
});
Object.defineProperty(this, "initializeRedisConnection", {
enumerable: true,
configurable: true,
writable: true,
value: async (redisConfig) => {
Redis.initilize(redisConfig);
Redis.subscribe(this.botId, "action", this.handleAction);
await Redis.subscribe(this.botId, "command", this.handleCommand).then((channel) => {
Log.stdout('[Redis] subscribed: ' + channel);
});
}
return;
}
if (command.options) {
if (!command.options.customGameSpeed)
return;
this.gameConfig.customGameSpeed = command.options.customGameSpeed;
if (this.gamePhase === "joined_lobby") {
this.customOptionsSet = false;
later(100).then(() => {
this.setCustomOptions();
});
Object.defineProperty(this, "handleCommand", {
enumerable: true,
configurable: true,
writable: true,
value: (command) => {
Log.stdout(`[command] ${JSON.stringify(command)}`);
if (command.join) {
this.joinGame(command.join);
return;
}
if (command.leave) {
if (this.gamePhase === "playing" || this.gamePhase === "joined_lobby") {
this.leaveGame();
}
else {
Log.stderr(`[leave] not in a game`);
}
return;
}
if (command.options) {
if (!command.options.customGameSpeed)
return;
this.gameConfig.customGameSpeed = command.options.customGameSpeed;
if (this.gamePhase === "joined_lobby") {
this.customOptionsSet = false;
later(100).then(() => {
this.setCustomOptions();
});
}
else {
Log.stderr(`[options] not in lobby`);
}
return;
}
if (command.forceStart) {
this.forceStartSet = false;
setTimeout(this.setForceStart, 200);
return;
}
if (command.status) {
Redis.publish(this.botId, "state", this.getCurrentState());
return;
}
}
});
Object.defineProperty(this, "getCurrentState", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
if (!this.socket.connected) {
return { disconnected: 'unknown' };
}
switch (this.gamePhase) {
case "initializing":
return { disconnected: 'initializing' };
case "connected":
return { connected: this.gameConfig.username };
case "joined_lobby":
return {
joined: {
gameType: this.gameType,
gameId: this.gameConfig.customGameId
}
};
case "playing":
return { playing: true };
}
}
});
Object.defineProperty(this, "handleAction", {
enumerable: true,
configurable: true,
writable: true,
value: (data) => {
if (this.gamePhase !== "playing") {
Log.stderr(`[action] not in game`);
return;
}
if (data.interrupt) {
this.socket.emit('clear_moves');
}
Log.debug("[action]", JSON.stringify(data));
for (let i = 0; i < data.actions.length; i++) {
const action = data.actions[i];
this.socket.emit('attack', action.start, action.end, action.is50);
this.moveCount++;
}
}
});
Object.defineProperty(this, "handleConnect", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
Log.stdout(`[connected] ${this.gameConfig.username}`);
Log.stdout(`READY TO PLAY`);
this.gamePhase = "connected";
Redis.publish(this.botId, "state", { connected: this.gameConfig.username });
if (this.gameConfig.setUsername) {
this.socket.emit('set_username', this.gameConfig.userId, this.gameConfig.username);
Log.debug(`sent: set_username, ${this.gameConfig.userId}, ${this.gameConfig.username}`);
}
}
});
Object.defineProperty(this, "handleDisconnect", {
enumerable: true,
configurable: true,
writable: true,
value: (reason) => {
this.gamePhase = "initializing";
Redis.publish(this.botId, "state", { disconnected: reason });
switch (reason) {
case 'io server disconnect':
Log.stderr("disconnected: " + reason);
process.exit(3);
case 'io client disconnect':
process.exit(0);
default:
Log.stderr("disconnected: " + reason);
}
}
});
Object.defineProperty(this, "handleErrorSetUsername", {
enumerable: true,
configurable: true,
writable: true,
value: (message) => {
if (message === '') {
Log.stdout(`[set_username] username set to ${this.gameConfig.username}`);
return;
}
Log.stdout(`[error_set_username] ${message}`);
}
});
Object.defineProperty(this, "handleGameStart", {
enumerable: true,
configurable: true,
writable: true,
value: async (data) => {
this.replay_id = data.replay_id;
this.keyspace = `${this.botId}-${this.replay_id}`;
this.moveCount = 0;
Log.stdout(`[game_start] replay: ${this.replay_id}, users: ${data.usernames}`);
Redis.publish(this.botId, "state", { game_start: data });
this.gameState = new GameState(data);
Log.debug(`[game_start] setKeys: ${this.keyspace}`);
Redis.setKeys(this.keyspace, data);
Log.debug(`[game_start] listPush: ${this.botId}-${"replays"} ${this.replay_id}`);
Redis.listPush(this.botId, "replays", this.replay_id);
for (let i = 0; i < this.gameConfig.warCry.length; i++) {
later(random(i * 3000, (i + 1) * 3000)).then(() => {
this.socket.emit('chat_message', data.chat_room, this.gameConfig.warCry[i]);
Log.debug(`sent: [chat_message] ${this.gameConfig.warCry[i]}`);
});
}
this.gamePhase = "playing";
}
});
Object.defineProperty(this, "handleGameUpdate", {
enumerable: true,
configurable: true,
writable: true,
value: async (data) => {
if (data.turn > this.gameConfig.MAX_TURNS) {
Log.stdout(`[game_update] ${this.replay_id}, turn: ${data.turn}, max turns reached`);
this.leaveGame();
return null;
}
Redis.publish(this.botId, "gameUpdate", data);
this.gameState.update(data);
if (data.turn === 1) {
Log.debug(`[game_update] setKeys: ${this.keyspace}`);
await Redis.setKeys(this.keyspace, {
["width"]: this.gameState.width,
["height"]: this.gameState.height,
["size"]: this.gameState.size,
["ownGeneral"]: this.gameState.ownGeneral,
});
}
Log.debug(`[game_update] setKeys: ${this.keyspace}`);
await Redis.setKeys(this.keyspace, {
["turn"]: this.gameState.turn,
["cities"]: this.gameState.cities,
["discoveredTiles"]: this.gameState.discoveredTiles,
["armies"]: this.gameState.armies,
["terrain"]: this.gameState.terrain,
["enemyGeneral"]: this.gameState.enemyGeneral,
["ownTiles"]: Array.from(this.gameState.ownTiles.entries()),
["enemyTiles"]: Array.from(this.gameState.enemyTiles.entries()),
});
let maxArmyOnTile = 0;
for (let [, value] of this.gameState.ownTiles) {
if (value > maxArmyOnTile) {
maxArmyOnTile = value;
}
}
Log.debug(`[game_update] listPush: ${this.keyspace}-${"scores"} ${data.scores}`);
Log.debug(`[game_update] listPush: ${this.keyspace}-${"maxArmyOnTile"} ${maxArmyOnTile}`);
Log.debug(`[game_update] listPush: ${this.keyspace}-${"moveCount"} ${this.moveCount}`);
Redis.listPush(this.keyspace, "scores", data.scores);
Redis.listPush(this.keyspace, "maxArmyOnTile", maxArmyOnTile);
Redis.listPush(this.keyspace, "moveCount", this.moveCount);
return Redis.publish(this.botId, "turn", {
turn: data.turn,
replay_id: this.replay_id
});
}
else {
Log.stderr(`[options] not in lobby`);
});
Object.defineProperty(this, "handleGameLost", {
enumerable: true,
configurable: true,
writable: true,
value: (data) => {
Log.stdout(`[game_lost] ${this.replay_id}, killer: ${this.gameState.usernames[data.killer]}`);
Redis.publish(this.botId, "state", {
game_lost: {
replay_id: this.replay_id,
killer: data.killer,
killer_name: this.gameState.usernames[data.killer]
}
});
this.leaveGame();
}
return;
}
if (command.forceStart) {
this.forceStartSet = false;
setTimeout(this.setForceStart, 200);
return;
}
if (command.status) {
Redis.publish(this.botId, "state", this.getCurrentState());
return;
}
};
getCurrentState = () => {
if (!this.socket.connected) {
return { disconnected: 'unknown' };
}
switch (this.gamePhase) {
case "initializing":
return { disconnected: 'initializing' };
case "connected":
return { connected: this.gameConfig.username };
case "joined_lobby":
return {
joined: {
gameType: this.gameType,
gameId: this.gameConfig.customGameId
});
Object.defineProperty(this, "handleGameWon", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
Log.stdout(`[game_won] ${this.replay_id}`);
Redis.publish(this.botId, "state", {
game_won: {
replay_id: this.replay_id
}
};
case "playing":
return { playing: true };
}
};
handleAction = (data) => {
if (this.gamePhase !== "playing") {
Log.stderr(`[action] not in game`);
return;
}
if (data.interrupt) {
this.socket.emit('clear_moves');
}
Log.debug("[action]", JSON.stringify(data));
for (let i = 0; i < data.actions.length; i++) {
const action = data.actions[i];
this.socket.emit('attack', action.start, action.end, action.is50);
this.moveCount++;
}
};
handleConnect = () => {
Log.stdout(`[connected] ${this.gameConfig.username}`);
Log.stdout(`READY TO PLAY`);
this.gamePhase = "connected";
Redis.publish(this.botId, "state", { connected: this.gameConfig.username });
if (this.gameConfig.setUsername) {
this.socket.emit('set_username', this.gameConfig.userId, this.gameConfig.username);
Log.debug(`sent: set_username, ${this.gameConfig.userId}, ${this.gameConfig.username}`);
}
};
handleDisconnect = (reason) => {
this.gamePhase = "initializing";
Redis.publish(this.botId, "state", { disconnected: reason });
switch (reason) {
case 'io server disconnect':
Log.stderr("disconnected: " + reason);
process.exit(3);
case 'io client disconnect':
process.exit(0);
default:
Log.stderr("disconnected: " + reason);
}
};
handleErrorSetUsername = (message) => {
if (message === '') {
Log.stdout(`[set_username] username set to ${this.gameConfig.username}`);
return;
}
Log.stdout(`[error_set_username] ${message}`);
};
handleGameStart = async (data) => {
this.replay_id = data.replay_id;
this.keyspace = `${this.botId}-${this.replay_id}`;
this.moveCount = 0;
Log.stdout(`[game_start] replay: ${this.replay_id}, users: ${data.usernames}`);
Redis.publish(this.botId, "state", { game_start: data });
this.gameState = new GameState(data);
Log.debug(`[game_start] setKeys: ${this.keyspace}`);
Redis.setKeys(this.keyspace, data);
Log.debug(`[game_start] listPush: ${this.botId}-${"replays"} ${this.replay_id}`);
Redis.listPush(this.botId, "replays", this.replay_id);
for (let i = 0; i < this.gameConfig.warCry.length; i++) {
later(random(i * 3000, (i + 1) * 3000)).then(() => {
this.socket.emit('chat_message', data.chat_room, this.gameConfig.warCry[i]);
Log.debug(`sent: [chat_message] ${this.gameConfig.warCry[i]}`);
});
}
this.gamePhase = "playing";
};
handleGameUpdate = async (data) => {
if (data.turn > this.gameConfig.MAX_TURNS) {
Log.stdout(`[game_update] ${this.replay_id}, turn: ${data.turn}, max turns reached`);
this.leaveGame();
return null;
}
Redis.publish(this.botId, "gameUpdate", data);
this.gameState.update(data);
if (data.turn === 1) {
Log.debug(`[game_update] setKeys: ${this.keyspace}`);
await Redis.setKeys(this.keyspace, {
["width"]: this.gameState.width,
["height"]: this.gameState.height,
["size"]: this.gameState.size,
["ownGeneral"]: this.gameState.ownGeneral,
});
}
Log.debug(`[game_update] setKeys: ${this.keyspace}`);
await Redis.setKeys(this.keyspace, {
["turn"]: this.gameState.turn,
["cities"]: this.gameState.cities,
["discoveredTiles"]: this.gameState.discoveredTiles,
["armies"]: this.gameState.armies,
["terrain"]: this.gameState.terrain,
["enemyGeneral"]: this.gameState.enemyGeneral,
["ownTiles"]: Array.from(this.gameState.ownTiles.entries()),
["enemyTiles"]: Array.from(this.gameState.enemyTiles.entries()),
});
this.leaveGame();
}
});
let maxArmyOnTile = 0;
for (let [, value] of this.gameState.ownTiles) {
if (value > maxArmyOnTile) {
maxArmyOnTile = value;
Object.defineProperty(this, "handleQueueUpdate", {
enumerable: true,
configurable: true,
writable: true,
value: (data) => {
if (!data.isForcing) {
this.forceStartSet = false;
setTimeout(this.setForceStart, 1000);
}
if (this.gameType === "custom"
&& data.usernames[0] === this.gameConfig.username
&& data.numPlayers != this.queueNumPlayers
&& data.options.game_speed != this.gameConfig.customGameSpeed) {
this.customOptionsSet = false;
later(100).then(() => {
this.setCustomOptions();
});
}
this.queueNumPlayers = data.numPlayers;
}
}
Log.debug(`[game_update] listPush: ${this.keyspace}-${"scores"} ${data.scores}`);
Log.debug(`[game_update] listPush: ${this.keyspace}-${"maxArmyOnTile"} ${maxArmyOnTile}`);
Log.debug(`[game_update] listPush: ${this.keyspace}-${"moveCount"} ${this.moveCount}`);
Redis.listPush(this.keyspace, "scores", data.scores);
Redis.listPush(this.keyspace, "maxArmyOnTile", maxArmyOnTile);
Redis.listPush(this.keyspace, "moveCount", this.moveCount);
return Redis.publish(this.botId, "turn", {
turn: data.turn,
replay_id: this.replay_id
});
};
handleGameLost = (data) => {
Log.stdout(`[game_lost] ${this.replay_id}, killer: ${this.gameState.usernames[data.killer]}`);
Redis.publish(this.botId, "state", {
game_lost: {
replay_id: this.replay_id,
killer: data.killer,
killer_name: this.gameState.usernames[data.killer]
Object.defineProperty(this, "joinGame", {
enumerable: true,
configurable: true,
writable: true,
value: (data) => {
this.gameType = data.gameType;
switch (data.gameType) {
case "ffa":
this.socket.emit('play', this.gameConfig.userId);
Log.stdout('[joined] FFA');
break;
case "1v1":
this.socket.emit('join_1v1', this.gameConfig.userId);
Log.stdout('[joined] 1v1');
break;
case "custom":
if (data.gameId) {
this.gameConfig.customGameId = data.gameId;
}
this.socket.emit('join_private', data.gameId, this.gameConfig.userId, process.env['AUTH_TOKEN']);
setTimeout(this.setCustomOptions, 100);
setTimeout(this.setForceStart, 2000);
Log.stdout(`[joined] custom: ${this.gameConfig.customGameId}`);
break;
default:
Log.stderr(`[join] invalid gameType: ${data.gameType}`);
return;
}
Redis.publish(this.botId, "state", { joined: data });
this.gamePhase = "joined_lobby";
}
});
this.leaveGame();
};
handleGameWon = () => {
Log.stdout(`[game_won] ${this.replay_id}`);
Redis.publish(this.botId, "state", {
game_won: {
replay_id: this.replay_id
Object.defineProperty(this, "leaveGame", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
if (this.gamePhase == "joined_lobby") {
this.socket.emit('cancel');
Log.debug('sent: cancel');
}
else if (this.gamePhase == "playing") {
this.socket.emit('leave_game');
Log.debug('sent: leave_game');
}
else {
Log.stderr(`[leaveGame] Invalid Request, Current State: ${this.gamePhase}`);
return;
}
Redis.publish(this.botId, "state", { left: true });
this.gamePhase = "connected";
this.forceStartSet = false;
this.customOptionsSet = false;
}
});
this.leaveGame();
};
handleQueueUpdate = (data) => {
if (!data.isForcing) {
this.forceStartSet = false;
setTimeout(this.setForceStart, 1000);
}
if (this.gameType === "custom"
&& data.usernames[0] === this.gameConfig.username
&& data.numPlayers != this.queueNumPlayers
&& data.options.game_speed != this.gameConfig.customGameSpeed) {
this.customOptionsSet = false;
later(100).then(() => {
this.setCustomOptions();
});
}
this.queueNumPlayers = data.numPlayers;
};
joinGame = (data) => {
this.gameType = data.gameType;
switch (data.gameType) {
case "ffa":
this.socket.emit('play', this.gameConfig.userId);
Log.stdout('[joined] FFA');
break;
case "1v1":
this.socket.emit('join_1v1', this.gameConfig.userId);
Log.stdout('[joined] 1v1');
break;
case "custom":
if (data.gameId) {
this.gameConfig.customGameId = data.gameId;
Object.defineProperty(this, "setForceStart", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
if (!this.forceStartSet) {
this.forceStartSet = true;
this.socket.emit('set_force_start', this.gameConfig.customGameId, true);
Log.debug('sent: set_force_start');
}
this.socket.emit('join_private', data.gameId, this.gameConfig.userId, process.env['AUTH_TOKEN']);
setTimeout(this.setCustomOptions, 100);
setTimeout(this.setForceStart, 2000);
Log.stdout(`[joined] custom: ${this.gameConfig.customGameId}`);
break;
default:
Log.stderr(`[join] invalid gameType: ${data.gameType}`);
return;
}
Redis.publish(this.botId, "state", { joined: data });
this.gamePhase = "joined_lobby";
};
leaveGame = () => {
if (this.gamePhase == "joined_lobby") {
this.socket.emit('cancel');
Log.debug('sent: cancel');
}
else if (this.gamePhase == "playing") {
this.socket.emit('leave_game');
Log.debug('sent: leave_game');
}
else {
Log.stderr(`[leaveGame] Invalid Request, Current State: ${this.gamePhase}`);
return;
}
Redis.publish(this.botId, "state", { left: true });
this.gamePhase = "connected";
this.forceStartSet = false;
this.customOptionsSet = false;
};
setForceStart = () => {
if (!this.forceStartSet) {
this.forceStartSet = true;
this.socket.emit('set_force_start', this.gameConfig.customGameId, true);
Log.debug('sent: set_force_start');
}
};
setCustomOptions = () => {
if (this.gameType != "custom")
return;
if (!this.customOptionsSet) {
this.customOptionsSet = true;
this.socket.emit('set_custom_options', this.gameConfig.customGameId, {
"game_speed": this.gameConfig.customGameSpeed
});
Log.debug('sent: set_custom_options');
}
};
deconflict = async () => {
if (this.deconflicted)
return;
this.deconflicted = true;
let countResponses = 0;
let startPing = Date.now();
let handlePing = (message) => {
if (message === MESSAGE.PING) {
Redis.publish(this.botId, "deconflict", MESSAGE.PONG);
}
else if (message === MESSAGE.PONG) {
countResponses++;
let ping = Date.now() - startPing;
if (countResponses === 2 && ping < 10000) {
Log.stderr("Redis channel conflict. Select a unique userId and try again.");
process.exit(4);
});
Object.defineProperty(this, "setCustomOptions", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
if (this.gameType != "custom")
return;
if (!this.customOptionsSet) {
this.customOptionsSet = true;
this.socket.emit('set_custom_options', this.gameConfig.customGameId, {
"game_speed": this.gameConfig.customGameSpeed
});
Log.debug('sent: set_custom_options');
}
}
};
await Redis.subscribe(this.botId, "deconflict", handlePing);
Redis.publish(this.botId, "deconflict", MESSAGE.PING);
};
quit = async () => {
switch (this.gamePhase) {
case "joined_lobby":
case "playing":
this.socket.emit('leave_game');
Log.debug('sent: leave_game');
}
await this.socket.disconnect();
await Redis.quit();
};
});
Object.defineProperty(this, "deconflict", {
enumerable: true,
configurable: true,
writable: true,
value: async () => {
if (this.deconflicted)
return;
this.deconflicted = true;
let countResponses = 0;
let startPing = Date.now();
let handlePing = (message) => {
if (message === MESSAGE.PING) {
Redis.publish(this.botId, "deconflict", MESSAGE.PONG);
}
else if (message === MESSAGE.PONG) {
countResponses++;
let ping = Date.now() - startPing;
if (countResponses === 2 && ping < 10000) {
Log.stderr("Redis channel conflict. Select a unique userId and try again.");
process.exit(4);
}
}
};
await Redis.subscribe(this.botId, "deconflict", handlePing);
Redis.publish(this.botId, "deconflict", MESSAGE.PING);
}
});
Object.defineProperty(this, "quit", {
enumerable: true,
configurable: true,
writable: true,
value: async () => {
switch (this.gamePhase) {
case "joined_lobby":
case "playing":
this.socket.emit('leave_game');
Log.debug('sent: leave_game');
}
await this.socket.disconnect();
await Redis.quit();
}
});
this.botId = gameConfig.BOT_ID_PREFIX + '-' + hashUserId(gameConfig.userId);
this.gameConfig = gameConfig;
this.initializeSocketConnection();
this.initializeRedisConnection(redisConfig).then(() => {
this.deconflict();
});
}
}
//# sourceMappingURL=app.js.map
import { patch } from './gameUtils.js';
export class GameState {
playerIndex;
replay_id;
usernames;
map = [];
turn;
width;
height;
size;
armies;
terrain;
cities = [];
ownGeneral = -1;
enemyGeneral = -1;
ownTiles = new Map();
enemyTiles = new Map();
discoveredTiles;
initialized = false;
constructor(data) {
Object.defineProperty(this, "playerIndex", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "replay_id", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "usernames", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "map", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "turn", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "width", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "height", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "size", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "armies", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "terrain", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "cities", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "ownGeneral", {
enumerable: true,
configurable: true,
writable: true,
value: -1
});
Object.defineProperty(this, "enemyGeneral", {
enumerable: true,
configurable: true,
writable: true,
value: -1
});
Object.defineProperty(this, "ownTiles", {
enumerable: true,
configurable: true,
writable: true,
value: new Map()
});
Object.defineProperty(this, "enemyTiles", {
enumerable: true,
configurable: true,
writable: true,
value: new Map()
});
Object.defineProperty(this, "discoveredTiles", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "initialized", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
this.playerIndex = data.playerIndex;

@@ -22,0 +107,0 @@ this.replay_id = data.replay_id;

{
"name": "@corsaircoalition/sergeant-socket",
"version": "2.0.0",
"version": "2.1.0",
"description": "a modular generals.io bot that implements advanced learning techniques",

@@ -8,3 +8,3 @@ "main": "out/index.js",

"dependencies": {
"@corsaircoalition/common": "^1.2.0",
"@corsaircoalition/common": "^1.3.2",
"commander": "^10.0.1",

@@ -14,4 +14,4 @@ "socket.io-client": "^4.7.2"

"devDependencies": {
"@sindresorhus/tsconfig": "^3.0.1",
"@types/node": "^18.17.1",
"@sindresorhus/tsconfig": "^4.0.0",
"@types/node": "^20.4.10",
"typescript": "^5.1.6"

@@ -18,0 +18,0 @@ },

# Sergeant Socket
A message broker that connects to generals.io via socket.io, publishes all game updates to Redis, and receives command and actions from other components on Redis.
[Generally Genius](https://corsaircoalition.github.io/) (GG) is a modular generals.io bot framework for development and analysis of game strategies and actions. [CorsairCoalition](https://corsaircoalition.github.io/) is a collection of components that form the GG framework.
## Installation
SergeantSocket is an IO module that connects to generals.io via socket.io, publishes all game updates to the Redis message broker, and receives command and actions from other components on Redis.
## Configuration
Download `config.example.json` from the [documentation repository](https://github.com/CorsairCoalition/docs) and make desired changes.
To setup other components, see the [detailed instructions](https://corsaircoalition.github.io/setup/) on the [project website](https://corsaircoalition.github.io/).
## Execution
Install and run the executable:
```sh
npm install -g @corsaircoalition/sergeant-socket
sergeant-socket config.json
```
npm install
npm run build
or run directly from npm library:
```sh
npx @corsaircoalition/sergeant-socket config.json
```
## Configuration
or use docker:
See `[config.json.example](https://github.com/CorsairCoalition/docs/blob/main/config.json.example)`.
```sh
docker run -it ./config.json:/config.json ghcr.io/corsaircoalition/sergeantsocket:latest
```

@@ -19,3 +37,11 @@ ## Usage

```
node . config.json
Usage: @corsaircoalition/sergeant-socket [options] <configFile>
a modular generals.io bot that implements advanced learning techniques
Options:
-V, --version output the version number
-d, --debug enable debugging (default: false)
-s, --set-username attempt to set username (default: false)
-h, --help display help for command
```

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc