trucoshi 0.2.18 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/trucoshi-server +4 -0
- package/dist/server/classes/Chat.d.ts +7 -0
- package/dist/server/classes/Chat.js +105 -0
- package/dist/server/classes/MatchTable.d.ts +15 -0
- package/dist/server/classes/MatchTable.js +113 -0
- package/dist/server/classes/SocketServer.d.ts +42 -0
- package/dist/server/classes/SocketServer.js +358 -0
- package/dist/server/classes/Trucoshi.d.ts +22 -0
- package/dist/server/classes/Trucoshi.js +27 -0
- package/dist/server/classes/User.d.ts +17 -0
- package/dist/server/classes/User.js +46 -0
- package/dist/server/classes/index.d.ts +5 -0
- package/dist/server/classes/index.js +21 -0
- package/dist/server/constants.d.ts +2 -0
- package/dist/server/constants.js +5 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +17 -0
- package/dist/server/middlewares/trucoshiEvents.d.ts +3 -0
- package/dist/server/middlewares/trucoshiEvents.js +154 -0
- package/dist/test/autoplay.d.ts +1 -0
- package/dist/test/autoplay.js +48 -0
- package/dist/test/play.d.ts +1 -0
- package/dist/test/play.js +124 -0
- package/package.json +3 -6
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Chat = void 0;
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
|
+
const SYSTEM_ID = "system";
|
|
6
|
+
const ChatUser = (id) => {
|
|
7
|
+
return {
|
|
8
|
+
id,
|
|
9
|
+
key: id,
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
const ChatMessage = ({ user, system, command, content, }) => {
|
|
13
|
+
return {
|
|
14
|
+
date: Date.now() / 1000,
|
|
15
|
+
user,
|
|
16
|
+
content,
|
|
17
|
+
system: system || false,
|
|
18
|
+
command: command || false,
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const ChatRoom = (io, id) => {
|
|
22
|
+
const room = {
|
|
23
|
+
id,
|
|
24
|
+
messages: [],
|
|
25
|
+
send(user, content) {
|
|
26
|
+
room.messages.push(ChatMessage({
|
|
27
|
+
user,
|
|
28
|
+
content,
|
|
29
|
+
}));
|
|
30
|
+
room.emit();
|
|
31
|
+
},
|
|
32
|
+
system(content) {
|
|
33
|
+
room.messages.push(ChatMessage({
|
|
34
|
+
user: ChatUser(SYSTEM_ID),
|
|
35
|
+
content,
|
|
36
|
+
system: true,
|
|
37
|
+
}));
|
|
38
|
+
room.emit();
|
|
39
|
+
},
|
|
40
|
+
command(team, command) {
|
|
41
|
+
room.messages.push(ChatMessage({
|
|
42
|
+
user: ChatUser(types_1.EChatSystem[team]),
|
|
43
|
+
content: command,
|
|
44
|
+
command: true,
|
|
45
|
+
}));
|
|
46
|
+
room.emit();
|
|
47
|
+
},
|
|
48
|
+
emit() {
|
|
49
|
+
io.sockets.adapter
|
|
50
|
+
.fetchSockets({
|
|
51
|
+
rooms: new Set([room.id]),
|
|
52
|
+
})
|
|
53
|
+
.then((sockets) => {
|
|
54
|
+
for (const playerSocket of sockets) {
|
|
55
|
+
playerSocket.emit(types_1.EServerEvent.UPDATE_CHAT, { id: room.id, messages: room.messages });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
return room;
|
|
61
|
+
};
|
|
62
|
+
const Chat = (io) => {
|
|
63
|
+
const chat = {
|
|
64
|
+
rooms: new types_1.TMap(),
|
|
65
|
+
create(id) {
|
|
66
|
+
const room = ChatRoom(io, id);
|
|
67
|
+
const exists = chat.rooms.get(id);
|
|
68
|
+
if (exists) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
chat.rooms.set(id, room);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
const adapter = io.of("/").adapter;
|
|
75
|
+
adapter.on("join-room", (room, socketId) => {
|
|
76
|
+
var _a;
|
|
77
|
+
const userSocket = io.sockets.sockets.get(socketId);
|
|
78
|
+
if (!userSocket || !userSocket.data.user) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const { id, key } = userSocket.data.user;
|
|
82
|
+
(_a = chat.rooms.get(room)) === null || _a === void 0 ? void 0 : _a.system(`${id} entro a la sala`);
|
|
83
|
+
userSocket.on(types_1.EClientEvent.CHAT, (matchId, message, callback) => {
|
|
84
|
+
if (matchId !== room || !userSocket.data.user) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const chatroom = chat.rooms.get(matchId);
|
|
88
|
+
if (chatroom) {
|
|
89
|
+
chatroom.send({ id, key }, message);
|
|
90
|
+
}
|
|
91
|
+
callback();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
adapter.on("leave-room", (room, socketId) => {
|
|
95
|
+
var _a;
|
|
96
|
+
const userSocket = io.sockets.sockets.get(socketId);
|
|
97
|
+
if (!userSocket || !userSocket.data.user) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const { id } = userSocket.data.user;
|
|
101
|
+
(_a = chat.rooms.get(room)) === null || _a === void 0 ? void 0 : _a.system(`${id} salio de la sala`);
|
|
102
|
+
});
|
|
103
|
+
return chat;
|
|
104
|
+
};
|
|
105
|
+
exports.Chat = Chat;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IHand, ILobby, IPlayedCard, IPlayer } from "../../lib";
|
|
2
|
+
import { EMatchTableState, IMatchPreviousHand, IPublicMatch, IPublicMatchInfo } from "../../types";
|
|
3
|
+
export interface IMatchTable {
|
|
4
|
+
ownerSession: string;
|
|
5
|
+
matchSessionId: string;
|
|
6
|
+
lobby: ILobby;
|
|
7
|
+
state(): EMatchTableState;
|
|
8
|
+
isSessionPlaying(session: string): IPlayer | null;
|
|
9
|
+
getPreviousHand(hand: IHand): IMatchPreviousHand;
|
|
10
|
+
getHandRounds(hand: IHand): IPlayedCard[][];
|
|
11
|
+
getPublicMatch(session?: string): IPublicMatch;
|
|
12
|
+
getPublicMatchInfo(): IPublicMatchInfo;
|
|
13
|
+
waitPlayerReconnection(player: IPlayer, callback: (onReconnect: () => void, onAbandon: () => void) => void, update: () => void): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export declare function MatchTable(matchSessionId: string, ownerSession: string, teamSize?: 1 | 2 | 3): IMatchTable;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MatchTable = void 0;
|
|
13
|
+
const lib_1 = require("../../lib");
|
|
14
|
+
const types_1 = require("../../types");
|
|
15
|
+
function MatchTable(matchSessionId, ownerSession, teamSize) {
|
|
16
|
+
const matchTable = {
|
|
17
|
+
ownerSession,
|
|
18
|
+
matchSessionId,
|
|
19
|
+
lobby: (0, lib_1.Lobby)(teamSize),
|
|
20
|
+
state() {
|
|
21
|
+
var _a;
|
|
22
|
+
matchTable.lobby.calculateReady();
|
|
23
|
+
if ((_a = matchTable.lobby.gameLoop) === null || _a === void 0 ? void 0 : _a.winner) {
|
|
24
|
+
return types_1.EMatchTableState.FINISHED;
|
|
25
|
+
}
|
|
26
|
+
if (matchTable.lobby.started) {
|
|
27
|
+
return types_1.EMatchTableState.STARTED;
|
|
28
|
+
}
|
|
29
|
+
if (matchTable.lobby.ready) {
|
|
30
|
+
return types_1.EMatchTableState.READY;
|
|
31
|
+
}
|
|
32
|
+
return types_1.EMatchTableState.UNREADY;
|
|
33
|
+
},
|
|
34
|
+
isSessionPlaying(session) {
|
|
35
|
+
const { lobby } = matchTable;
|
|
36
|
+
const search = lobby.players.find((player) => player && player.session === session);
|
|
37
|
+
return search || null;
|
|
38
|
+
},
|
|
39
|
+
getPublicMatchInfo() {
|
|
40
|
+
var _a;
|
|
41
|
+
const { matchSessionId, state, lobby: { players, maxPlayers }, } = matchTable;
|
|
42
|
+
return {
|
|
43
|
+
ownerId: (_a = players.find((player) => player.isOwner)) === null || _a === void 0 ? void 0 : _a.id,
|
|
44
|
+
matchSessionId,
|
|
45
|
+
maxPlayers,
|
|
46
|
+
players: players.length,
|
|
47
|
+
state: state(),
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
waitPlayerReconnection(player, callback, update) {
|
|
51
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
player.setReady(false);
|
|
53
|
+
update();
|
|
54
|
+
try {
|
|
55
|
+
yield new Promise(callback);
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
if (matchTable.state() !== types_1.EMatchTableState.STARTED &&
|
|
59
|
+
matchTable.state() !== types_1.EMatchTableState.FINISHED) {
|
|
60
|
+
player.setReady(false);
|
|
61
|
+
matchTable.lobby.removePlayer(player.session);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
player.setReady(true);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
update();
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
getHandRounds(hand) {
|
|
71
|
+
if (!hand) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
return hand.rounds.map((round) => round.cards) || [];
|
|
75
|
+
},
|
|
76
|
+
getPreviousHand(hand) {
|
|
77
|
+
return {
|
|
78
|
+
rounds: matchTable.getHandRounds(hand),
|
|
79
|
+
points: hand.points,
|
|
80
|
+
matchSessionId: matchTable.matchSessionId,
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
getPublicMatch(userSession) {
|
|
84
|
+
var _a, _b, _c, _d;
|
|
85
|
+
const { lobby } = matchTable;
|
|
86
|
+
const winner = ((_a = lobby.gameLoop) === null || _a === void 0 ? void 0 : _a.winner) || null;
|
|
87
|
+
const rounds = ((_b = lobby.gameLoop) === null || _b === void 0 ? void 0 : _b.currentHand)
|
|
88
|
+
? matchTable.getHandRounds((_c = lobby.gameLoop) === null || _c === void 0 ? void 0 : _c.currentHand)
|
|
89
|
+
: [];
|
|
90
|
+
const players = lobby.players.filter((player) => Boolean(player));
|
|
91
|
+
const currentPlayerIdx = players.findIndex((player) => player && player.session === userSession);
|
|
92
|
+
const me = players[currentPlayerIdx];
|
|
93
|
+
const cut = players.slice(currentPlayerIdx, players.length);
|
|
94
|
+
const end = players.slice(0, currentPlayerIdx);
|
|
95
|
+
const publicPlayers = cut
|
|
96
|
+
.concat(end)
|
|
97
|
+
.map((player) => ((player === null || player === void 0 ? void 0 : player.session) === userSession ? player : player.getPublicPlayer()));
|
|
98
|
+
const teams = ((_d = lobby.gameLoop) === null || _d === void 0 ? void 0 : _d.teams) || lobby.teams;
|
|
99
|
+
const publicTeams = teams.map((team) => team.getPublicTeam(userSession));
|
|
100
|
+
return {
|
|
101
|
+
me,
|
|
102
|
+
winner,
|
|
103
|
+
matchSessionId: matchTable.matchSessionId,
|
|
104
|
+
state: matchTable.state(),
|
|
105
|
+
teams: publicTeams,
|
|
106
|
+
players: publicPlayers,
|
|
107
|
+
rounds,
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
return matchTable;
|
|
112
|
+
}
|
|
113
|
+
exports.MatchTable = MatchTable;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Server as HttpServer } from "http";
|
|
3
|
+
import { Server, Socket } from "socket.io";
|
|
4
|
+
import { IPlayer, IPlayInstance, IPublicPlayer, ITeam } from "../../lib";
|
|
5
|
+
import { ClientToServerEvents, ECommand, IEventCallback, IPublicMatch, ServerToClientEvents } from "../../types";
|
|
6
|
+
import { IChat } from "./Chat";
|
|
7
|
+
import { IMatchTable } from "./MatchTable";
|
|
8
|
+
import { ITrucoshi } from "./Trucoshi";
|
|
9
|
+
import { IUser } from "./User";
|
|
10
|
+
interface InterServerEvents {
|
|
11
|
+
}
|
|
12
|
+
interface SocketData {
|
|
13
|
+
user?: IUser;
|
|
14
|
+
}
|
|
15
|
+
export type TrucoshiServer = Server<ClientToServerEvents, ServerToClientEvents, InterServerEvents, SocketData>;
|
|
16
|
+
export type TrucoshiSocket = Socket<ClientToServerEvents, ServerToClientEvents, InterServerEvents, SocketData>;
|
|
17
|
+
export interface ISocketServer extends ITrucoshi {
|
|
18
|
+
io: TrucoshiServer;
|
|
19
|
+
httpServer: HttpServer;
|
|
20
|
+
chat: IChat;
|
|
21
|
+
getTableSockets(table: IMatchTable, callback?: (playerSocket: TrucoshiSocket, player: IPlayer | null) => Promise<void>): Promise<{
|
|
22
|
+
sockets: any[];
|
|
23
|
+
players: IPublicPlayer[];
|
|
24
|
+
}>;
|
|
25
|
+
setOrGetSession(socket: TrucoshiSocket, id: string | null, session: string | null, callback: IEventCallback<{
|
|
26
|
+
session?: string;
|
|
27
|
+
}>): Promise<IUser>;
|
|
28
|
+
leaveMatch(matchId: string, socketId: string, mayReconnect?: boolean): Promise<void>;
|
|
29
|
+
emitWaitingPossibleSay(play: IPlayInstance, table: IMatchTable): Promise<ECommand>;
|
|
30
|
+
emitWaitingForPlay(play: IPlayInstance, table: IMatchTable): Promise<void>;
|
|
31
|
+
emitMatchUpdate(table: IMatchTable, skipSocketIds?: Array<string>): Promise<void>;
|
|
32
|
+
emitPreviousHand(play: IPlayInstance, table: IMatchTable): Promise<void>;
|
|
33
|
+
emitSocketMatch(socket: TrucoshiSocket, currentMatchId: string | null): IPublicMatch | null;
|
|
34
|
+
startMatch(matchSessionId: string): Promise<void>;
|
|
35
|
+
onTurn(table: IMatchTable, play: IPlayInstance, newHandJustStarted: boolean): Promise<void>;
|
|
36
|
+
onTruco(table: IMatchTable, play: IPlayInstance): Promise<void>;
|
|
37
|
+
onWinner(table: IMatchTable, winner: ITeam): Promise<void>;
|
|
38
|
+
cleanupMatchTable(match: IMatchTable): void;
|
|
39
|
+
listen: (callback: (io: TrucoshiServer) => void) => void;
|
|
40
|
+
}
|
|
41
|
+
export declare const SocketServer: (trucoshi: ITrucoshi, port: number, origin?: string | Array<string>) => ISocketServer;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.SocketServer = void 0;
|
|
13
|
+
const crypto_1 = require("crypto");
|
|
14
|
+
const http_1 = require("http");
|
|
15
|
+
const socket_io_1 = require("socket.io");
|
|
16
|
+
const types_1 = require("../../types");
|
|
17
|
+
const constants_1 = require("../constants");
|
|
18
|
+
const Chat_1 = require("./Chat");
|
|
19
|
+
const User_1 = require("./User");
|
|
20
|
+
const SocketServer = (trucoshi, port, origin) => {
|
|
21
|
+
const httpServer = (0, http_1.createServer)();
|
|
22
|
+
const io = new socket_io_1.Server(httpServer, {
|
|
23
|
+
cors: {
|
|
24
|
+
origin,
|
|
25
|
+
methods: ["GET", "POST"],
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
const server = {
|
|
29
|
+
io,
|
|
30
|
+
httpServer,
|
|
31
|
+
turns: trucoshi.turns,
|
|
32
|
+
tables: trucoshi.tables,
|
|
33
|
+
users: trucoshi.users,
|
|
34
|
+
chat: (0, Chat_1.Chat)(io),
|
|
35
|
+
listen(callback) {
|
|
36
|
+
httpServer.listen(port, undefined, undefined, () => callback(server.io));
|
|
37
|
+
},
|
|
38
|
+
setOrGetSession(socket, id, session, callback = () => { }) {
|
|
39
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
if (session) {
|
|
41
|
+
const user = server.users.get(session);
|
|
42
|
+
if (user) {
|
|
43
|
+
const newId = id || user.id || "Satoshi";
|
|
44
|
+
user.connect();
|
|
45
|
+
user.setId(newId);
|
|
46
|
+
socket.data.user = user;
|
|
47
|
+
callback({ success: true, session });
|
|
48
|
+
return user;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const newSession = (0, crypto_1.randomUUID)();
|
|
52
|
+
const userKey = (0, crypto_1.randomUUID)();
|
|
53
|
+
const newId = id || "Satoshi";
|
|
54
|
+
const newUser = (0, User_1.User)(userKey, newId, newSession);
|
|
55
|
+
socket.data.user = newUser;
|
|
56
|
+
server.users.set(newSession, newUser);
|
|
57
|
+
callback({ success: false, session: newSession });
|
|
58
|
+
return newUser;
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
getTableSockets(table, callback) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
64
|
+
var _a;
|
|
65
|
+
const sockets = yield server.io.sockets.adapter.fetchSockets({
|
|
66
|
+
rooms: new Set([table.matchSessionId]),
|
|
67
|
+
});
|
|
68
|
+
const players = [];
|
|
69
|
+
for (const playerSocket of sockets) {
|
|
70
|
+
if (!((_a = playerSocket.data.user) === null || _a === void 0 ? void 0 : _a.session)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const player = table.isSessionPlaying(playerSocket.data.user.session);
|
|
74
|
+
if (player) {
|
|
75
|
+
players.push(player);
|
|
76
|
+
}
|
|
77
|
+
if (callback) {
|
|
78
|
+
yield callback(playerSocket, player);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
resolve({ sockets, players });
|
|
82
|
+
}));
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
emitMatchUpdate(table, skipSocketIds = []) {
|
|
86
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
87
|
+
yield server.getTableSockets(table, (playerSocket) => __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
var _a;
|
|
89
|
+
if (skipSocketIds.includes(playerSocket.id)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
playerSocket.emit(types_1.EServerEvent.UPDATE_MATCH, table.getPublicMatch((_a = playerSocket.data.user) === null || _a === void 0 ? void 0 : _a.session));
|
|
93
|
+
}));
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
emitWaitingPossibleSay(play, table) {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
let someoneSaidSomething = false;
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
return server.getTableSockets(table, (playerSocket, player) => __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
if (!player) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
playerSocket.emit(types_1.EServerEvent.WAITING_POSSIBLE_SAY, table.getPublicMatch(player.session), (data) => {
|
|
105
|
+
if (!data) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (someoneSaidSomething) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const { command } = data;
|
|
112
|
+
try {
|
|
113
|
+
if (command) {
|
|
114
|
+
const saidCommand = play.say(command, player);
|
|
115
|
+
if (saidCommand) {
|
|
116
|
+
someoneSaidSomething = true;
|
|
117
|
+
server.chat.rooms
|
|
118
|
+
.getOrThrow(table.matchSessionId)
|
|
119
|
+
.command(player.teamIdx, saidCommand);
|
|
120
|
+
return resolve(saidCommand);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
reject(e);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}));
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
emitWaitingForPlay(play, table) {
|
|
133
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
server
|
|
136
|
+
.emitWaitingPossibleSay(play, table)
|
|
137
|
+
.then(() => {
|
|
138
|
+
resolve();
|
|
139
|
+
})
|
|
140
|
+
.catch(console.error);
|
|
141
|
+
return server.getTableSockets(table, (playerSocket, player) => __awaiter(this, void 0, void 0, function* () {
|
|
142
|
+
var _a;
|
|
143
|
+
if (!player) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (player.session === ((_a = play.player) === null || _a === void 0 ? void 0 : _a.session)) {
|
|
147
|
+
playerSocket.emit(types_1.EServerEvent.WAITING_PLAY, table.getPublicMatch(player.session), (data) => {
|
|
148
|
+
if (!data) {
|
|
149
|
+
return reject(new Error(types_1.EServerEvent.WAITING_PLAY + " callback returned empty"));
|
|
150
|
+
}
|
|
151
|
+
const { cardIdx, card } = data;
|
|
152
|
+
if (cardIdx !== undefined && card) {
|
|
153
|
+
const playedCard = play.use(cardIdx, card);
|
|
154
|
+
if (playedCard) {
|
|
155
|
+
return resolve();
|
|
156
|
+
}
|
|
157
|
+
return reject(new Error("Invalid Card"));
|
|
158
|
+
}
|
|
159
|
+
return reject(new Error("Invalid Callback Response"));
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}));
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
emitPreviousHand(play, table) {
|
|
167
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
168
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
169
|
+
try {
|
|
170
|
+
const promises = [];
|
|
171
|
+
yield server.getTableSockets(table, (playerSocket, player) => __awaiter(this, void 0, void 0, function* () {
|
|
172
|
+
promises.push(new Promise((resolvePlayer, rejectPlayer) => {
|
|
173
|
+
if (!player || !play.prevHand) {
|
|
174
|
+
return rejectPlayer();
|
|
175
|
+
}
|
|
176
|
+
playerSocket.emit(types_1.EServerEvent.PREVIOUS_HAND, table.getPreviousHand(play.prevHand), resolvePlayer);
|
|
177
|
+
setTimeout(() => {
|
|
178
|
+
rejectPlayer();
|
|
179
|
+
}, constants_1.PREVIOUS_HAND_ACK_TIMEOUT);
|
|
180
|
+
}));
|
|
181
|
+
}));
|
|
182
|
+
yield Promise.allSettled(promises);
|
|
183
|
+
resolve();
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
reject(e);
|
|
187
|
+
}
|
|
188
|
+
}));
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
onTurn(table, play, newHandJustStarted) {
|
|
192
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
193
|
+
var _a;
|
|
194
|
+
server.turns.set(table.matchSessionId, {
|
|
195
|
+
play,
|
|
196
|
+
resolve,
|
|
197
|
+
});
|
|
198
|
+
try {
|
|
199
|
+
const session = (_a = play.player) === null || _a === void 0 ? void 0 : _a.session;
|
|
200
|
+
if (!session || !play) {
|
|
201
|
+
throw new Error("Unexpected Error");
|
|
202
|
+
}
|
|
203
|
+
server.users.getOrThrow(session);
|
|
204
|
+
if (newHandJustStarted) {
|
|
205
|
+
yield server.emitPreviousHand(play, table);
|
|
206
|
+
}
|
|
207
|
+
yield server.emitWaitingForPlay(play, table);
|
|
208
|
+
return resolve();
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
reject(e);
|
|
212
|
+
}
|
|
213
|
+
}));
|
|
214
|
+
},
|
|
215
|
+
onTruco(table, play) {
|
|
216
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
217
|
+
server.turns.set(table.matchSessionId, {
|
|
218
|
+
play,
|
|
219
|
+
resolve,
|
|
220
|
+
});
|
|
221
|
+
try {
|
|
222
|
+
yield server.emitWaitingPossibleSay(play, table);
|
|
223
|
+
return resolve();
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
reject(e);
|
|
227
|
+
}
|
|
228
|
+
}));
|
|
229
|
+
},
|
|
230
|
+
onWinner(table, _winner) {
|
|
231
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
232
|
+
yield server.emitMatchUpdate(table);
|
|
233
|
+
});
|
|
234
|
+
},
|
|
235
|
+
startMatch(matchSessionId) {
|
|
236
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
237
|
+
const table = server.tables.getOrThrow(matchSessionId);
|
|
238
|
+
if (table && !table.lobby.gameLoop) {
|
|
239
|
+
table.lobby
|
|
240
|
+
.startMatch()
|
|
241
|
+
.onTurn(server.onTurn.bind(this, table))
|
|
242
|
+
.onTruco(server.onTruco.bind(this, table))
|
|
243
|
+
.onWinner(server.onWinner.bind(this, table))
|
|
244
|
+
.begin();
|
|
245
|
+
server.tables.set(matchSessionId, table);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
},
|
|
250
|
+
emitSocketMatch(socket, matchId) {
|
|
251
|
+
var _a;
|
|
252
|
+
if (!matchId || !((_a = socket.data.user) === null || _a === void 0 ? void 0 : _a.session)) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
const currentTable = server.tables.get(matchId);
|
|
256
|
+
if (currentTable) {
|
|
257
|
+
socket.join(currentTable.matchSessionId);
|
|
258
|
+
const { play, resolve } = server.turns.get(currentTable.matchSessionId) || {};
|
|
259
|
+
if (play && play.player && currentTable.isSessionPlaying(socket.data.user.session)) {
|
|
260
|
+
if (play.state === types_1.EHandState.WAITING_PLAY &&
|
|
261
|
+
socket.data.user.session === play.player.session) {
|
|
262
|
+
server.emitWaitingForPlay(play, currentTable).then(resolve).catch(console.error);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
server.emitWaitingPossibleSay(play, currentTable).then(resolve).catch(console.error);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
socket.emit(types_1.EServerEvent.UPDATE_MATCH, currentTable.getPublicMatch(socket.data.user.session));
|
|
270
|
+
}
|
|
271
|
+
return currentTable.getPublicMatch(socket.data.user.session);
|
|
272
|
+
}
|
|
273
|
+
return null;
|
|
274
|
+
},
|
|
275
|
+
leaveMatch(matchId, socketId, mayReconnect) {
|
|
276
|
+
return new Promise((resolve, reject) => {
|
|
277
|
+
var _a;
|
|
278
|
+
const _abandon = (table, player, abandon) => {
|
|
279
|
+
try {
|
|
280
|
+
const { play, resolve: playResolve } = server.turns.getOrThrow(table.matchSessionId);
|
|
281
|
+
play.say(types_1.ESayCommand.MAZO, player);
|
|
282
|
+
playResolve();
|
|
283
|
+
abandon();
|
|
284
|
+
}
|
|
285
|
+
catch (e) {
|
|
286
|
+
reject(e);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
const playingMatch = _getPossiblePlayingMatch(matchId, socketId);
|
|
290
|
+
if (!playingMatch) {
|
|
291
|
+
return resolve();
|
|
292
|
+
}
|
|
293
|
+
const { player, table, user } = playingMatch;
|
|
294
|
+
if (table.state() === types_1.EMatchTableState.FINISHED && ((_a = table.lobby.gameLoop) === null || _a === void 0 ? void 0 : _a.winner)) {
|
|
295
|
+
server.cleanupMatchTable(table);
|
|
296
|
+
return resolve();
|
|
297
|
+
}
|
|
298
|
+
if (!mayReconnect) {
|
|
299
|
+
return _abandon(table, player, resolve);
|
|
300
|
+
}
|
|
301
|
+
server.getTableSockets(table).then(({ players }) => {
|
|
302
|
+
const find = players.find((p) => p.key === player.key);
|
|
303
|
+
if (find) {
|
|
304
|
+
return resolve();
|
|
305
|
+
}
|
|
306
|
+
table.waitPlayerReconnection(player, (reconnect, abandon) => {
|
|
307
|
+
user.waitReconnection(table.matchSessionId, reconnect, _abandon.bind({}, table, player, abandon));
|
|
308
|
+
}, () => {
|
|
309
|
+
server.emitMatchUpdate(table, []);
|
|
310
|
+
});
|
|
311
|
+
resolve();
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
cleanupMatchTable(table) {
|
|
316
|
+
try {
|
|
317
|
+
for (const player of table.lobby.players) {
|
|
318
|
+
const user = server.users.getOrThrow(player.session);
|
|
319
|
+
user.reconnect(table.matchSessionId); // resolve promises and timeouts
|
|
320
|
+
server.tables.delete(table.matchSessionId);
|
|
321
|
+
if (player.isOwner) {
|
|
322
|
+
user.setOwnedMatch(null);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
catch (e) {
|
|
327
|
+
console.error(e);
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
const _getPossiblePlayingMatch = (room, socketId) => {
|
|
332
|
+
const socket = server.io.sockets.sockets.get(socketId);
|
|
333
|
+
if (!socket || !socket.data.user) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
const table = server.tables.get(room);
|
|
337
|
+
if (table) {
|
|
338
|
+
const player = table.isSessionPlaying(socket.data.user.session);
|
|
339
|
+
if (player) {
|
|
340
|
+
return { table, player, user: socket.data.user };
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return null;
|
|
344
|
+
};
|
|
345
|
+
io.of("/").adapter.on("leave-room", (room, socketId) => {
|
|
346
|
+
server.leaveMatch(room, socketId, true).then().catch(console.error);
|
|
347
|
+
});
|
|
348
|
+
io.of("/").adapter.on("join-room", (room, socketId) => {
|
|
349
|
+
const playingMatch = _getPossiblePlayingMatch(room, socketId);
|
|
350
|
+
if (!playingMatch) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const { table, user } = playingMatch;
|
|
354
|
+
user.reconnect(table.matchSessionId);
|
|
355
|
+
});
|
|
356
|
+
return server;
|
|
357
|
+
};
|
|
358
|
+
exports.SocketServer = SocketServer;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IPlayInstance } from "../../lib";
|
|
2
|
+
import { EMatchTableState, IPublicMatchInfo, TMap } from "../../types";
|
|
3
|
+
import { IMatchTable } from "./MatchTable";
|
|
4
|
+
import { IUser } from "./User";
|
|
5
|
+
export interface ITrucoshi {
|
|
6
|
+
users: TMap<string, IUser>;
|
|
7
|
+
tables: MatchTableMap;
|
|
8
|
+
turns: TMap<string, ITrucoshiTurn>;
|
|
9
|
+
}
|
|
10
|
+
interface ITrucoshiTurn {
|
|
11
|
+
play: IPlayInstance;
|
|
12
|
+
resolve(): void;
|
|
13
|
+
}
|
|
14
|
+
interface MatchTableMap extends TMap<string, IMatchTable> {
|
|
15
|
+
getAll(filters: {
|
|
16
|
+
state?: Array<EMatchTableState>;
|
|
17
|
+
}): Array<IPublicMatchInfo>;
|
|
18
|
+
}
|
|
19
|
+
declare class MatchTableMap extends TMap<string, IMatchTable> {
|
|
20
|
+
}
|
|
21
|
+
export declare const Trucoshi: () => ITrucoshi;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Trucoshi = void 0;
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
|
+
class MatchTableMap extends types_1.TMap {
|
|
6
|
+
getAll(filters = {}) {
|
|
7
|
+
let results = [];
|
|
8
|
+
for (let value of this.values()) {
|
|
9
|
+
if (!filters.state || !filters.state.length || filters.state.includes(value.state())) {
|
|
10
|
+
results.push(value.getPublicMatchInfo());
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return results;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const Trucoshi = () => {
|
|
17
|
+
const users = new types_1.TMap(); // sessionId, user
|
|
18
|
+
const tables = new MatchTableMap(); // sessionId, table
|
|
19
|
+
const turns = new types_1.TMap(); // sessionId, play instance, play promise resolve and type
|
|
20
|
+
const trucoshi = {
|
|
21
|
+
users,
|
|
22
|
+
tables,
|
|
23
|
+
turns,
|
|
24
|
+
};
|
|
25
|
+
return trucoshi;
|
|
26
|
+
};
|
|
27
|
+
exports.Trucoshi = Trucoshi;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export interface IUser {
|
|
3
|
+
key: string;
|
|
4
|
+
id: string;
|
|
5
|
+
session: string;
|
|
6
|
+
online: boolean;
|
|
7
|
+
ownedMatchId: string | null;
|
|
8
|
+
waitingTimeouts: Map<string, NodeJS.Timeout | null>;
|
|
9
|
+
waitingPromises: Map<string, () => void>;
|
|
10
|
+
waitReconnection(room: string, reconnect: () => void, abandon: () => void): void;
|
|
11
|
+
setOwnedMatch(id: string | null): void;
|
|
12
|
+
connect(): void;
|
|
13
|
+
disconnect(): void;
|
|
14
|
+
reconnect(room: string): void;
|
|
15
|
+
setId(id: string): void;
|
|
16
|
+
}
|
|
17
|
+
export declare function User(key: string, id: string, session: string): IUser;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.User = void 0;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
function User(key, id, session) {
|
|
6
|
+
const user = {
|
|
7
|
+
id,
|
|
8
|
+
key,
|
|
9
|
+
session,
|
|
10
|
+
online: true,
|
|
11
|
+
ownedMatchId: null,
|
|
12
|
+
waitingTimeouts: new Map(),
|
|
13
|
+
waitingPromises: new Map(),
|
|
14
|
+
waitReconnection(room, reconnect, abandon) {
|
|
15
|
+
user.waitingTimeouts.set(room, setTimeout(() => {
|
|
16
|
+
abandon();
|
|
17
|
+
user.waitingPromises.delete(room);
|
|
18
|
+
}, constants_1.PLAYER_ABANDON_TIMEOUT));
|
|
19
|
+
user.waitingPromises.set(room, reconnect);
|
|
20
|
+
},
|
|
21
|
+
reconnect(room) {
|
|
22
|
+
const promise = user.waitingPromises.get(room);
|
|
23
|
+
if (promise) {
|
|
24
|
+
promise();
|
|
25
|
+
user.waitingPromises.delete(room);
|
|
26
|
+
}
|
|
27
|
+
const timeout = user.waitingTimeouts.get(room);
|
|
28
|
+
if (timeout) {
|
|
29
|
+
clearTimeout(timeout);
|
|
30
|
+
user.waitingTimeouts.delete(room);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
setOwnedMatch(id) {
|
|
34
|
+
user.ownedMatchId = id;
|
|
35
|
+
},
|
|
36
|
+
connect() {
|
|
37
|
+
user.online = true;
|
|
38
|
+
},
|
|
39
|
+
disconnect() { },
|
|
40
|
+
setId(id) {
|
|
41
|
+
user.id = id;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
return user;
|
|
45
|
+
}
|
|
46
|
+
exports.User = User;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./Chat"), exports);
|
|
18
|
+
__exportStar(require("./MatchTable"), exports);
|
|
19
|
+
__exportStar(require("./SocketServer"), exports);
|
|
20
|
+
__exportStar(require("./Trucoshi"), exports);
|
|
21
|
+
__exportStar(require("./User"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './classes';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./classes"), exports);
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trucoshiEvents = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const types_1 = require("../../types");
|
|
6
|
+
const classes_1 = require("../classes");
|
|
7
|
+
const trucoshiEvents = (server) => (socket, next) => {
|
|
8
|
+
socket.on("disconnect", (_reason) => {
|
|
9
|
+
var _a;
|
|
10
|
+
try {
|
|
11
|
+
const user = server.users.getOrThrow((_a = socket.data.user) === null || _a === void 0 ? void 0 : _a.session);
|
|
12
|
+
if (user) {
|
|
13
|
+
user.disconnect();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
// noop
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
socket.on(types_1.EClientEvent.PING, (msg) => {
|
|
21
|
+
socket.emit(types_1.EServerEvent.PONG, msg);
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Create Match
|
|
25
|
+
*/
|
|
26
|
+
socket.on(types_1.EClientEvent.CREATE_MATCH, (callback) => {
|
|
27
|
+
try {
|
|
28
|
+
if (!socket.data.user) {
|
|
29
|
+
throw new Error("Session not found");
|
|
30
|
+
}
|
|
31
|
+
const user = server.users.getOrThrow(socket.data.user.session);
|
|
32
|
+
const existingTable = user.ownedMatchId && server.tables.get(user.ownedMatchId);
|
|
33
|
+
if (existingTable) {
|
|
34
|
+
return callback({
|
|
35
|
+
success: false,
|
|
36
|
+
match: existingTable.getPublicMatch(socket.data.user.session),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const matchId = (0, crypto_1.randomUUID)();
|
|
40
|
+
const table = (0, classes_1.MatchTable)(matchId, socket.data.user.session);
|
|
41
|
+
user.ownedMatchId = matchId;
|
|
42
|
+
table.lobby.addPlayer(user.key, user.id, socket.data.user.session, 0, true);
|
|
43
|
+
server.chat.create(matchId);
|
|
44
|
+
socket.join(matchId);
|
|
45
|
+
server.tables.set(matchId, table);
|
|
46
|
+
return callback({ success: true, match: table.getPublicMatch(user.id) });
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
return callback({ success: false });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* Start Match
|
|
54
|
+
*/
|
|
55
|
+
socket.on(types_1.EClientEvent.START_MATCH, (callback) => {
|
|
56
|
+
var _a;
|
|
57
|
+
try {
|
|
58
|
+
const user = server.users.getOrThrow((_a = socket.data.user) === null || _a === void 0 ? void 0 : _a.session);
|
|
59
|
+
const matchId = user.ownedMatchId;
|
|
60
|
+
if (matchId) {
|
|
61
|
+
server.startMatch(matchId);
|
|
62
|
+
return callback({ success: true, matchSessionId: matchId });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
callback({ success: false });
|
|
67
|
+
}
|
|
68
|
+
callback({ success: false });
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* Join Match
|
|
72
|
+
*/
|
|
73
|
+
socket.on(types_1.EClientEvent.JOIN_MATCH, (matchSessionId, teamIdx, callback) => {
|
|
74
|
+
var _a, _b;
|
|
75
|
+
try {
|
|
76
|
+
const user = server.users.getOrThrow((_a = socket.data.user) === null || _a === void 0 ? void 0 : _a.session);
|
|
77
|
+
const table = server.tables.get(matchSessionId);
|
|
78
|
+
if (table) {
|
|
79
|
+
table.lobby.addPlayer(user.key, user.id, user.session, teamIdx, user.ownedMatchId === matchSessionId);
|
|
80
|
+
socket.join(table.matchSessionId);
|
|
81
|
+
server.emitMatchUpdate(table, []);
|
|
82
|
+
return callback({ success: true, match: table.getPublicMatch((_b = socket.data.user) === null || _b === void 0 ? void 0 : _b.session) });
|
|
83
|
+
}
|
|
84
|
+
callback({ success: false });
|
|
85
|
+
}
|
|
86
|
+
catch (e) {
|
|
87
|
+
callback({ success: false });
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* Get public matches
|
|
92
|
+
*/
|
|
93
|
+
socket.on(types_1.EClientEvent.LIST_MATCHES, (filters = {}, callback) => {
|
|
94
|
+
const publicMatches = server.tables.getAll(filters);
|
|
95
|
+
callback({ success: true, matches: publicMatches });
|
|
96
|
+
});
|
|
97
|
+
/**
|
|
98
|
+
* Set Session
|
|
99
|
+
*/
|
|
100
|
+
socket.on(types_1.EClientEvent.SET_SESSION, (id, session, callback = () => { }) => {
|
|
101
|
+
server.setOrGetSession(socket, id, session, ({ success, session }) => {
|
|
102
|
+
if (session && success) {
|
|
103
|
+
const activeMatches = server.tables
|
|
104
|
+
.findAll((table) => Boolean(table.isSessionPlaying(session)))
|
|
105
|
+
.map((match) => match.getPublicMatchInfo());
|
|
106
|
+
return callback({ success, session, activeMatches });
|
|
107
|
+
}
|
|
108
|
+
callback({ success, session, activeMatches: [] });
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
/**
|
|
112
|
+
* Fetch match with session
|
|
113
|
+
*/
|
|
114
|
+
socket.on(types_1.EClientEvent.FETCH_MATCH, (session, matchId, callback) => {
|
|
115
|
+
return server.setOrGetSession(socket, null, session, ({ success }) => {
|
|
116
|
+
var _a;
|
|
117
|
+
if (!success) {
|
|
118
|
+
return callback({ success: false, match: null });
|
|
119
|
+
}
|
|
120
|
+
(_a = server.chat.rooms.get(matchId)) === null || _a === void 0 ? void 0 : _a.emit();
|
|
121
|
+
const match = server.emitSocketMatch(socket, matchId);
|
|
122
|
+
callback({ success: Boolean(match), match });
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
/**
|
|
126
|
+
* Set Player Ready
|
|
127
|
+
*/
|
|
128
|
+
socket.on(types_1.EClientEvent.SET_PLAYER_READY, (matchId, ready, callback) => {
|
|
129
|
+
var _a;
|
|
130
|
+
try {
|
|
131
|
+
if (!socket.data.user) {
|
|
132
|
+
throw new Error("Session not found");
|
|
133
|
+
}
|
|
134
|
+
const table = server.tables.getOrThrow(matchId);
|
|
135
|
+
const player = table.lobby.players.find((player) => { var _a; return player && player.session === ((_a = socket.data.user) === null || _a === void 0 ? void 0 : _a.session); });
|
|
136
|
+
if (player) {
|
|
137
|
+
player.setReady(ready);
|
|
138
|
+
server.emitMatchUpdate(table, [socket.id]);
|
|
139
|
+
callback({ success: true, match: table.getPublicMatch((_a = socket.data.user) === null || _a === void 0 ? void 0 : _a.session) });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
callback({ success: false });
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
/**
|
|
147
|
+
* Leave Match
|
|
148
|
+
*/
|
|
149
|
+
socket.on(types_1.EClientEvent.LEAVE_MATCH, (matchId) => {
|
|
150
|
+
server.leaveMatch(matchId, socket.id, false);
|
|
151
|
+
});
|
|
152
|
+
next();
|
|
153
|
+
};
|
|
154
|
+
exports.trucoshiEvents = trucoshiEvents;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const lib_1 = require("../lib");
|
|
13
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
+
const trucoshi = (0, lib_1.Lobby)();
|
|
15
|
+
trucoshi.addPlayer("lukini", "lukini", "lukini").setReady(true);
|
|
16
|
+
trucoshi.addPlayer("denoph", "denoph", "denoph").setReady(true);
|
|
17
|
+
trucoshi.addPlayer("guada", "guada", "guada").setReady(true);
|
|
18
|
+
trucoshi.addPlayer("juli", "juli", "juli").setReady(true);
|
|
19
|
+
trucoshi.addPlayer("day", "day", "day").setReady(true);
|
|
20
|
+
trucoshi.addPlayer("fran", "fran", "fran").setReady(true);
|
|
21
|
+
trucoshi
|
|
22
|
+
.startMatch()
|
|
23
|
+
.onTurn((play) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
var _a;
|
|
25
|
+
if (!play.player) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const name = (_a = play.player) === null || _a === void 0 ? void 0 : _a.id.toUpperCase();
|
|
29
|
+
console.log(`=== Mano ${play.handIdx} === Ronda ${play.roundIdx} === Turno de ${name} ===`);
|
|
30
|
+
play.teams.map((team, id) => console.log(`=== Team ${id} = ${team.points.malas} malas ${team.points.buenas} buenas ===`));
|
|
31
|
+
console.log(play.rounds && play.rounds.length
|
|
32
|
+
? play.rounds.map((round) => round.cards.length ? round.cards.map((c) => [c.player.id, c.card]) : "")
|
|
33
|
+
: "");
|
|
34
|
+
const randomIdx = Math.round(Math.random() * (play.player.hand.length - 1));
|
|
35
|
+
const handString = JSON.stringify(play.player.hand);
|
|
36
|
+
const card = play.use(randomIdx, play.player.hand[randomIdx]);
|
|
37
|
+
console.log(`\n${handString}\nUsing ${card}`);
|
|
38
|
+
console.log(play.rounds && play.rounds.length
|
|
39
|
+
? play.rounds.map((round) => round.cards.length ? round.cards.map((c) => [c.player.id, c.card]) : "")
|
|
40
|
+
: "");
|
|
41
|
+
}))
|
|
42
|
+
.onWinner((winner, teams) => __awaiter(void 0, void 0, void 0, function* () {
|
|
43
|
+
console.log("\n");
|
|
44
|
+
teams.map((t, i) => console.log(`Equipo ${i}: ${t.players.map((p) => ` ${p.id}`)} === ${t.points.malas} malas ${t.points.buenas} buenas`));
|
|
45
|
+
console.log(`\nEquipo Ganador:${winner.players.map((p) => ` ${p.id}`)}`);
|
|
46
|
+
}))
|
|
47
|
+
.begin();
|
|
48
|
+
}))();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
const readline = __importStar(require("readline"));
|
|
36
|
+
const lib_1 = require("../lib");
|
|
37
|
+
const command = (title, onLine) => {
|
|
38
|
+
const promise = () => new Promise((resolve) => {
|
|
39
|
+
const rl = readline.createInterface(process.stdin, process.stdout);
|
|
40
|
+
rl.setPrompt(title);
|
|
41
|
+
rl.prompt();
|
|
42
|
+
rl.on("line", (line) => __awaiter(void 0, void 0, void 0, function* () {
|
|
43
|
+
try {
|
|
44
|
+
yield onLine(line, () => rl.close());
|
|
45
|
+
rl.close();
|
|
46
|
+
resolve();
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
rl.close();
|
|
50
|
+
return (() => __awaiter(void 0, void 0, void 0, function* () {
|
|
51
|
+
yield promise();
|
|
52
|
+
resolve();
|
|
53
|
+
}))();
|
|
54
|
+
}
|
|
55
|
+
}));
|
|
56
|
+
});
|
|
57
|
+
return promise;
|
|
58
|
+
};
|
|
59
|
+
const playCommand = (play) => {
|
|
60
|
+
var _a, _b, _d;
|
|
61
|
+
return command(`${(_a = play.player) === null || _a === void 0 ? void 0 : _a.id} elije una carta [${(_b = play.player) === null || _b === void 0 ? void 0 : _b.hand.map((_c, i) => i + 1)}]: ${JSON.stringify((_d = play.player) === null || _d === void 0 ? void 0 : _d.hand)}\n`, (idx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
62
|
+
var _e, _f;
|
|
63
|
+
const card = (_e = play.player) === null || _e === void 0 ? void 0 : _e.hand[Number(idx) - 1];
|
|
64
|
+
const playedCard = play.use(Number(idx) - 1, card);
|
|
65
|
+
if (!playedCard) {
|
|
66
|
+
return Promise.reject();
|
|
67
|
+
}
|
|
68
|
+
const handString = JSON.stringify((_f = play.player) === null || _f === void 0 ? void 0 : _f.hand);
|
|
69
|
+
console.log(`\n${handString}\nUsing ${playedCard}`);
|
|
70
|
+
console.log(play.rounds && play.rounds.length
|
|
71
|
+
? play.rounds.map((round) => round.cards.length ? round.cards.map((c) => [c.player.id, c.card]) : "")
|
|
72
|
+
: "");
|
|
73
|
+
return Promise.resolve();
|
|
74
|
+
}));
|
|
75
|
+
};
|
|
76
|
+
const sayCommand = (play, canPlay) => {
|
|
77
|
+
var _a, _b, _d, _e;
|
|
78
|
+
if (!((_a = play.player) === null || _a === void 0 ? void 0 : _a._commands)) {
|
|
79
|
+
return () => { };
|
|
80
|
+
}
|
|
81
|
+
const commandsArr = Array.from((_d = (_b = play.player) === null || _b === void 0 ? void 0 : _b._commands) === null || _d === void 0 ? void 0 : _d.values());
|
|
82
|
+
return command(`${(_e = play.player) === null || _e === void 0 ? void 0 : _e.id} elije una accion [${canPlay ? "0," : ""}${commandsArr.map((_c, i) => i + 1)}]: ${canPlay ? JSON.stringify(["CARTA", ...(commandsArr || [])]) : JSON.stringify(commandsArr)}\n`, (idx, close) => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
const selectedCommand = commandsArr[Number(idx) - 1];
|
|
84
|
+
if (selectedCommand) {
|
|
85
|
+
close();
|
|
86
|
+
const saidCommand = play.say(selectedCommand, play.player);
|
|
87
|
+
console.log({ saidCommand });
|
|
88
|
+
return Promise.resolve();
|
|
89
|
+
}
|
|
90
|
+
if (idx === "0" && canPlay) {
|
|
91
|
+
close();
|
|
92
|
+
yield playCommand(play)();
|
|
93
|
+
return Promise.resolve();
|
|
94
|
+
}
|
|
95
|
+
return Promise.reject();
|
|
96
|
+
}));
|
|
97
|
+
};
|
|
98
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
99
|
+
const trucoshi = (0, lib_1.Lobby)();
|
|
100
|
+
trucoshi.addPlayer("lukini", "lukini", "lukini").setReady(true);
|
|
101
|
+
trucoshi.addPlayer("denoph", "denoph", "denoph").setReady(true);
|
|
102
|
+
trucoshi.addPlayer("guada", "guada", "guada").setReady(true);
|
|
103
|
+
trucoshi.addPlayer("juli", "juli", "juli").setReady(true);
|
|
104
|
+
trucoshi
|
|
105
|
+
.startMatch()
|
|
106
|
+
.onTruco((play) => __awaiter(void 0, void 0, void 0, function* () {
|
|
107
|
+
yield sayCommand(play, false)();
|
|
108
|
+
}))
|
|
109
|
+
.onTurn((play) => __awaiter(void 0, void 0, void 0, function* () {
|
|
110
|
+
var _a;
|
|
111
|
+
const name = (_a = play.player) === null || _a === void 0 ? void 0 : _a.id.toUpperCase();
|
|
112
|
+
console.log(`=== Mano ${play.handIdx} === Ronda ${play.roundIdx} === Turno de ${name} ===`);
|
|
113
|
+
play.teams.map((team, id) => console.log(`=== Team ${id} = ${team.points.malas} malas ${team.points.buenas} buenas`));
|
|
114
|
+
console.log(play.rounds && play.rounds.length
|
|
115
|
+
? play.rounds.map((round) => round.cards.length ? round.cards.map((c) => [c.player.id, c.card]) : "")
|
|
116
|
+
: "");
|
|
117
|
+
yield sayCommand(play, true)();
|
|
118
|
+
}))
|
|
119
|
+
.onWinner((winner, teams) => __awaiter(void 0, void 0, void 0, function* () {
|
|
120
|
+
teams.map((t, i) => console.log(`Equipo ${i}: ${t.players.map((p) => ` ${p.id}`)} === ${t.points.malas} malas ${t.points.buenas} buenas`));
|
|
121
|
+
console.log(`\nEquipo Ganador:${winner === null || winner === void 0 ? void 0 : winner.players.map((p) => ` ${p.id}`)}`);
|
|
122
|
+
}))
|
|
123
|
+
.begin();
|
|
124
|
+
}))();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trucoshi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"scripts": {
|
|
@@ -24,11 +24,8 @@
|
|
|
24
24
|
"ts-mocha": "^10.0.0"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
|
-
"dist
|
|
28
|
-
"
|
|
29
|
-
"dist/types.js",
|
|
30
|
-
"dist/types.d.ts",
|
|
31
|
-
"dist/lib/**/*"
|
|
27
|
+
"dist",
|
|
28
|
+
"bin"
|
|
32
29
|
],
|
|
33
30
|
"dependencies": {
|
|
34
31
|
"rimraf": "^4.1.1",
|