Commit 1e0613cb authored by nanahira's avatar nanahira

Merge branch 'master' into enter-room-log

parents 78da1f9d 103429ba
Pipeline #10117 passed with stages
in 40 minutes and 22 seconds
...@@ -8,7 +8,7 @@ RUN apt update && \ ...@@ -8,7 +8,7 @@ RUN apt update && \
rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/*
# windbot # windbot
RUN git clone --depth=1 https://github.com/nanahira/windbot /tmp/windbot && \ RUN git clone --depth=1 https://code.mycard.moe/nanahira/windbot /tmp/windbot && \
cd /tmp/windbot && \ cd /tmp/windbot && \
xbuild /property:Configuration=Release /property:TargetFrameworkVersion="v4.5" && \ xbuild /property:Configuration=Release /property:TargetFrameworkVersion="v4.5" && \
mv /tmp/windbot/bin/Release /ygopro-server/windbot && \ mv /tmp/windbot/bin/Release /ygopro-server/windbot && \
......
...@@ -11,6 +11,8 @@ const typedefs_json_1 = __importDefault(require("./data/typedefs.json")); ...@@ -11,6 +11,8 @@ const typedefs_json_1 = __importDefault(require("./data/typedefs.json"));
const proto_structs_json_1 = __importDefault(require("./data/proto_structs.json")); const proto_structs_json_1 = __importDefault(require("./data/proto_structs.json"));
const constants_json_1 = __importDefault(require("./data/constants.json")); const constants_json_1 = __importDefault(require("./data/constants.json"));
class Handler { class Handler {
handler;
synchronous;
constructor(handler, synchronous) { constructor(handler, synchronous) {
this.handler = handler; this.handler = handler;
this.synchronous = synchronous || false; this.synchronous = synchronous || false;
...@@ -28,6 +30,13 @@ class Handler { ...@@ -28,6 +30,13 @@ class Handler {
} }
} }
class YGOProMessagesHelper { class YGOProMessagesHelper {
handlers;
structs;
structs_declaration;
typedefs;
proto_structs;
constants;
singleHandleLimit;
constructor(singleHandleLimit) { constructor(singleHandleLimit) {
this.handlers = { this.handlers = {
STOC: [new Map(), STOC: [new Map(),
...@@ -62,7 +71,7 @@ class YGOProMessagesHelper { ...@@ -62,7 +71,7 @@ class YGOProMessagesHelper {
this.structs = new Map(); this.structs = new Map();
for (let name in this.structs_declaration) { for (let name in this.structs_declaration) {
const declaration = this.structs_declaration[name]; const declaration = this.structs_declaration[name];
let result = struct_1.Struct(); let result = (0, struct_1.Struct)();
for (let field of declaration) { for (let field of declaration) {
if (field.encoding) { if (field.encoding) {
switch (field.encoding) { switch (field.encoding) {
...@@ -171,12 +180,13 @@ class YGOProMessagesHelper { ...@@ -171,12 +180,13 @@ class YGOProMessagesHelper {
} }
handlerCollection.get(translatedProto).push(handlerObj); handlerCollection.get(translatedProto).push(handlerObj);
} }
async handleBuffer(messageBuffer, direction, protoFilter, params) { async handleBuffer(messageBuffer, direction, protoFilter, params, preconnect = false) {
let feedback = null; let feedback = null;
let messageLength = 0; let messageLength = 0;
let bufferProto = 0; let bufferProto = 0;
let datas = []; let datas = [];
for (let l = 0; l < this.singleHandleLimit; ++l) { const limit = preconnect ? 2 : this.singleHandleLimit;
for (let l = 0; l < limit; ++l) {
if (messageLength === 0) { if (messageLength === 0) {
if (messageBuffer.length >= 2) { if (messageBuffer.length >= 2) {
messageLength = messageBuffer.readUInt16LE(0); messageLength = messageBuffer.readUInt16LE(0);
...@@ -206,7 +216,14 @@ class YGOProMessagesHelper { ...@@ -206,7 +216,14 @@ class YGOProMessagesHelper {
else { else {
if (messageBuffer.length >= 2 + messageLength) { if (messageBuffer.length >= 2 + messageLength) {
const proto = this.constants[direction][bufferProto]; const proto = this.constants[direction][bufferProto];
let cancel = proto && protoFilter && underscore_1.default.indexOf(protoFilter, proto) === -1; let cancel = proto && protoFilter && !protoFilter.includes(proto);
if (cancel && preconnect) {
feedback = {
type: "INVALID_PACKET",
message: `${direction} proto not allowed`
};
break;
}
let buffer = messageBuffer.slice(3, 2 + messageLength); let buffer = messageBuffer.slice(3, 2 + messageLength);
//console.log(l, direction, proto, cancel); //console.log(l, direction, proto, cancel);
for (let priority = 0; priority < 4; ++priority) { for (let priority = 0; priority < 4; ++priority) {
...@@ -224,6 +241,12 @@ class YGOProMessagesHelper { ...@@ -224,6 +241,12 @@ class YGOProMessagesHelper {
for (let handler of handlerCollection.get(bufferProto)) { for (let handler of handlerCollection.get(bufferProto)) {
cancel = await handler.handle(buffer, info, datas, params); cancel = await handler.handle(buffer, info, datas, params);
if (cancel) { if (cancel) {
if (cancel === '_cancel') {
return {
datas: [],
feedback
};
}
break; break;
} }
} }
...@@ -246,10 +269,10 @@ class YGOProMessagesHelper { ...@@ -246,10 +269,10 @@ class YGOProMessagesHelper {
break; break;
} }
} }
if (l === this.singleHandleLimit - 1) { if (l === limit - 1) {
feedback = { feedback = {
type: "OVERSIZE", type: "OVERSIZE",
message: `Oversized ${direction}` message: `Oversized ${direction} ${limit}`
}; };
} }
} }
......
...@@ -8,13 +8,13 @@ import net from "net"; ...@@ -8,13 +8,13 @@ import net from "net";
class Handler { class Handler {
private handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean>; private handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string>;
synchronous: boolean; synchronous: boolean;
constructor(handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean>, synchronous: boolean) { constructor(handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string>, synchronous: boolean) {
this.handler = handler; this.handler = handler;
this.synchronous = synchronous || false; this.synchronous = synchronous || false;
} }
async handle(buffer: Buffer, info: any, datas: Buffer[], params: any) { async handle(buffer: Buffer, info: any, datas: Buffer[], params: any): Promise<boolean | string> {
if (this.synchronous) { if (this.synchronous) {
return !!(await this.handler(buffer, info, datas, params)); return !!(await this.handler(buffer, info, datas, params));
} else { } else {
...@@ -208,7 +208,7 @@ export class YGOProMessagesHelper { ...@@ -208,7 +208,7 @@ export class YGOProMessagesHelper {
}); });
} }
addHandler(protostr: string, handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean>, synchronous: boolean, priority: number) { addHandler(protostr: string, handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string>, synchronous: boolean, priority: number) {
if (priority < 0 || priority > 4) { if (priority < 0 || priority > 4) {
throw "Invalid priority: " + priority; throw "Invalid priority: " + priority;
} }
...@@ -226,12 +226,13 @@ export class YGOProMessagesHelper { ...@@ -226,12 +226,13 @@ export class YGOProMessagesHelper {
handlerCollection.get(translatedProto).push(handlerObj); handlerCollection.get(translatedProto).push(handlerObj);
} }
async handleBuffer(messageBuffer: Buffer, direction: string, protoFilter?: string[], params?: any): Promise<HandleResult> { async handleBuffer(messageBuffer: Buffer, direction: string, protoFilter?: string[], params?: any, preconnect = false): Promise<HandleResult> {
let feedback: Feedback = null; let feedback: Feedback = null;
let messageLength = 0; let messageLength = 0;
let bufferProto = 0; let bufferProto = 0;
let datas: Buffer[] = []; let datas: Buffer[] = [];
for (let l = 0; l < this.singleHandleLimit; ++l) { const limit = preconnect ? 2 : this.singleHandleLimit;
for (let l = 0; l < limit; ++l) {
if (messageLength === 0) { if (messageLength === 0) {
if (messageBuffer.length >= 2) { if (messageBuffer.length >= 2) {
messageLength = messageBuffer.readUInt16LE(0); messageLength = messageBuffer.readUInt16LE(0);
...@@ -257,7 +258,14 @@ export class YGOProMessagesHelper { ...@@ -257,7 +258,14 @@ export class YGOProMessagesHelper {
} else { } else {
if (messageBuffer.length >= 2 + messageLength) { if (messageBuffer.length >= 2 + messageLength) {
const proto = this.constants[direction][bufferProto]; const proto = this.constants[direction][bufferProto];
let cancel = proto && protoFilter && _.indexOf(protoFilter, proto) === -1; let cancel: string | boolean = proto && protoFilter && !protoFilter.includes(proto);
if (cancel && preconnect) {
feedback = {
type: "INVALID_PACKET",
message: `${direction} proto not allowed`
};
break;
}
let buffer = messageBuffer.slice(3, 2 + messageLength); let buffer = messageBuffer.slice(3, 2 + messageLength);
//console.log(l, direction, proto, cancel); //console.log(l, direction, proto, cancel);
for (let priority = 0; priority < 4; ++priority) { for (let priority = 0; priority < 4; ++priority) {
...@@ -275,6 +283,12 @@ export class YGOProMessagesHelper { ...@@ -275,6 +283,12 @@ export class YGOProMessagesHelper {
for (let handler of handlerCollection.get(bufferProto)) { for (let handler of handlerCollection.get(bufferProto)) {
cancel = await handler.handle(buffer, info, datas, params); cancel = await handler.handle(buffer, info, datas, params);
if (cancel) { if (cancel) {
if (cancel === '_cancel') {
return {
datas: [],
feedback
}
}
break; break;
} }
} }
...@@ -296,10 +310,10 @@ export class YGOProMessagesHelper { ...@@ -296,10 +310,10 @@ export class YGOProMessagesHelper {
break; break;
} }
} }
if (l === this.singleHandleLimit - 1) { if (l === limit - 1) {
feedback = { feedback = {
type: "OVERSIZE", type: "OVERSIZE",
message: `Oversized ${direction}` message: `Oversized ${direction} ${limit}`
}; };
} }
} }
......
...@@ -8,6 +8,9 @@ const axios_1 = __importDefault(require("axios")); ...@@ -8,6 +8,9 @@ const axios_1 = __importDefault(require("axios"));
const querystring_1 = __importDefault(require("querystring")); const querystring_1 = __importDefault(require("querystring"));
const moment_1 = __importDefault(require("moment")); const moment_1 = __importDefault(require("moment"));
class AthleticChecker { class AthleticChecker {
config;
athleticDeckCache;
lastAthleticDeckFetchTime;
constructor(config) { constructor(config) {
this.config = config; this.config = config;
} }
...@@ -16,7 +19,7 @@ class AthleticChecker { ...@@ -16,7 +19,7 @@ class AthleticChecker {
return deckText; return deckText;
} }
async getAthleticDecks() { async getAthleticDecks() {
if (this.athleticDeckCache && moment_1.default().diff(this.lastAthleticDeckFetchTime, "seconds") < this.config.ttl) { if (this.athleticDeckCache && (0, moment_1.default)().diff(this.lastAthleticDeckFetchTime, "seconds") < this.config.ttl) {
return this.athleticDeckCache; return this.athleticDeckCache;
} }
const { data } = await axios_1.default.get(this.config.rankURL, { const { data } = await axios_1.default.get(this.config.rankURL, {
...@@ -27,7 +30,7 @@ class AthleticChecker { ...@@ -27,7 +30,7 @@ class AthleticChecker {
}); });
const athleticDecks = data.slice(0, this.config.rankCount).map(m => m.name); const athleticDecks = data.slice(0, this.config.rankCount).map(m => m.name);
this.athleticDeckCache = athleticDecks; this.athleticDeckCache = athleticDecks;
this.lastAthleticDeckFetchTime = moment_1.default(); this.lastAthleticDeckFetchTime = (0, moment_1.default)();
return athleticDecks; return athleticDecks;
} }
async getDeckType(deck) { async getDeckType(deck) {
...@@ -42,7 +45,7 @@ class AthleticChecker { ...@@ -42,7 +45,7 @@ class AthleticChecker {
try { try {
const athleticDecks = await this.getAthleticDecks(); const athleticDecks = await this.getAthleticDecks();
const deckType = await this.getDeckType(deck); const deckType = await this.getDeckType(deck);
const athletic = athleticDecks.includes(deckType); const athletic = athleticDecks.findIndex(d => d === deckType) + 1;
return { success: true, athletic, message: null }; return { success: true, athletic, message: null };
} }
catch (e) { catch (e) {
......
...@@ -21,7 +21,7 @@ interface AthleticDecksReturnData { ...@@ -21,7 +21,7 @@ interface AthleticDecksReturnData {
interface ReturnMessage { interface ReturnMessage {
success: boolean; success: boolean;
athletic?: boolean; athletic?: number;
message: string; message: string;
} }
...@@ -63,8 +63,8 @@ export class AthleticChecker { ...@@ -63,8 +63,8 @@ export class AthleticChecker {
try { try {
const athleticDecks = await this.getAthleticDecks(); const athleticDecks = await this.getAthleticDecks();
const deckType = await this.getDeckType(deck); const deckType = await this.getDeckType(deck);
const athletic = athleticDecks.includes(deckType); const athletic = athleticDecks.findIndex(d => d === deckType) + 1;
return { success: true, athletic, message: null } return { success: true, athletic, message: null };
} catch (e) { } catch (e) {
return { success: false, message: e.toString() }; return { success: false, message: e.toString() };
} }
......
...@@ -40,35 +40,40 @@ const jszip_1 = __importDefault(require("jszip")); ...@@ -40,35 +40,40 @@ const jszip_1 = __importDefault(require("jszip"));
const fs = __importStar(require("fs")); const fs = __importStar(require("fs"));
require("reflect-metadata"); require("reflect-metadata");
class DataManager { class DataManager {
config;
log;
ready;
db;
constructor(config, log) { constructor(config, log) {
this.config = config; this.config = config;
this.ready = false;
this.log = log; this.log = log;
this.ready = false;
} }
async transaction(fun) { async transaction(fun) {
const runner = this.db.createQueryRunner();
await runner.connect();
await runner.startTransaction();
let result = false;
try { try {
result = await fun(runner.manager); // @ts-ignore
if (this.config.type !== 'sqlite') {
this.db.transaction(async (mdb) => {
const result = await fun(mdb);
if (!result) {
throw new Error('Rollback requested.');
}
});
}
else {
await fun(this.db.manager);
}
} }
catch (e) { catch (e) {
result = false; this.log.warn(`Transaction failed: ${e.toString()}`);
this.log.warn(`Failed running transaction: ${e.toString()}`);
}
if (result) {
await runner.commitTransaction();
} }
else {
await runner.rollbackTransaction();
}
await runner.release();
} }
async init() { async init() {
this.db = await typeorm_1.createConnection({ this.db = await (0, typeorm_1.createConnection)({
type: "mysql", type: "mysql",
synchronize: true, synchronize: true,
supportBigNumbers: true,
bigNumberStrings: false,
entities: ["./data-manager/entities/*.js"], entities: ["./data-manager/entities/*.js"],
...this.config ...this.config
}); });
...@@ -76,8 +81,13 @@ class DataManager { ...@@ -76,8 +81,13 @@ class DataManager {
} }
async getCloudReplaysFromKey(key) { async getCloudReplaysFromKey(key) {
try { try {
const replays = await this.db.createQueryBuilder(CloudReplay_1.CloudReplay, "replay") const replaysQuery = this.db.createQueryBuilder(CloudReplay_1.CloudReplay, "replay");
.where("exists (select id from cloud_replay_player where cloud_replay_player.cloudReplayId = replay.id and cloud_replay_player.key = :key)", { key }) const sqb = replaysQuery.subQuery()
.select('splayer.id')
.from(CloudReplayPlayer_1.CloudReplayPlayer, 'splayer')
.where('splayer.cloudReplayId = replay.id')
.andWhere('splayer.key = :key');
const replays = await replaysQuery.where(`exists ${sqb.getQuery()}`, { key })
.orderBy("replay.date", "DESC") .orderBy("replay.date", "DESC")
.limit(10) .limit(10)
.leftJoinAndSelect("replay.players", "player") .leftJoinAndSelect("replay.players", "player")
...@@ -125,7 +135,7 @@ class DataManager { ...@@ -125,7 +135,7 @@ class DataManager {
const replay = new CloudReplay_1.CloudReplay(); const replay = new CloudReplay_1.CloudReplay();
replay.id = id; replay.id = id;
replay.fromBuffer(buffer); replay.fromBuffer(buffer);
replay.date = moment_1.default().toDate(); replay.date = (0, moment_1.default)().toDate();
const players = playerInfos.map(p => { const players = playerInfos.map(p => {
const player = CloudReplayPlayer_1.CloudReplayPlayer.fromPlayerInfo(p); const player = CloudReplayPlayer_1.CloudReplayPlayer.fromPlayerInfo(p);
return player; return player;
...@@ -216,12 +226,12 @@ class DataManager { ...@@ -216,12 +226,12 @@ class DataManager {
if (ban) { if (ban) {
ban.count += count; ban.count += count;
const banTime = ban.count > 3 ? Math.pow(2, ban.count - 3) * 2 : 0; const banTime = ban.count > 3 ? Math.pow(2, ban.count - 3) * 2 : 0;
const banDate = moment_1.default(ban.time); const banDate = (0, moment_1.default)(ban.time);
if (moment_1.default().isAfter(banDate)) { if ((0, moment_1.default)().isAfter(banDate)) {
ban.time = moment_1.default().add(banTime, 'm').toDate(); ban.time = (0, moment_1.default)().add(banTime, 'm').toDate();
} }
else { else {
ban.time = moment_1.default(banDate).add(banTime, 'm').toDate(); ban.time = (0, moment_1.default)(banDate).add(banTime, 'm').toDate();
} }
if (!underscore_1.default.contains(ban.reasons, reason)) { if (!underscore_1.default.contains(ban.reasons, reason)) {
ban.reasons.push(reason); ban.reasons.push(reason);
...@@ -231,7 +241,7 @@ class DataManager { ...@@ -231,7 +241,7 @@ class DataManager {
else { else {
ban = new RandomDuelBan_1.RandomDuelBan(); ban = new RandomDuelBan_1.RandomDuelBan();
ban.ip = ip; ban.ip = ip;
ban.time = moment_1.default().toDate(); ban.time = (0, moment_1.default)().toDate();
ban.count = count; ban.count = count;
ban.reasons = [reason]; ban.reasons = [reason];
ban.needTip = 1; ban.needTip = 1;
...@@ -275,18 +285,24 @@ class DataManager { ...@@ -275,18 +285,24 @@ class DataManager {
queryBuilder.andWhere("duelLog.duelCount = :duelCount", { duelCount }); queryBuilder.andWhere("duelLog.duelCount = :duelCount", { duelCount });
} }
if (playerName != null && playerName.length || playerScore != null && !isNaN(playerScore)) { if (playerName != null && playerName.length || playerScore != null && !isNaN(playerScore)) {
let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id"; const sqb = queryBuilder.subQuery()
.select('splayer.id')
.from(DuelLogPlayer_1.DuelLogPlayer, 'splayer')
.where('splayer.duelLogId = duelLog.id');
//let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id";
const innerQueryParams = {}; const innerQueryParams = {};
if (playerName != null && playerName.length) { if (playerName != null && playerName.length) {
//const escapedPlayerName = this.getEscapedString(playerName); //const escapedPlayerName = this.getEscapedString(playerName);
innerQuery += " and duel_log_player.realName = :playerName"; sqb.andWhere('splayer.realName = :playerName');
//innerQuery += " and duel_log_player.realName = :playerName";
innerQueryParams.playerName = playerName; innerQueryParams.playerName = playerName;
} }
if (playerScore != null && !isNaN(playerScore)) { if (playerScore != null && !isNaN(playerScore)) {
innerQuery += " and duel_log_player.score = :playerScore"; //innerQuery += " and duel_log_player.score = :playerScore";
sqb.andWhere('splayer.score = :playerScore');
innerQueryParams.playerScore = playerScore; innerQueryParams.playerScore = playerScore;
} }
queryBuilder.andWhere(`exists (${innerQuery})`, innerQueryParams); queryBuilder.andWhere(`exists ${sqb.getQuery()}`, innerQueryParams);
} }
queryBuilder.orderBy("duelLog.id", "DESC") queryBuilder.orderBy("duelLog.id", "DESC")
.leftJoinAndSelect("duelLog.players", "player"); .leftJoinAndSelect("duelLog.players", "player");
...@@ -313,8 +329,16 @@ class DataManager { ...@@ -313,8 +329,16 @@ class DataManager {
async getDuelLogFromRecoverSearch(realName) { async getDuelLogFromRecoverSearch(realName) {
const repo = this.db.getRepository(DuelLog_1.DuelLog); const repo = this.db.getRepository(DuelLog_1.DuelLog);
try { try {
const duelLogs = await repo.createQueryBuilder("duelLog") const duelLogsQuery = repo.createQueryBuilder("duelLog")
.where("startDeckBuffer is not null and currentDeckBuffer is not null and roomMode != 2 and exists (select id from duel_log_player where duel_log_player.duelLogId = duelLog.id and duel_log_player.realName = :realName)", { realName }) .where('startDeckBuffer is not null')
.andWhere('currentDeckBuffer is not null')
.andWhere('roomMode != 2');
const sqb = duelLogsQuery.subQuery()
.select('splayer.id')
.from(DuelLogPlayer_1.DuelLogPlayer, 'splayer')
.andWhere('splayer.duelLogId = duelLog.id')
.andWhere('splayer.realName = :realName');
const duelLogs = await duelLogsQuery.andWhere(`exists ${sqb.getQuery()}`, { realName })
.orderBy("duelLog.id", "DESC") .orderBy("duelLog.id", "DESC")
.limit(10) .limit(10)
.leftJoinAndSelect("duelLog.players", "player") .leftJoinAndSelect("duelLog.players", "player")
...@@ -392,7 +416,7 @@ class DataManager { ...@@ -392,7 +416,7 @@ class DataManager {
async saveDuelLog(name, roomId, cloudReplayId, replayFilename, roomMode, duelCount, playerInfos) { async saveDuelLog(name, roomId, cloudReplayId, replayFilename, roomMode, duelCount, playerInfos) {
const duelLog = new DuelLog_1.DuelLog(); const duelLog = new DuelLog_1.DuelLog();
duelLog.name = name; duelLog.name = name;
duelLog.time = moment_1.default().toDate(); duelLog.time = (0, moment_1.default)().toDate();
duelLog.roomId = roomId; duelLog.roomId = roomId;
duelLog.cloudReplayId = cloudReplayId; duelLog.cloudReplayId = cloudReplayId;
duelLog.replayFileName = replayFilename; duelLog.replayFileName = replayFilename;
...@@ -599,11 +623,11 @@ class DataManager { ...@@ -599,11 +623,11 @@ class DataManager {
} }
const keyType = vipKey.type; const keyType = vipKey.type;
const previousDate = user.vipExpireDate; const previousDate = user.vipExpireDate;
if (previousDate && moment_1.default().isBefore(previousDate)) { if (previousDate && (0, moment_1.default)().isBefore(previousDate)) {
user.vipExpireDate = moment_1.default(previousDate).add(keyType, "d").toDate(); user.vipExpireDate = (0, moment_1.default)(previousDate).add(keyType, "d").toDate();
} }
else { else {
user.vipExpireDate = moment_1.default().add(keyType, "d").toDate(); user.vipExpireDate = (0, moment_1.default)().add(keyType, "d").toDate();
} }
user = await mdb.save(user); user = await mdb.save(user);
vipKey.isUsed = 1; vipKey.isUsed = 1;
...@@ -647,7 +671,7 @@ class DataManager { ...@@ -647,7 +671,7 @@ class DataManager {
user = new User_1.User(); user = new User_1.User();
user.key = userKey; user.key = userKey;
} }
user.vipExpireDate = moment_1.default(oldVipUserInfo.expire_date).toDate(); user.vipExpireDate = (0, moment_1.default)(oldVipUserInfo.expire_date).toDate();
user.victory = oldVipUserInfo.victory || null; user.victory = oldVipUserInfo.victory || null;
user.words = oldVipUserInfo.words || null; user.words = oldVipUserInfo.words || null;
user = await mdb.save(user); user = await mdb.save(user);
......
import moment from "moment"; import moment from "moment";
import bunyan from "bunyan"; import bunyan from "bunyan";
import {Connection, ConnectionOptions, createConnection, EntityManager} from "typeorm"; import {Connection, createConnection, EntityManager} from "typeorm";
import {CloudReplay} from "./entities/CloudReplay"; import {CloudReplay} from "./entities/CloudReplay";
import {CloudReplayPlayer} from "./entities/CloudReplayPlayer"; import {CloudReplayPlayer} from "./entities/CloudReplayPlayer";
import {Ban} from "./entities/Ban"; import {Ban} from "./entities/Ban";
...@@ -16,6 +16,7 @@ import {RandomDuelScore} from "./entities/RandomDuelScore"; ...@@ -16,6 +16,7 @@ import {RandomDuelScore} from "./entities/RandomDuelScore";
import JSZip from "jszip"; import JSZip from "jszip";
import * as fs from "fs"; import * as fs from "fs";
import "reflect-metadata"; import "reflect-metadata";
import { MysqlConnectionOptions } from "typeorm/driver/mysql/MysqlConnectionOptions";
interface BasePlayerInfo { interface BasePlayerInfo {
name: string; name: string;
...@@ -42,37 +43,34 @@ export interface DuelLogQuery {roomName: string, duelCount: number, playerName: ...@@ -42,37 +43,34 @@ export interface DuelLogQuery {roomName: string, duelCount: number, playerName:
export class DataManager { export class DataManager {
config: ConnectionOptions;
ready: boolean; ready: boolean;
db: Connection; private db: Connection;
log: bunyan; constructor(private config: MysqlConnectionOptions, private log: bunyan) {
constructor(config: ConnectionOptions, log: bunyan) {
this.config = config;
this.ready = false; this.ready = false;
this.log = log;
} }
private async transaction(fun: (mdb: EntityManager) => Promise<boolean>) { private async transaction(fun: (mdb: EntityManager) => Promise<boolean>) {
const runner = this.db.createQueryRunner();
await runner.connect();
await runner.startTransaction();
let result = false;
try { try {
result = await fun(runner.manager); // @ts-ignore
} catch(e) { if (this.config.type !== 'sqlite') {
result = false; this.db.transaction(async (mdb) => {
this.log.warn(`Failed running transaction: ${e.toString()}`) const result = await fun(mdb);
} if (!result) {
if(result) { throw new Error('Rollback requested.');
await runner.commitTransaction(); }
} else { });
await runner.rollbackTransaction(); } else {
await fun(this.db.manager);
}
} catch (e) {
this.log.warn(`Transaction failed: ${e.toString()}`);
} }
await runner.release();
} }
async init() { async init() {
this.db = await createConnection({ this.db = await createConnection({
type: "mysql", type: "mysql",
synchronize: true, synchronize: true,
supportBigNumbers: true,
bigNumberStrings: false,
entities: ["./data-manager/entities/*.js"], entities: ["./data-manager/entities/*.js"],
...this.config ...this.config
}); });
...@@ -80,8 +78,13 @@ export class DataManager { ...@@ -80,8 +78,13 @@ export class DataManager {
} }
async getCloudReplaysFromKey(key: string) { async getCloudReplaysFromKey(key: string) {
try { try {
const replays = await this.db.createQueryBuilder(CloudReplay, "replay") const replaysQuery = this.db.createQueryBuilder(CloudReplay, "replay");
.where("exists (select id from cloud_replay_player where cloud_replay_player.cloudReplayId = replay.id and cloud_replay_player.key = :key)", { key }) const sqb = replaysQuery.subQuery()
.select('splayer.id')
.from(CloudReplayPlayer, 'splayer')
.where('splayer.cloudReplayId = replay.id')
.andWhere('splayer.key = :key');
const replays = await replaysQuery.where(`exists ${sqb.getQuery()}`, { key })
.orderBy("replay.date", "DESC") .orderBy("replay.date", "DESC")
.limit(10) .limit(10)
.leftJoinAndSelect("replay.players", "player") .leftJoinAndSelect("replay.players", "player")
...@@ -282,19 +285,25 @@ export class DataManager { ...@@ -282,19 +285,25 @@ export class DataManager {
if(duelCount != null && !isNaN(duelCount)) { if(duelCount != null && !isNaN(duelCount)) {
queryBuilder.andWhere("duelLog.duelCount = :duelCount", { duelCount }); queryBuilder.andWhere("duelLog.duelCount = :duelCount", { duelCount });
} }
if(playerName != null && playerName.length || playerScore != null && !isNaN(playerScore)) { if (playerName != null && playerName.length || playerScore != null && !isNaN(playerScore)) {
let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id"; const sqb = queryBuilder.subQuery()
.select('splayer.id')
.from(DuelLogPlayer, 'splayer')
.where('splayer.duelLogId = duelLog.id');
//let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id";
const innerQueryParams: any = {}; const innerQueryParams: any = {};
if(playerName != null && playerName.length) { if(playerName != null && playerName.length) {
//const escapedPlayerName = this.getEscapedString(playerName); //const escapedPlayerName = this.getEscapedString(playerName);
innerQuery += " and duel_log_player.realName = :playerName"; sqb.andWhere('splayer.realName = :playerName');
//innerQuery += " and duel_log_player.realName = :playerName";
innerQueryParams.playerName = playerName; innerQueryParams.playerName = playerName;
} }
if(playerScore != null && !isNaN(playerScore)) { if(playerScore != null && !isNaN(playerScore)) {
innerQuery += " and duel_log_player.score = :playerScore"; //innerQuery += " and duel_log_player.score = :playerScore";
sqb.andWhere('splayer.score = :playerScore');
innerQueryParams.playerScore = playerScore; innerQueryParams.playerScore = playerScore;
} }
queryBuilder.andWhere(`exists (${innerQuery})`, innerQueryParams); queryBuilder.andWhere(`exists ${sqb.getQuery()}`, innerQueryParams);
} }
queryBuilder.orderBy("duelLog.id", "DESC") queryBuilder.orderBy("duelLog.id", "DESC")
.leftJoinAndSelect("duelLog.players", "player"); .leftJoinAndSelect("duelLog.players", "player");
...@@ -322,8 +331,16 @@ export class DataManager { ...@@ -322,8 +331,16 @@ export class DataManager {
async getDuelLogFromRecoverSearch(realName: string) { async getDuelLogFromRecoverSearch(realName: string) {
const repo = this.db.getRepository(DuelLog); const repo = this.db.getRepository(DuelLog);
try { try {
const duelLogs = await repo.createQueryBuilder("duelLog") const duelLogsQuery = repo.createQueryBuilder("duelLog")
.where("startDeckBuffer is not null and currentDeckBuffer is not null and roomMode != 2 and exists (select id from duel_log_player where duel_log_player.duelLogId = duelLog.id and duel_log_player.realName = :realName)", { realName }) .where('startDeckBuffer is not null')
.andWhere('currentDeckBuffer is not null')
.andWhere('roomMode != 2');
const sqb = duelLogsQuery.subQuery()
.select('splayer.id')
.from(DuelLogPlayer, 'splayer')
.andWhere('splayer.duelLogId = duelLog.id')
.andWhere('splayer.realName = :realName');
const duelLogs = await duelLogsQuery.andWhere(`exists ${sqb.getQuery()}`, { realName })
.orderBy("duelLog.id", "DESC") .orderBy("duelLog.id", "DESC")
.limit(10) .limit(10)
.leftJoinAndSelect("duelLog.players", "player") .leftJoinAndSelect("duelLog.players", "player")
......
...@@ -17,7 +17,7 @@ function encodeDeck(deck) { ...@@ -17,7 +17,7 @@ function encodeDeck(deck) {
buffer.writeInt32LE(cardCode, pointer); buffer.writeInt32LE(cardCode, pointer);
pointer += 4; pointer += 4;
} }
assert_1.default(pointer === bufferSize, `Invalid buffer size. Expected: ${bufferSize}. Got: ${pointer}`); (0, assert_1.default)(pointer === bufferSize, `Invalid buffer size. Expected: ${bufferSize}. Got: ${pointer}`);
return buffer; return buffer;
} }
exports.encodeDeck = encodeDeck; exports.encodeDeck = encodeDeck;
...@@ -28,7 +28,7 @@ function decodeDeck(buffer) { ...@@ -28,7 +28,7 @@ function decodeDeck(buffer) {
const sideLength = buffer.readInt32LE(pointer); const sideLength = buffer.readInt32LE(pointer);
pointer += 4; pointer += 4;
const correctBufferLength = (2 + mainLength + sideLength) * 4; const correctBufferLength = (2 + mainLength + sideLength) * 4;
assert_1.default(buffer.length >= (2 + mainLength + sideLength) * 4, `Invalid buffer size. Expected: ${correctBufferLength}. Got: ${buffer.length}`); (0, assert_1.default)(buffer.length >= (2 + mainLength + sideLength) * 4, `Invalid buffer size. Expected: ${correctBufferLength}. Got: ${buffer.length}`);
const main = []; const main = [];
const side = []; const side = [];
for (let i = 0; i < mainLength; ++i) { for (let i = 0; i < mainLength; ++i) {
......
...@@ -13,24 +13,27 @@ exports.Ban = void 0; ...@@ -13,24 +13,27 @@ exports.Ban = void 0;
const typeorm_1 = require("typeorm"); const typeorm_1 = require("typeorm");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase"); const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let Ban = class Ban extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase { let Ban = class Ban extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
id;
ip;
name;
}; };
__decorate([ __decorate([
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: "bigint" }), (0, typeorm_1.PrimaryGeneratedColumn)({ unsigned: true, type: global.PrimaryKeyType || 'bigint' }),
__metadata("design:type", Number) __metadata("design:type", Number)
], Ban.prototype, "id", void 0); ], Ban.prototype, "id", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column({ type: "varchar", length: 64, nullable: true }), (0, typeorm_1.Column)({ type: "varchar", length: 64, nullable: true }),
__metadata("design:type", String) __metadata("design:type", String)
], Ban.prototype, "ip", void 0); ], Ban.prototype, "ip", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column({ type: "varchar", length: 20, nullable: true }), (0, typeorm_1.Column)({ type: "varchar", length: 20, nullable: true }),
__metadata("design:type", String) __metadata("design:type", String)
], Ban.prototype, "name", void 0); ], Ban.prototype, "name", void 0);
Ban = __decorate([ Ban = __decorate([
typeorm_1.Entity(), (0, typeorm_1.Entity)(),
typeorm_1.Unique(["ip", "name"]) (0, typeorm_1.Unique)(["ip", "name"])
], Ban); ], Ban);
exports.Ban = Ban; exports.Ban = Ban;
//# sourceMappingURL=Ban.js.map //# sourceMappingURL=Ban.js.map
\ No newline at end of file
...@@ -4,7 +4,7 @@ import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase"; ...@@ -4,7 +4,7 @@ import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase";
@Entity() @Entity()
@Unique(["ip", "name"]) @Unique(["ip", "name"])
export class Ban extends CreateAndUpdateTimeBase { export class Ban extends CreateAndUpdateTimeBase {
@PrimaryGeneratedColumn({ unsigned: true, type: "bigint" }) @PrimaryGeneratedColumn({ unsigned: true, type: (global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint' })
id: number; id: number;
@Index() @Index()
......
...@@ -13,17 +13,20 @@ exports.BasePlayer = void 0; ...@@ -13,17 +13,20 @@ exports.BasePlayer = void 0;
const typeorm_1 = require("typeorm"); const typeorm_1 = require("typeorm");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase"); const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
class BasePlayer extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase { class BasePlayer extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
id;
name;
pos;
} }
__decorate([ __decorate([
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: "bigint" }), (0, typeorm_1.PrimaryGeneratedColumn)({ unsigned: true, type: global.PrimaryKeyType || 'bigint' }),
__metadata("design:type", Number) __metadata("design:type", Number)
], BasePlayer.prototype, "id", void 0); ], BasePlayer.prototype, "id", void 0);
__decorate([ __decorate([
typeorm_1.Column({ type: "varchar", length: 20 }), (0, typeorm_1.Column)({ type: "varchar", length: 20 }),
__metadata("design:type", String) __metadata("design:type", String)
], BasePlayer.prototype, "name", void 0); ], BasePlayer.prototype, "name", void 0);
__decorate([ __decorate([
typeorm_1.Column({ type: "tinyint" }), (0, typeorm_1.Column)({ type: "tinyint" }),
__metadata("design:type", Number) __metadata("design:type", Number)
], BasePlayer.prototype, "pos", void 0); ], BasePlayer.prototype, "pos", void 0);
exports.BasePlayer = BasePlayer; exports.BasePlayer = BasePlayer;
......
import {Column, PrimaryGeneratedColumn} from "typeorm"; import {Column, PrimaryGeneratedColumn} from "typeorm";
import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase"; import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase";
export abstract class BasePlayer extends CreateAndUpdateTimeBase { export abstract class BasePlayer extends CreateAndUpdateTimeBase {
@PrimaryGeneratedColumn({unsigned: true, type: "bigint"}) @PrimaryGeneratedColumn({unsigned: true, type: (global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint'})
id: number; id: number;
@Column({ type: "varchar", length: 20 }) @Column({ type: "varchar", length: 20 })
...@@ -10,4 +9,4 @@ export abstract class BasePlayer extends CreateAndUpdateTimeBase { ...@@ -10,4 +9,4 @@ export abstract class BasePlayer extends CreateAndUpdateTimeBase {
@Column({ type: "tinyint" }) @Column({ type: "tinyint" })
pos: number; pos: number;
} }
\ No newline at end of file
...@@ -19,15 +19,19 @@ const underscore_1 = __importDefault(require("underscore")); ...@@ -19,15 +19,19 @@ const underscore_1 = __importDefault(require("underscore"));
const moment_1 = __importDefault(require("moment")); const moment_1 = __importDefault(require("moment"));
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase"); const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let CloudReplay = class CloudReplay extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase { let CloudReplay = class CloudReplay extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
id;
data;
fromBuffer(buffer) { fromBuffer(buffer) {
this.data = buffer.toString("base64"); this.data = buffer.toString("base64");
} }
toBuffer() { toBuffer() {
return Buffer.from(this.data, "base64"); return Buffer.from(this.data, "base64");
} }
date;
getDateString() { getDateString() {
return moment_1.default(this.date).format('YYYY-MM-DD HH:mm:ss'); return (0, moment_1.default)(this.date).format('YYYY-MM-DD HH:mm:ss');
} }
players;
getPlayerNamesString() { getPlayerNamesString() {
const playerInfos = underscore_1.default.clone(this.players); const playerInfos = underscore_1.default.clone(this.players);
playerInfos.sort((p1, p2) => p1.pos - p2.pos); playerInfos.sort((p1, p2) => p1.pos - p2.pos);
...@@ -38,24 +42,24 @@ let CloudReplay = class CloudReplay extends CreateAndUpdateTimeBase_1.CreateAndU ...@@ -38,24 +42,24 @@ let CloudReplay = class CloudReplay extends CreateAndUpdateTimeBase_1.CreateAndU
} }
}; };
__decorate([ __decorate([
typeorm_1.PrimaryColumn({ unsigned: true, type: "bigint" }), (0, typeorm_1.PrimaryColumn)({ unsigned: true, type: global.PrimaryKeyType || 'bigint' }),
__metadata("design:type", Number) __metadata("design:type", Number)
], CloudReplay.prototype, "id", void 0); ], CloudReplay.prototype, "id", void 0);
__decorate([ __decorate([
typeorm_1.Column({ type: "text" }), (0, typeorm_1.Column)({ type: "text" }),
__metadata("design:type", String) __metadata("design:type", String)
], CloudReplay.prototype, "data", void 0); ], CloudReplay.prototype, "data", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column({ type: "datetime" }), (0, typeorm_1.Column)({ type: "datetime" }),
__metadata("design:type", Date) __metadata("design:type", Date)
], CloudReplay.prototype, "date", void 0); ], CloudReplay.prototype, "date", void 0);
__decorate([ __decorate([
typeorm_1.OneToMany(() => CloudReplayPlayer_1.CloudReplayPlayer, player => player.cloudReplay), (0, typeorm_1.OneToMany)(() => CloudReplayPlayer_1.CloudReplayPlayer, player => player.cloudReplay),
__metadata("design:type", Array) __metadata("design:type", Array)
], CloudReplay.prototype, "players", void 0); ], CloudReplay.prototype, "players", void 0);
CloudReplay = __decorate([ CloudReplay = __decorate([
typeorm_1.Entity({ (0, typeorm_1.Entity)({
orderBy: { orderBy: {
date: "DESC" date: "DESC"
} }
......
...@@ -10,7 +10,7 @@ import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase"; ...@@ -10,7 +10,7 @@ import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase";
} }
}) })
export class CloudReplay extends CreateAndUpdateTimeBase { export class CloudReplay extends CreateAndUpdateTimeBase {
@PrimaryColumn({ unsigned: true, type: "bigint" }) @PrimaryColumn({ unsigned: true, type: (global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint' })
id: number; id: number;
@Column({ type: "text" }) @Column({ type: "text" })
......
...@@ -15,6 +15,8 @@ const typeorm_1 = require("typeorm"); ...@@ -15,6 +15,8 @@ const typeorm_1 = require("typeorm");
const CloudReplay_1 = require("./CloudReplay"); const CloudReplay_1 = require("./CloudReplay");
const BasePlayer_1 = require("./BasePlayer"); const BasePlayer_1 = require("./BasePlayer");
let CloudReplayPlayer = CloudReplayPlayer_1 = class CloudReplayPlayer extends BasePlayer_1.BasePlayer { let CloudReplayPlayer = CloudReplayPlayer_1 = class CloudReplayPlayer extends BasePlayer_1.BasePlayer {
key;
cloudReplay;
static fromPlayerInfo(info) { static fromPlayerInfo(info) {
const p = new CloudReplayPlayer_1(); const p = new CloudReplayPlayer_1();
p.key = info.key; p.key = info.key;
...@@ -24,16 +26,16 @@ let CloudReplayPlayer = CloudReplayPlayer_1 = class CloudReplayPlayer extends Ba ...@@ -24,16 +26,16 @@ let CloudReplayPlayer = CloudReplayPlayer_1 = class CloudReplayPlayer extends Ba
} }
}; };
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column({ type: "varchar", length: 128 }), (0, typeorm_1.Column)({ type: "varchar", length: 128 }),
__metadata("design:type", String) __metadata("design:type", String)
], CloudReplayPlayer.prototype, "key", void 0); ], CloudReplayPlayer.prototype, "key", void 0);
__decorate([ __decorate([
typeorm_1.ManyToOne(() => CloudReplay_1.CloudReplay, replay => replay.players), (0, typeorm_1.ManyToOne)(() => CloudReplay_1.CloudReplay, replay => replay.players),
__metadata("design:type", CloudReplay_1.CloudReplay) __metadata("design:type", CloudReplay_1.CloudReplay)
], CloudReplayPlayer.prototype, "cloudReplay", void 0); ], CloudReplayPlayer.prototype, "cloudReplay", void 0);
CloudReplayPlayer = CloudReplayPlayer_1 = __decorate([ CloudReplayPlayer = CloudReplayPlayer_1 = __decorate([
typeorm_1.Entity() (0, typeorm_1.Entity)()
], CloudReplayPlayer); ], CloudReplayPlayer);
exports.CloudReplayPlayer = CloudReplayPlayer; exports.CloudReplayPlayer = CloudReplayPlayer;
//# sourceMappingURL=CloudReplayPlayer.js.map //# sourceMappingURL=CloudReplayPlayer.js.map
\ No newline at end of file
...@@ -12,13 +12,15 @@ Object.defineProperty(exports, "__esModule", { value: true }); ...@@ -12,13 +12,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateAndUpdateTimeBase = void 0; exports.CreateAndUpdateTimeBase = void 0;
const typeorm_1 = require("typeorm"); const typeorm_1 = require("typeorm");
class CreateAndUpdateTimeBase { class CreateAndUpdateTimeBase {
createTime;
updateTime;
} }
__decorate([ __decorate([
typeorm_1.CreateDateColumn(), (0, typeorm_1.CreateDateColumn)(),
__metadata("design:type", Date) __metadata("design:type", Date)
], CreateAndUpdateTimeBase.prototype, "createTime", void 0); ], CreateAndUpdateTimeBase.prototype, "createTime", void 0);
__decorate([ __decorate([
typeorm_1.UpdateDateColumn(), (0, typeorm_1.UpdateDateColumn)(),
__metadata("design:type", Date) __metadata("design:type", Date)
], CreateAndUpdateTimeBase.prototype, "updateTime", void 0); ], CreateAndUpdateTimeBase.prototype, "updateTime", void 0);
exports.CreateAndUpdateTimeBase = CreateAndUpdateTimeBase; exports.CreateAndUpdateTimeBase = CreateAndUpdateTimeBase;
......
...@@ -19,16 +19,25 @@ const moment_1 = __importDefault(require("moment")); ...@@ -19,16 +19,25 @@ const moment_1 = __importDefault(require("moment"));
const underscore_1 = __importDefault(require("underscore")); const underscore_1 = __importDefault(require("underscore"));
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase"); const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let DuelLog = class DuelLog extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase { let DuelLog = class DuelLog extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
id;
time;
name;
roomId;
cloudReplayId; // not very needed to become a relation
replayFileName;
roomMode;
duelCount;
players;
getViewString() { getViewString() {
const viewPlayers = underscore_1.default.clone(this.players); const viewPlayers = underscore_1.default.clone(this.players);
viewPlayers.sort((p1, p2) => p1.pos - p2.pos); viewPlayers.sort((p1, p2) => p1.pos - p2.pos);
const playerString = viewPlayers[0].realName.split("$")[0] + (viewPlayers[2] ? "+" + viewPlayers[2].realName.split("$")[0] : "") + " VS " + (viewPlayers[1] ? viewPlayers[1].realName.split("$")[0] : "AI") + (viewPlayers[3] ? "+" + viewPlayers[3].realName.split("$")[0] : ""); const playerString = viewPlayers[0].realName.split("$")[0] + (viewPlayers[2] ? "+" + viewPlayers[2].realName.split("$")[0] : "") + " VS " + (viewPlayers[1] ? viewPlayers[1].realName.split("$")[0] : "AI") + (viewPlayers[3] ? "+" + viewPlayers[3].realName.split("$")[0] : "");
return `<${this.id}> ${playerString} ${moment_1.default(this.time).format("YYYY-MM-DD HH-mm-ss")}`; return `<${this.id}> ${playerString} ${(0, moment_1.default)(this.time).format("YYYY-MM-DD HH-mm-ss")}`;
} }
getViewJSON(tournamentModeSettings) { getViewJSON(tournamentModeSettings) {
const data = { const data = {
id: this.id, id: this.id,
time: moment_1.default(this.time).format("YYYY-MM-DD HH:mm:ss"), time: (0, moment_1.default)(this.time).format("YYYY-MM-DD HH:mm:ss"),
name: this.name + (tournamentModeSettings.show_info ? " (Duel:" + this.duelCount + ")" : ""), name: this.name + (tournamentModeSettings.show_info ? " (Duel:" + this.duelCount + ")" : ""),
roomid: this.roomId, roomid: this.roomId,
cloud_replay_id: "R#" + this.cloudReplayId, cloud_replay_id: "R#" + this.cloudReplayId,
...@@ -47,46 +56,46 @@ let DuelLog = class DuelLog extends CreateAndUpdateTimeBase_1.CreateAndUpdateTim ...@@ -47,46 +56,46 @@ let DuelLog = class DuelLog extends CreateAndUpdateTimeBase_1.CreateAndUpdateTim
} }
}; };
__decorate([ __decorate([
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: "bigint" }), (0, typeorm_1.PrimaryGeneratedColumn)({ unsigned: true, type: global.PrimaryKeyType || 'bigint' }),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLog.prototype, "id", void 0); ], DuelLog.prototype, "id", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column("datetime"), (0, typeorm_1.Column)("datetime"),
__metadata("design:type", Date) __metadata("design:type", Date)
], DuelLog.prototype, "time", void 0); ], DuelLog.prototype, "time", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column({ type: "varchar", length: 20 }), (0, typeorm_1.Column)({ type: "varchar", length: 20 }),
__metadata("design:type", String) __metadata("design:type", String)
], DuelLog.prototype, "name", void 0); ], DuelLog.prototype, "name", void 0);
__decorate([ __decorate([
typeorm_1.Column("int"), (0, typeorm_1.Column)("int"),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLog.prototype, "roomId", void 0); ], DuelLog.prototype, "roomId", void 0);
__decorate([ __decorate([
typeorm_1.Column("bigint"), (0, typeorm_1.Column)(global.PrimaryKeyType || 'bigint'),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLog.prototype, "cloudReplayId", void 0); ], DuelLog.prototype, "cloudReplayId", void 0);
__decorate([ __decorate([
typeorm_1.Column({ type: "varchar", length: 256 }), (0, typeorm_1.Column)({ type: "varchar", length: 256 }),
__metadata("design:type", String) __metadata("design:type", String)
], DuelLog.prototype, "replayFileName", void 0); ], DuelLog.prototype, "replayFileName", void 0);
__decorate([ __decorate([
typeorm_1.Column("tinyint", { unsigned: true }), (0, typeorm_1.Column)("tinyint", { unsigned: true }),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLog.prototype, "roomMode", void 0); ], DuelLog.prototype, "roomMode", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column("tinyint", { unsigned: true }), (0, typeorm_1.Column)("tinyint", { unsigned: true }),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLog.prototype, "duelCount", void 0); ], DuelLog.prototype, "duelCount", void 0);
__decorate([ __decorate([
typeorm_1.OneToMany(() => DuelLogPlayer_1.DuelLogPlayer, player => player.duelLog), (0, typeorm_1.OneToMany)(() => DuelLogPlayer_1.DuelLogPlayer, player => player.duelLog),
__metadata("design:type", Array) __metadata("design:type", Array)
], DuelLog.prototype, "players", void 0); ], DuelLog.prototype, "players", void 0);
DuelLog = __decorate([ DuelLog = __decorate([
typeorm_1.Entity({ (0, typeorm_1.Entity)({
orderBy: { orderBy: {
id: "DESC" id: "DESC"
} }
......
...@@ -10,7 +10,7 @@ import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase"; ...@@ -10,7 +10,7 @@ import {CreateAndUpdateTimeBase} from "./CreateAndUpdateTimeBase";
} }
}) })
export class DuelLog extends CreateAndUpdateTimeBase { export class DuelLog extends CreateAndUpdateTimeBase {
@PrimaryGeneratedColumn({unsigned: true, type: "bigint"}) @PrimaryGeneratedColumn({unsigned: true, type: (global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint'})
id: number; id: number;
@Index() @Index()
...@@ -24,7 +24,7 @@ export class DuelLog extends CreateAndUpdateTimeBase { ...@@ -24,7 +24,7 @@ export class DuelLog extends CreateAndUpdateTimeBase {
@Column("int") @Column("int")
roomId: number; roomId: number;
@Column("bigint") @Column((global as any).PrimaryKeyType as ('bigint' | 'integer') || 'bigint')
cloudReplayId: number; // not very needed to become a relation cloudReplayId: number; // not very needed to become a relation
@Column({type: "varchar", length: 256}) @Column({type: "varchar", length: 256})
...@@ -67,4 +67,4 @@ export class DuelLog extends CreateAndUpdateTimeBase { ...@@ -67,4 +67,4 @@ export class DuelLog extends CreateAndUpdateTimeBase {
} }
return data; return data;
} }
} }
\ No newline at end of file
...@@ -16,26 +16,36 @@ const BasePlayer_1 = require("./BasePlayer"); ...@@ -16,26 +16,36 @@ const BasePlayer_1 = require("./BasePlayer");
const DuelLog_1 = require("./DuelLog"); const DuelLog_1 = require("./DuelLog");
const DeckEncoder_1 = require("../DeckEncoder"); const DeckEncoder_1 = require("../DeckEncoder");
let DuelLogPlayer = DuelLogPlayer_1 = class DuelLogPlayer extends BasePlayer_1.BasePlayer { let DuelLogPlayer = DuelLogPlayer_1 = class DuelLogPlayer extends BasePlayer_1.BasePlayer {
realName;
ip;
isFirst;
score;
lp;
cardCount;
startDeckBuffer;
currentDeckBuffer;
winner;
setStartDeck(deck) { setStartDeck(deck) {
if (deck === null) { if (deck === null) {
this.startDeckBuffer = null; this.startDeckBuffer = null;
return; return;
} }
this.startDeckBuffer = DeckEncoder_1.encodeDeck(deck).toString("base64"); this.startDeckBuffer = (0, DeckEncoder_1.encodeDeck)(deck).toString("base64");
} }
getStartDeck() { getStartDeck() {
return DeckEncoder_1.decodeDeck(Buffer.from(this.startDeckBuffer, "base64")); return (0, DeckEncoder_1.decodeDeck)(Buffer.from(this.startDeckBuffer, "base64"));
} }
setCurrentDeck(deck) { setCurrentDeck(deck) {
if (deck === null) { if (deck === null) {
this.currentDeckBuffer = null; this.currentDeckBuffer = null;
return; return;
} }
this.currentDeckBuffer = DeckEncoder_1.encodeDeck(deck).toString("base64"); this.currentDeckBuffer = (0, DeckEncoder_1.encodeDeck)(deck).toString("base64");
} }
getCurrentDeck() { getCurrentDeck() {
return DeckEncoder_1.decodeDeck(Buffer.from(this.currentDeckBuffer, "base64")); return (0, DeckEncoder_1.decodeDeck)(Buffer.from(this.currentDeckBuffer, "base64"));
} }
duelLog;
static fromDuelLogPlayerInfo(info) { static fromDuelLogPlayerInfo(info) {
const p = new DuelLogPlayer_1(); const p = new DuelLogPlayer_1();
p.name = info.name; p.name = info.name;
...@@ -47,55 +57,55 @@ let DuelLogPlayer = DuelLogPlayer_1 = class DuelLogPlayer extends BasePlayer_1.B ...@@ -47,55 +57,55 @@ let DuelLogPlayer = DuelLogPlayer_1 = class DuelLogPlayer extends BasePlayer_1.B
p.cardCount = info.cardCount; p.cardCount = info.cardCount;
p.isFirst = info.isFirst ? 1 : 0; p.isFirst = info.isFirst ? 1 : 0;
p.winner = info.winner ? 1 : 0; p.winner = info.winner ? 1 : 0;
p.startDeckBuffer = info.startDeckBuffer.toString("base64"); p.startDeckBuffer = info.startDeckBuffer?.toString("base64") || null;
p.setCurrentDeck(info.deck); p.setCurrentDeck(info.deck);
return p; return p;
} }
}; };
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column({ type: "varchar", length: 20 }), (0, typeorm_1.Column)({ type: "varchar", length: 20 }),
__metadata("design:type", String) __metadata("design:type", String)
], DuelLogPlayer.prototype, "realName", void 0); ], DuelLogPlayer.prototype, "realName", void 0);
__decorate([ __decorate([
typeorm_1.Column({ type: "varchar", length: 64, nullable: true }), (0, typeorm_1.Column)({ type: "varchar", length: 64, nullable: true }),
__metadata("design:type", String) __metadata("design:type", String)
], DuelLogPlayer.prototype, "ip", void 0); ], DuelLogPlayer.prototype, "ip", void 0);
__decorate([ __decorate([
typeorm_1.Column("tinyint", { unsigned: true }), (0, typeorm_1.Column)("tinyint", { unsigned: true }),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLogPlayer.prototype, "isFirst", void 0); ], DuelLogPlayer.prototype, "isFirst", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column("tinyint"), (0, typeorm_1.Column)("tinyint"),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLogPlayer.prototype, "score", void 0); ], DuelLogPlayer.prototype, "score", void 0);
__decorate([ __decorate([
typeorm_1.Column("int", { nullable: true }), (0, typeorm_1.Column)("int", { nullable: true }),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLogPlayer.prototype, "lp", void 0); ], DuelLogPlayer.prototype, "lp", void 0);
__decorate([ __decorate([
typeorm_1.Column("smallint", { nullable: true }), (0, typeorm_1.Column)("smallint", { nullable: true }),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLogPlayer.prototype, "cardCount", void 0); ], DuelLogPlayer.prototype, "cardCount", void 0);
__decorate([ __decorate([
typeorm_1.Column("text", { nullable: true }), (0, typeorm_1.Column)("text", { nullable: true }),
__metadata("design:type", String) __metadata("design:type", String)
], DuelLogPlayer.prototype, "startDeckBuffer", void 0); ], DuelLogPlayer.prototype, "startDeckBuffer", void 0);
__decorate([ __decorate([
typeorm_1.Column("text", { nullable: true }), (0, typeorm_1.Column)("text", { nullable: true }),
__metadata("design:type", String) __metadata("design:type", String)
], DuelLogPlayer.prototype, "currentDeckBuffer", void 0); ], DuelLogPlayer.prototype, "currentDeckBuffer", void 0);
__decorate([ __decorate([
typeorm_1.Column("tinyint"), (0, typeorm_1.Column)("tinyint"),
__metadata("design:type", Number) __metadata("design:type", Number)
], DuelLogPlayer.prototype, "winner", void 0); ], DuelLogPlayer.prototype, "winner", void 0);
__decorate([ __decorate([
typeorm_1.ManyToOne(() => DuelLog_1.DuelLog, duelLog => duelLog.players), (0, typeorm_1.ManyToOne)(() => DuelLog_1.DuelLog, duelLog => duelLog.players),
__metadata("design:type", DuelLog_1.DuelLog) __metadata("design:type", DuelLog_1.DuelLog)
], DuelLogPlayer.prototype, "duelLog", void 0); ], DuelLogPlayer.prototype, "duelLog", void 0);
DuelLogPlayer = DuelLogPlayer_1 = __decorate([ DuelLogPlayer = DuelLogPlayer_1 = __decorate([
typeorm_1.Entity() (0, typeorm_1.Entity)()
], DuelLogPlayer); ], DuelLogPlayer);
exports.DuelLogPlayer = DuelLogPlayer; exports.DuelLogPlayer = DuelLogPlayer;
//# sourceMappingURL=DuelLogPlayer.js.map //# sourceMappingURL=DuelLogPlayer.js.map
\ No newline at end of file
...@@ -73,7 +73,7 @@ export class DuelLogPlayer extends BasePlayer { ...@@ -73,7 +73,7 @@ export class DuelLogPlayer extends BasePlayer {
p.cardCount = info.cardCount; p.cardCount = info.cardCount;
p.isFirst = info.isFirst ? 1 : 0; p.isFirst = info.isFirst ? 1 : 0;
p.winner = info.winner ? 1 : 0; p.winner = info.winner ? 1 : 0;
p.startDeckBuffer = info.startDeckBuffer.toString("base64"); p.startDeckBuffer = info.startDeckBuffer?.toString("base64") || null;
p.setCurrentDeck(info.deck); p.setCurrentDeck(info.deck);
return p; return p;
} }
......
...@@ -13,6 +13,11 @@ exports.RandomDuelBan = void 0; ...@@ -13,6 +13,11 @@ exports.RandomDuelBan = void 0;
const typeorm_1 = require("typeorm"); const typeorm_1 = require("typeorm");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase"); const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let RandomDuelBan = class RandomDuelBan extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase { let RandomDuelBan = class RandomDuelBan extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
ip;
time;
count;
reasons;
needTip;
setNeedTip(need) { setNeedTip(need) {
this.needTip = need ? 1 : 0; this.needTip = need ? 1 : 0;
} }
...@@ -21,27 +26,27 @@ let RandomDuelBan = class RandomDuelBan extends CreateAndUpdateTimeBase_1.Create ...@@ -21,27 +26,27 @@ let RandomDuelBan = class RandomDuelBan extends CreateAndUpdateTimeBase_1.Create
} }
}; };
__decorate([ __decorate([
typeorm_1.PrimaryColumn({ type: "varchar", length: 64 }), (0, typeorm_1.PrimaryColumn)({ type: "varchar", length: 64 }),
__metadata("design:type", String) __metadata("design:type", String)
], RandomDuelBan.prototype, "ip", void 0); ], RandomDuelBan.prototype, "ip", void 0);
__decorate([ __decorate([
typeorm_1.Column("datetime"), (0, typeorm_1.Column)("datetime"),
__metadata("design:type", Date) __metadata("design:type", Date)
], RandomDuelBan.prototype, "time", void 0); ], RandomDuelBan.prototype, "time", void 0);
__decorate([ __decorate([
typeorm_1.Column("smallint"), (0, typeorm_1.Column)("smallint"),
__metadata("design:type", Number) __metadata("design:type", Number)
], RandomDuelBan.prototype, "count", void 0); ], RandomDuelBan.prototype, "count", void 0);
__decorate([ __decorate([
typeorm_1.Column({ type: "simple-array" }), (0, typeorm_1.Column)({ type: "simple-array" }),
__metadata("design:type", Array) __metadata("design:type", Array)
], RandomDuelBan.prototype, "reasons", void 0); ], RandomDuelBan.prototype, "reasons", void 0);
__decorate([ __decorate([
typeorm_1.Column({ type: "tinyint", unsigned: true }), (0, typeorm_1.Column)({ type: "tinyint", unsigned: true }),
__metadata("design:type", Number) __metadata("design:type", Number)
], RandomDuelBan.prototype, "needTip", void 0); ], RandomDuelBan.prototype, "needTip", void 0);
RandomDuelBan = __decorate([ RandomDuelBan = __decorate([
typeorm_1.Entity() (0, typeorm_1.Entity)()
], RandomDuelBan); ], RandomDuelBan);
exports.RandomDuelBan = RandomDuelBan; exports.RandomDuelBan = RandomDuelBan;
//# sourceMappingURL=RandomDuelBan.js.map //# sourceMappingURL=RandomDuelBan.js.map
\ No newline at end of file
...@@ -13,6 +13,11 @@ exports.RandomDuelScore = void 0; ...@@ -13,6 +13,11 @@ exports.RandomDuelScore = void 0;
const typeorm_1 = require("typeorm"); const typeorm_1 = require("typeorm");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase"); const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let RandomDuelScore = class RandomDuelScore extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase { let RandomDuelScore = class RandomDuelScore extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
name;
winCount;
loseCount;
fleeCount;
winCombo;
getDisplayName() { getDisplayName() {
return this.name.split("$")[0]; return this.name.split("$")[0];
} }
...@@ -44,30 +49,30 @@ let RandomDuelScore = class RandomDuelScore extends CreateAndUpdateTimeBase_1.Cr ...@@ -44,30 +49,30 @@ let RandomDuelScore = class RandomDuelScore extends CreateAndUpdateTimeBase_1.Cr
} }
}; };
__decorate([ __decorate([
typeorm_1.PrimaryColumn({ type: "varchar", length: 20 }), (0, typeorm_1.PrimaryColumn)({ type: "varchar", length: 20 }),
__metadata("design:type", String) __metadata("design:type", String)
], RandomDuelScore.prototype, "name", void 0); ], RandomDuelScore.prototype, "name", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column("int", { unsigned: true, default: 0 }), (0, typeorm_1.Column)("int", { unsigned: true, default: 0 }),
__metadata("design:type", Number) __metadata("design:type", Number)
], RandomDuelScore.prototype, "winCount", void 0); ], RandomDuelScore.prototype, "winCount", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column("int", { unsigned: true, default: 0 }), (0, typeorm_1.Column)("int", { unsigned: true, default: 0 }),
__metadata("design:type", Number) __metadata("design:type", Number)
], RandomDuelScore.prototype, "loseCount", void 0); ], RandomDuelScore.prototype, "loseCount", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column("int", { unsigned: true, default: 0 }), (0, typeorm_1.Column)("int", { unsigned: true, default: 0 }),
__metadata("design:type", Number) __metadata("design:type", Number)
], RandomDuelScore.prototype, "fleeCount", void 0); ], RandomDuelScore.prototype, "fleeCount", void 0);
__decorate([ __decorate([
typeorm_1.Column("int", { unsigned: true, default: 0 }), (0, typeorm_1.Column)("int", { unsigned: true, default: 0 }),
__metadata("design:type", Number) __metadata("design:type", Number)
], RandomDuelScore.prototype, "winCombo", void 0); ], RandomDuelScore.prototype, "winCombo", void 0);
RandomDuelScore = __decorate([ RandomDuelScore = __decorate([
typeorm_1.Entity() (0, typeorm_1.Entity)()
], RandomDuelScore); ], RandomDuelScore);
exports.RandomDuelScore = RandomDuelScore; exports.RandomDuelScore = RandomDuelScore;
//# sourceMappingURL=RandomDuelScore.js.map //# sourceMappingURL=RandomDuelScore.js.map
\ No newline at end of file
...@@ -19,41 +19,48 @@ const VipKey_1 = require("./VipKey"); ...@@ -19,41 +19,48 @@ const VipKey_1 = require("./VipKey");
const moment_1 = __importDefault(require("moment")); const moment_1 = __importDefault(require("moment"));
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase"); const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let User = class User extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase { let User = class User extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
key;
chatColor;
vipExpireDate;
isVip() { isVip() {
return this.vipExpireDate && moment_1.default().isBefore(this.vipExpireDate); return this.vipExpireDate && (0, moment_1.default)().isBefore(this.vipExpireDate);
} }
victory;
words;
dialogues;
usedKeys;
}; };
__decorate([ __decorate([
typeorm_1.PrimaryColumn({ type: "varchar", length: 128 }), (0, typeorm_1.PrimaryColumn)({ type: "varchar", length: 128 }),
__metadata("design:type", String) __metadata("design:type", String)
], User.prototype, "key", void 0); ], User.prototype, "key", void 0);
__decorate([ __decorate([
typeorm_1.Column("varchar", { length: 16, nullable: true }), (0, typeorm_1.Column)("varchar", { length: 16, nullable: true }),
__metadata("design:type", String) __metadata("design:type", String)
], User.prototype, "chatColor", void 0); ], User.prototype, "chatColor", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column("datetime", { nullable: true }), (0, typeorm_1.Column)("datetime", { nullable: true }),
__metadata("design:type", Date) __metadata("design:type", Date)
], User.prototype, "vipExpireDate", void 0); ], User.prototype, "vipExpireDate", void 0);
__decorate([ __decorate([
typeorm_1.Column("text", { nullable: true }), (0, typeorm_1.Column)("text", { nullable: true }),
__metadata("design:type", String) __metadata("design:type", String)
], User.prototype, "victory", void 0); ], User.prototype, "victory", void 0);
__decorate([ __decorate([
typeorm_1.Column("text", { nullable: true }), (0, typeorm_1.Column)("text", { nullable: true }),
__metadata("design:type", String) __metadata("design:type", String)
], User.prototype, "words", void 0); ], User.prototype, "words", void 0);
__decorate([ __decorate([
typeorm_1.OneToMany(() => UserDialog_1.UserDialog, dialog => dialog.user), (0, typeorm_1.OneToMany)(() => UserDialog_1.UserDialog, dialog => dialog.user),
__metadata("design:type", Array) __metadata("design:type", Array)
], User.prototype, "dialogues", void 0); ], User.prototype, "dialogues", void 0);
__decorate([ __decorate([
typeorm_1.OneToMany(() => VipKey_1.VipKey, vipKey => vipKey.usedBy), (0, typeorm_1.OneToMany)(() => VipKey_1.VipKey, vipKey => vipKey.usedBy),
__metadata("design:type", Array) __metadata("design:type", Array)
], User.prototype, "usedKeys", void 0); ], User.prototype, "usedKeys", void 0);
User = __decorate([ User = __decorate([
typeorm_1.Entity() (0, typeorm_1.Entity)()
], User); ], User);
exports.User = User; exports.User = User;
//# sourceMappingURL=User.js.map //# sourceMappingURL=User.js.map
\ No newline at end of file
...@@ -13,26 +13,30 @@ exports.UserDialog = void 0; ...@@ -13,26 +13,30 @@ exports.UserDialog = void 0;
const typeorm_1 = require("typeorm"); const typeorm_1 = require("typeorm");
const User_1 = require("./User"); const User_1 = require("./User");
let UserDialog = class UserDialog { let UserDialog = class UserDialog {
id;
cardCode;
text;
user;
}; };
__decorate([ __decorate([
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: "bigint" }), (0, typeorm_1.PrimaryGeneratedColumn)({ unsigned: true, type: "bigint" }),
__metadata("design:type", Number) __metadata("design:type", Number)
], UserDialog.prototype, "id", void 0); ], UserDialog.prototype, "id", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column("int", { unsigned: true }), (0, typeorm_1.Column)("int", { unsigned: true }),
__metadata("design:type", Number) __metadata("design:type", Number)
], UserDialog.prototype, "cardCode", void 0); ], UserDialog.prototype, "cardCode", void 0);
__decorate([ __decorate([
typeorm_1.Column("text"), (0, typeorm_1.Column)("text"),
__metadata("design:type", String) __metadata("design:type", String)
], UserDialog.prototype, "text", void 0); ], UserDialog.prototype, "text", void 0);
__decorate([ __decorate([
typeorm_1.ManyToOne(() => User_1.User, user => user.dialogues), (0, typeorm_1.ManyToOne)(() => User_1.User, user => user.dialogues),
__metadata("design:type", User_1.User) __metadata("design:type", User_1.User)
], UserDialog.prototype, "user", void 0); ], UserDialog.prototype, "user", void 0);
UserDialog = __decorate([ UserDialog = __decorate([
typeorm_1.Entity() (0, typeorm_1.Entity)()
], UserDialog); ], UserDialog);
exports.UserDialog = UserDialog; exports.UserDialog = UserDialog;
//# sourceMappingURL=UserDialog.js.map //# sourceMappingURL=UserDialog.js.map
\ No newline at end of file
...@@ -14,34 +14,39 @@ const typeorm_1 = require("typeorm"); ...@@ -14,34 +14,39 @@ const typeorm_1 = require("typeorm");
const User_1 = require("./User"); const User_1 = require("./User");
const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase"); const CreateAndUpdateTimeBase_1 = require("./CreateAndUpdateTimeBase");
let VipKey = class VipKey extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase { let VipKey = class VipKey extends CreateAndUpdateTimeBase_1.CreateAndUpdateTimeBase {
id;
key;
type;
isUsed;
usedBy;
toJSON() { toJSON() {
return { key: this.key, type: this.type }; return { key: this.key, type: this.type };
} }
}; };
__decorate([ __decorate([
typeorm_1.PrimaryGeneratedColumn({ unsigned: true, type: "bigint" }), (0, typeorm_1.PrimaryGeneratedColumn)({ unsigned: true, type: "bigint" }),
__metadata("design:type", Number) __metadata("design:type", Number)
], VipKey.prototype, "id", void 0); ], VipKey.prototype, "id", void 0);
__decorate([ __decorate([
typeorm_1.Index({ unique: true }), (0, typeorm_1.Index)({ unique: true }),
typeorm_1.Column("varchar", { length: 30 }), (0, typeorm_1.Column)("varchar", { length: 30 }),
__metadata("design:type", String) __metadata("design:type", String)
], VipKey.prototype, "key", void 0); ], VipKey.prototype, "key", void 0);
__decorate([ __decorate([
typeorm_1.Column("int", { unsigned: true }), (0, typeorm_1.Column)("int", { unsigned: true }),
__metadata("design:type", Number) __metadata("design:type", Number)
], VipKey.prototype, "type", void 0); ], VipKey.prototype, "type", void 0);
__decorate([ __decorate([
typeorm_1.Index(), (0, typeorm_1.Index)(),
typeorm_1.Column("tinyint", { unsigned: true, default: 0 }), (0, typeorm_1.Column)("tinyint", { unsigned: true, default: 0 }),
__metadata("design:type", Number) __metadata("design:type", Number)
], VipKey.prototype, "isUsed", void 0); ], VipKey.prototype, "isUsed", void 0);
__decorate([ __decorate([
typeorm_1.ManyToOne(() => User_1.User, user => user.usedKeys), (0, typeorm_1.ManyToOne)(() => User_1.User, user => user.usedKeys),
__metadata("design:type", User_1.User) __metadata("design:type", User_1.User)
], VipKey.prototype, "usedBy", void 0); ], VipKey.prototype, "usedBy", void 0);
VipKey = __decorate([ VipKey = __decorate([
typeorm_1.Entity() (0, typeorm_1.Entity)()
], VipKey); ], VipKey);
exports.VipKey = VipKey; exports.VipKey = VipKey;
//# sourceMappingURL=VipKey.js.map //# sourceMappingURL=VipKey.js.map
\ No newline at end of file
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
"lflist": 0, "lflist": 0,
"rule": 0, "rule": 0,
"mode": 0, "mode": 0,
"comment": "rule: 0=OCGONLY, 1=TCGONLY, 2=OT; mode: 0=SINGLE, 1=MATCH, 2=TAG", "comment": "rule: 0=OCG-ONLY, 1=TCG-ONLY, 2=SC-ONLY, 3=CUSTOM-ONLY, 4=NO-UNIQUE, 5=ALL; mode: 0=SINGLE, 1=MATCH, 2=TAG",
"duel_rule": 5, "duel_rule": 5,
"no_check_deck": false, "no_check_deck": false,
"no_shuffle_deck": false, "no_shuffle_deck": false,
...@@ -66,12 +66,14 @@ ...@@ -66,12 +66,14 @@
"tips": { "tips": {
"enabled": true, "enabled": true,
"split_zh": false, "split_zh": false,
"get": "https://api.moecube.com/biu-tips/tips.json", "get": "https://sapi.moecube.com:444/biu-tips/tips.json",
"get_zh": false "get_zh": false,
"interval": 30000,
"interval_ingame": 120000
}, },
"dialogues": { "dialogues": {
"enabled": true, "enabled": true,
"get_custom": "http://purerosefallen.github.io/ygopro-tips/dialogues-222.json", "get_custom": "https://minio.momobako.com:9000/public/ygopro-tips/dialogues-222.json",
"get": "http://mercury233.me/ygosrv233/dialogues.json" "get": "http://mercury233.me/ygosrv233/dialogues.json"
}, },
"words": { "words": {
...@@ -160,6 +162,7 @@ ...@@ -160,6 +162,7 @@
"post_detailed_score": true, "post_detailed_score": true,
"post_score_midduel": true, "post_score_midduel": true,
"cache_ttl": 60000, "cache_ttl": 60000,
"no_match_mode": false,
"options": { "options": {
"apiKey": "123" "apiKey": "123"
}, },
...@@ -217,6 +220,7 @@ ...@@ -217,6 +220,7 @@
"source": "mycard-athletic" "source": "mycard-athletic"
}, },
"rankCount": 10, "rankCount": 10,
"banCount": 0,
"ttl": 600 "ttl": 600
}, },
"test_mode": { "test_mode": {
......
...@@ -85,6 +85,7 @@ ...@@ -85,6 +85,7 @@
"kick_count_down_arena_part2": " will be evicted for not getting ready or starting the game.", "kick_count_down_arena_part2": " will be evicted for not getting ready or starting the game.",
"chat_order_main": "Mycard YGOPro Server function list", "chat_order_main": "Mycard YGOPro Server function list",
"chat_order_help": "/help show this list", "chat_order_help": "/help show this list",
"chat_order_refresh": "/refresh refresh field when stuck",
"chat_order_roomname": "/roomname show room name", "chat_order_roomname": "/roomname show room name",
"chat_order_windbot": "/ai to add an AI, /ai name to add selected AI ", "chat_order_windbot": "/ai to add an AI, /ai name to add selected AI ",
"chat_order_tip": "/tip show a tip", "chat_order_tip": "/tip show a tip",
...@@ -203,6 +204,10 @@ ...@@ -203,6 +204,10 @@
"auto_death_part2": " minutes.", "auto_death_part2": " minutes.",
"athletic_arena_tip": "During an athletic match, a game quit behavior is regarded as a surrender.", "athletic_arena_tip": "During an athletic match, a game quit behavior is regarded as a surrender.",
"windbot_disable_random_room": "By adding the AI, this random game won't get any new player unless they enter the room name:", "windbot_disable_random_room": "By adding the AI, this random game won't get any new player unless they enter the room name:",
"refresh_success": "Refresh field succeeded.",
"refresh_failed": "Refresh field failed.",
"banned_athletic_deck_part1": "Entertainment Mode does not allow top ",
"banned_athletic_deck_part2": " popular meta decks. Please change your deck.",
"using_athletic_deck": " is using a competitive deck." "using_athletic_deck": " is using a competitive deck."
}, },
"es-es": { "es-es": {
...@@ -437,6 +442,7 @@ ...@@ -437,6 +442,7 @@
"kick_count_down_arena_part2": "若不准备或开始游戏将视为投降", "kick_count_down_arena_part2": "若不准备或开始游戏将视为投降",
"chat_order_main": "Mycard YGOPro Server 指令帮助", "chat_order_main": "Mycard YGOPro Server 指令帮助",
"chat_order_help": "/help 显示这个帮助信息", "chat_order_help": "/help 显示这个帮助信息",
"chat_order_refresh": "/refresh 刷新场面信息,卡顿时用",
"chat_order_roomname": "/roomname 显示当前房间的名字", "chat_order_roomname": "/roomname 显示当前房间的名字",
"chat_order_windbot": "/ai 添加一个AI,/ai 角色名 可指定添加的角色", "chat_order_windbot": "/ai 添加一个AI,/ai 角色名 可指定添加的角色",
"chat_order_tip": "/tip 显示一条提示", "chat_order_tip": "/tip 显示一条提示",
...@@ -555,6 +561,10 @@ ...@@ -555,6 +561,10 @@
"auto_death_part2": "分钟后,将自动进入加时赛。", "auto_death_part2": "分钟后,将自动进入加时赛。",
"athletic_arena_tip": "在竞技匹配中,比赛开始前退出游戏也会视为投降。", "athletic_arena_tip": "在竞技匹配中,比赛开始前退出游戏也会视为投降。",
"windbot_disable_random_room": "因为添加了AI,本随机对战房间将只能通过房间名加入:", "windbot_disable_random_room": "因为添加了AI,本随机对战房间将只能通过房间名加入:",
"refresh_success": "刷新场面成功。",
"refresh_fail": "刷新场面失败。",
"banned_athletic_deck_part1": "娱乐匹配中禁止使用使用数前",
"banned_athletic_deck_part2": "的竞技卡组。请更换卡组。",
"using_athletic_deck": " 正在使用竞技卡组。" "using_athletic_deck": " 正在使用竞技卡组。"
}, },
"ko-kr": { "ko-kr": {
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
"apps": [ "apps": [
{ {
"name": "ygopro-server", "name": "ygopro-server",
"script": "/ygopro-server/ygopro-server.js", "script": "npm",
"cwd": "/ygopro-server" "cwd": "/ygopro-server",
"args": "start"
}, },
{ {
"name": "windbot", "name": "windbot",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -11,19 +11,15 @@ ...@@ -11,19 +11,15 @@
], ],
"author": "zh99998 <zh99998@gmail.com>, mercury233 <me@mercury233.me>, Nanahira <78877@qq.com>", "author": "zh99998 <zh99998@gmail.com>, mercury233 <me@mercury233.me>, Nanahira <78877@qq.com>",
"dependencies": { "dependencies": {
"@types/bunyan": "^1.8.6",
"@types/node": "^14.0.13",
"@types/underscore": "^1.10.24",
"async": "^3.2.0", "async": "^3.2.0",
"axios": "^0.19.2", "axios": "^0.19.2",
"bunyan": "^1.8.14", "bunyan": "^1.8.14",
"challonge": "latest", "challonge": "^2.2.0",
"coffeescript": "^2.5.1", "deepmerge": "^4.2.2",
"deepmerge": "latest", "formidable": "^2.0.1",
"formidable": "latest", "geoip-country-lite": "^1.0.0",
"geoip-country-lite": "latest",
"jszip": "^3.5.0", "jszip": "^3.5.0",
"load-json-file": "latest", "load-json-file": "^6.2.0",
"lzma": "^2.3.2", "lzma": "^2.3.2",
"moment": "^2.29.1", "moment": "^2.29.1",
"mysql": "^2.18.1", "mysql": "^2.18.1",
...@@ -32,21 +28,27 @@ ...@@ -32,21 +28,27 @@
"q": "^1.5.1", "q": "^1.5.1",
"querystring": "^0.2.0", "querystring": "^0.2.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"request": "latest", "request": "^2.88.2",
"sqlite3": "latest", "sqlite3": "^5.0.2",
"typeorm": "^0.2.29", "typeorm": "^0.2.29",
"typescript": "^4.0.5",
"underscore": "^1.11.0", "underscore": "^1.11.0",
"underscore.string": "latest", "underscore.string": "^3.3.6",
"ws": "^1.1.1" "ws": "^1.1.1"
}, },
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"build": "coffee -c *.coffee && tsc", "build": "coffee -c *.coffee && tsc",
"start": "node ygopro-server.js", "start": "node ygopro-server.js | bunyan",
"tournament": "node ygopro-tournament.js", "tournament": "node ygopro-tournament.js",
"pre": "node ygopro-pre.js", "pre": "node ygopro-pre.js",
"updated": "node ygopro-update.js", "updated": "node ygopro-update.js",
"webhook": "node ygopro-webhook.js" "webhook": "node ygopro-webhook.js"
},
"devDependencies": {
"@types/bunyan": "^1.8.8",
"@types/node": "^17.0.19",
"@types/underscore": "^1.11.4",
"coffeescript": "^2.6.1",
"typescript": "^4.5.5"
} }
} }
...@@ -18,7 +18,6 @@ _.str = require 'underscore.string' ...@@ -18,7 +18,6 @@ _.str = require 'underscore.string'
_.mixin(_.str.exports()) _.mixin(_.str.exports())
request = require 'request' request = require 'request'
axios = require 'axios'
qs = require "querystring" qs = require "querystring"
zlib = require 'zlib' zlib = require 'zlib'
axios = require 'axios' axios = require 'axios'
...@@ -404,6 +403,7 @@ init = () -> ...@@ -404,6 +403,7 @@ init = () ->
log.info('Saving migrated settings.') log.info('Saving migrated settings.')
await setting_save(settings) await setting_save(settings)
if settings.modules.mysql.enabled if settings.modules.mysql.enabled
global.PrimaryKeyType = if settings.modules.mysql.db.type == 'sqlite' then 'integer' else 'bigint'
DataManager = require('./data-manager/DataManager.js').DataManager DataManager = require('./data-manager/DataManager.js').DataManager
dataManager = global.dataManager = new DataManager(settings.modules.mysql.db, log) dataManager = global.dataManager = new DataManager(settings.modules.mysql.db, log)
log.info('Connecting to database.') log.info('Connecting to database.')
...@@ -492,9 +492,9 @@ init = () -> ...@@ -492,9 +492,9 @@ init = () ->
badwordR.level3=new RegExp('(?:'+badwords.level3.join(')|(?:')+')','i'); badwordR.level3=new RegExp('(?:'+badwords.level3.join(')|(?:')+')','i');
setInterval ()-> setInterval ()->
moment_now = moment() moment_now = global.moment_now = moment()
moment_now_string = moment_now.format() moment_now_string = global.moment_now_string = moment_now.format()
moment_long_ago_string = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's').format() moment_long_ago_string = global.moment_long_ago_string = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's').format()
return return
, 500 , 500
...@@ -628,11 +628,18 @@ init = () -> ...@@ -628,11 +628,18 @@ init = () ->
load_tips_zh() load_tips_zh()
if settings.modules.tips.enabled if settings.modules.tips.enabled
setInterval ()-> if settings.modules.tips.interval
for room in ROOM_all when room and room.established setInterval ()->
ygopro.stoc_send_random_tip_to_room(room) if room.duel_stage == ygopro.constants.DUEL_STAGE.SIDING or room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN for room in ROOM_all when room and room.established and room.duel_stage != ygopro.constants.END
return ygopro.stoc_send_random_tip_to_room(room) if room.duel_stage != ygopro.constants.DUEL_STAGE.DUELING
, 30000 return
, settings.modules.tips.interval
if settings.modules.tips.interval_ingame
setInterval ()->
for room in ROOM_all when room and room.established and room.duel_stage != ygopro.constants.END
ygopro.stoc_send_random_tip_to_room(room) if room.duel_stage == ygopro.constants.DUEL_STAGE.DUELING
return
, settings.modules.tips.interval_ingame
if settings.modules.dialogues.enabled and settings.modules.dialogues.get if settings.modules.dialogues.enabled and settings.modules.dialogues.get
load_dialogues() load_dialogues()
...@@ -660,9 +667,9 @@ init = () -> ...@@ -660,9 +667,9 @@ init = () ->
setInterval ()-> setInterval ()->
for room in ROOM_all when room and room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN and room.random_type and room.last_active_time and room.waiting_for_player and room.get_disconnected_count() == 0 and (!settings.modules.side_timeout or room.duel_stage != ygopro.constants.DUEL_STAGE.SIDING) and !room.recovered for room in ROOM_all when room and room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN and room.random_type and room.last_active_time and room.waiting_for_player and room.get_disconnected_count() == 0 and (!settings.modules.side_timeout or room.duel_stage != ygopro.constants.DUEL_STAGE.SIDING) and !room.recovered
time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000) time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000)
#log.info time_passed #log.info time_passed, moment_now_string
if time_passed >= settings.modules.random_duel.hang_timeout if time_passed >= settings.modules.random_duel.hang_timeout
room.last_active_time = moment_now_string room.refreshLastActiveTime()
await ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}") await ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}")
room.scores[room.waiting_for_player.name_vpass] = -9 room.scores[room.waiting_for_player.name_vpass] = -9
#log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass] #log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
...@@ -681,7 +688,7 @@ init = () -> ...@@ -681,7 +688,7 @@ init = () ->
time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000) time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000)
#log.info time_passed #log.info time_passed
if time_passed >= settings.modules.random_duel.hang_timeout if time_passed >= settings.modules.random_duel.hang_timeout
room.last_active_time = moment_now_string room.refreshLastActiveTime()
ygopro.stoc_send_chat_to_room(room, "#{room.waiting_for_player.name} ${kicked_by_system}", ygopro.constants.COLORS.RED) ygopro.stoc_send_chat_to_room(room, "#{room.waiting_for_player.name} ${kicked_by_system}", ygopro.constants.COLORS.RED)
room.scores[room.waiting_for_player.name_vpass] = -9 room.scores[room.waiting_for_player.name_vpass] = -9
#log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass] #log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
...@@ -1105,7 +1112,7 @@ CLIENT_is_able_to_reconnect = global.CLIENT_is_able_to_reconnect = (client, deck ...@@ -1105,7 +1112,7 @@ CLIENT_is_able_to_reconnect = global.CLIENT_is_able_to_reconnect = (client, deck
if client.system_kicked if client.system_kicked
return false return false
disconnect_info = disconnect_list[CLIENT_get_authorize_key(client)] disconnect_info = disconnect_list[CLIENT_get_authorize_key(client)]
unless disconnect_info unless disconnect_info and disconnect_info.deckbuf
return false return false
room = ROOM_all[disconnect_info.room_id] room = ROOM_all[disconnect_info.room_id]
if !room if !room
...@@ -1204,7 +1211,7 @@ CLIENT_reconnect = global.CLIENT_reconnect = (client) -> ...@@ -1204,7 +1211,7 @@ CLIENT_reconnect = global.CLIENT_reconnect = (client) ->
client.established = true client.established = true
client.pre_establish_buffers = [] client.pre_establish_buffers = []
if room.random_type or room.arena if room.random_type or room.arena
room.last_active_time = moment_now_string room.refreshLastActiveTime()
CLIENT_import_data(client, dinfo.old_client, room) CLIENT_import_data(client, dinfo.old_client, room)
CLIENT_send_reconnect_info(client, client.server, room) CLIENT_send_reconnect_info(client, client.server, room)
#console.log("#{client.name} ${reconnect_to_game}") #console.log("#{client.name} ${reconnect_to_game}")
...@@ -1233,7 +1240,7 @@ CLIENT_kick_reconnect = global.CLIENT_kick_reconnect = (client, deckbuf) -> ...@@ -1233,7 +1240,7 @@ CLIENT_kick_reconnect = global.CLIENT_kick_reconnect = (client, deckbuf) ->
client.established = true client.established = true
client.pre_establish_buffers = [] client.pre_establish_buffers = []
if room.random_type or room.arena if room.random_type or room.arena
room.last_active_time = moment_now_string room.refreshLastActiveTime()
CLIENT_import_data(client, player, room) CLIENT_import_data(client, player, room)
CLIENT_send_reconnect_info(client, client.server, room) CLIENT_send_reconnect_info(client, client.server, room)
#console.log("#{client.name} ${reconnect_to_game}") #console.log("#{client.name} ${reconnect_to_game}")
...@@ -1313,23 +1320,7 @@ SOCKET_flush_data = global.SOCKET_flush_data = (sk, datas) -> ...@@ -1313,23 +1320,7 @@ SOCKET_flush_data = global.SOCKET_flush_data = (sk, datas) ->
return true return true
getSeedTimet = global.getSeedTimet = (count) -> getSeedTimet = global.getSeedTimet = (count) ->
ret = [] return _.range(count).map(() => 0)
for i in [0...count]
curTime = null
while !curTime or _.any(ret, (time) ->
return time == curTime.unix()
)
curTime = moment_now
offset = Math.floor(Math.random() * 240) - 120
if offset > 0
curTime = curTime.add(offset, "s")
else if offset < 0
curTime = curTime.subtract(-offset, "s")
ret.push(curTime.unix())
ret.sort((a, b) ->
return a - b
)
return ret
class Room class Room
constructor: (name, @hostinfo) -> constructor: (name, @hostinfo) ->
...@@ -1370,15 +1361,15 @@ class Room ...@@ -1370,15 +1361,15 @@ class Room
@hostinfo.mode = 2 @hostinfo.mode = 2
@hostinfo.start_lp = 16000 @hostinfo.start_lp = 16000
else if name[0...3] == 'AI#' else if name[0...3] == 'AI#'
@hostinfo.rule = 2 @hostinfo.rule = 5
@hostinfo.lflist = -1 @hostinfo.lflist = -1
@hostinfo.time_limit = 0 @hostinfo.time_limit = 0
@hostinfo.no_check_deck = true @hostinfo.no_check_deck = true
else if (param = name.match /^(\d)(\d)(T|F)(T|F)(T|F)(\d+),(\d+),(\d+)/i) else if (param = name.match /^(\d)(\d)([12345TF])(T|F)(T|F)(\d+),(\d+),(\d+)/i)
@hostinfo.rule = parseInt(param[1]) @hostinfo.rule = parseInt(param[1])
@hostinfo.mode = parseInt(param[2]) @hostinfo.mode = parseInt(param[2])
@hostinfo.duel_rule = (if param[3] == 'T' then 3 else 4) @hostinfo.duel_rule = (if parseInt(param[3]) then parseInt(param[3]) else (if param[3] == 'T' then 3 else 5))
@hostinfo.no_check_deck = param[4] == 'T' @hostinfo.no_check_deck = param[4] == 'T'
@hostinfo.no_shuffle_deck = param[5] == 'T' @hostinfo.no_shuffle_deck = param[5] == 'T'
@hostinfo.start_lp = parseInt(param[6]) @hostinfo.start_lp = parseInt(param[6])
...@@ -1400,11 +1391,11 @@ class Room ...@@ -1400,11 +1391,11 @@ class Room
@hostinfo.lflist = 0 @hostinfo.lflist = 0
if (rule.match /(^|,|,)(OR|OCGRANDOM)(,|,|$)/) if (rule.match /(^|,|,)(OR|OCGRANDOM)(,|,|$)/)
@hostinfo.rule = 2 @hostinfo.rule = 5
@hostinfo.lflist = 0 @hostinfo.lflist = 0
if (rule.match /(^|,|,)(CR|CCGRANDOM)(,|,|$)/) if (rule.match /(^|,|,)(CR|CCGRANDOM)(,|,|$)/)
@hostinfo.rule = 4 @hostinfo.rule = 2
@hostinfo.lflist = -1 @hostinfo.lflist = -1
if (rule.match /(^|,|,)(TOR|TCGONLYRANDOM)(,|,|$)/) if (rule.match /(^|,|,)(TOR|TCGONLYRANDOM)(,|,|$)/)
...@@ -1412,7 +1403,7 @@ class Room ...@@ -1412,7 +1403,7 @@ class Room
@hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg @hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg
if (rule.match /(^|,|,)(TR|TCGRANDOM)(,|,|$)/) if (rule.match /(^|,|,)(TR|TCGRANDOM)(,|,|$)/)
@hostinfo.rule = 2 @hostinfo.rule = 5
@hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg @hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg
if (rule.match /(^|,|,)(OOMR|OCGONLYMATCHRANDOM)(,|,|$)/) if (rule.match /(^|,|,)(OOMR|OCGONLYMATCHRANDOM)(,|,|$)/)
...@@ -1421,12 +1412,12 @@ class Room ...@@ -1421,12 +1412,12 @@ class Room
@hostinfo.mode = 1 @hostinfo.mode = 1
if (rule.match /(^|,|,)(OMR|OCGMATCHRANDOM)(,|,|$)/) if (rule.match /(^|,|,)(OMR|OCGMATCHRANDOM)(,|,|$)/)
@hostinfo.rule = 2 @hostinfo.rule = 5
@hostinfo.lflist = 0 @hostinfo.lflist = 0
@hostinfo.mode = 1 @hostinfo.mode = 1
if (rule.match /(^|,|,)(CMR|CCGMATCHRANDOM)(,|,|$)/) if (rule.match /(^|,|,)(CMR|CCGMATCHRANDOM)(,|,|$)/)
@hostinfo.rule = 4 @hostinfo.rule = 2
@hostinfo.lflist = -1 @hostinfo.lflist = -1
@hostinfo.mode = 1 @hostinfo.mode = 1
...@@ -1436,7 +1427,7 @@ class Room ...@@ -1436,7 +1427,7 @@ class Room
@hostinfo.mode = 1 @hostinfo.mode = 1
if (rule.match /(^|,|,)(TMR|TCGMATCHRANDOM)(,|,|$)/) if (rule.match /(^|,|,)(TMR|TCGMATCHRANDOM)(,|,|$)/)
@hostinfo.rule = 2 @hostinfo.rule = 5
@hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg @hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg
@hostinfo.mode = 1 @hostinfo.mode = 1
...@@ -1449,10 +1440,10 @@ class Room ...@@ -1449,10 +1440,10 @@ class Room
@hostinfo.lflist = 0 @hostinfo.lflist = 0
if (rule.match /(^|,|,)(OT|TCG)(,|,|$)/) if (rule.match /(^|,|,)(OT|TCG)(,|,|$)/)
@hostinfo.rule = 2 @hostinfo.rule = 5
if (rule.match /(^|,|,)(CN|CCG|CHINESE)(,|,|$)/) if (rule.match /(^|,|,)(SC|CN|CCG|CHINESE)(,|,|$)/)
@hostinfo.rule = 4 @hostinfo.rule = 2
@hostinfo.lflist = -1 @hostinfo.lflist = -1
if (param = rule.match /(^|,|,)LP(\d+)(,|,|$)/) if (param = rule.match /(^|,|,)LP(\d+)(,|,|$)/)
...@@ -1487,6 +1478,9 @@ class Room ...@@ -1487,6 +1478,9 @@ class Room
@hostinfo.lflist = -1 @hostinfo.lflist = -1
if (rule.match /(^|,|,)(NOUNIQUE|NU)(,|,|$)/) if (rule.match /(^|,|,)(NOUNIQUE|NU)(,|,|$)/)
@hostinfo.rule = 4
if (rule.match /(^|,|,)(CUSTOM|DIY)(,|,|$)/)
@hostinfo.rule = 3 @hostinfo.rule = 3
if (rule.match /(^|,|,)(NOCHECK|NC)(,|,|$)/) if (rule.match /(^|,|,)(NOCHECK|NC)(,|,|$)/)
...@@ -1832,7 +1826,7 @@ class Room ...@@ -1832,7 +1826,7 @@ class Room
@finished = true @finished = true
if !@finished_by_death if !@finished_by_death
@scores[client.name_vpass] = -9 @scores[client.name_vpass] = -9
if @random_type and not client.flee_free and (!settings.modules.reconnect.enabled or @get_disconnected_count() == 0) if @random_type and not client.flee_free and (!settings.modules.reconnect.enabled or @get_disconnected_count() == 0) and not client.kicked_by_system and not client.kicked_by_player
ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}") ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}")
if settings.modules.random_duel.record_match_scores and @random_type == 'M' if settings.modules.random_duel.record_match_scores and @random_type == 'M'
ROOM_player_flee(client.name_vpass) ROOM_player_flee(client.name_vpass)
...@@ -1981,6 +1975,12 @@ class Room ...@@ -1981,6 +1975,12 @@ class Room
for line in _.lines lines for line in _.lines lines
ygopro.stoc_send_chat_to_room(this, line, ygopro.constants.COLORS.PINK) ygopro.stoc_send_chat_to_room(this, line, ygopro.constants.COLORS.PINK)
refreshLastActiveTime: (longAgo) ->
if longAgo
@last_active_time = moment_long_ago_string
else
@last_active_time = moment_now_string
# 网络连接 # 网络连接
netRequestHandler = (client) -> netRequestHandler = (client) ->
client.ip = client.remoteAddress client.ip = client.remoteAddress
...@@ -1992,6 +1992,11 @@ netRequestHandler = (client) -> ...@@ -1992,6 +1992,11 @@ netRequestHandler = (client) ->
ROOM_connected_ip[client.ip] = connect_count ROOM_connected_ip[client.ip] = connect_count
#log.info "connect", client.ip, ROOM_connected_ip[client.ip] #log.info "connect", client.ip, ROOM_connected_ip[client.ip]
if ROOM_bad_ip[client.ip] > 5 or ROOM_connected_ip[client.ip] > 10
log.info 'BAD IP', client.ip
client.destroy()
return
# server stand for the connection to ygopro server process # server stand for the connection to ygopro server process
server = new net.Socket() server = new net.Socket()
client.server = server client.server = server
...@@ -2073,11 +2078,6 @@ netRequestHandler = (client) -> ...@@ -2073,11 +2078,6 @@ netRequestHandler = (client) ->
SERVER_clear_disconnect(server) SERVER_clear_disconnect(server)
return return
if ROOM_bad_ip[client.ip] > 5 or ROOM_connected_ip[client.ip] > 10
log.info 'BAD IP', client.ip
CLIENT_kick(client)
return
client.playLines = (lines) -> client.playLines = (lines) ->
for line in _.lines lines for line in _.lines lines
ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK) ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK)
...@@ -2126,14 +2126,20 @@ netRequestHandler = (client) -> ...@@ -2126,14 +2126,20 @@ netRequestHandler = (client) ->
return return
room.watcher.write(buffer) for buffer in handle_data.datas room.watcher.write(buffer) for buffer in handle_data.datas
else else
ctos_filter = if settings.modules.reconnect.enabled and client.pre_reconnecting then ["UPDATE_DECK"] else null ctos_filter = null
preconnect = false
if settings.modules.reconnect.enabled and client.pre_reconnecting_to_room
ctos_filter = ["UPDATE_DECK"]
if client.name == null
ctos_filter = ["JOIN_GAME", "PLAYER_INFO"]
preconnect = true
handle_data = await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, { handle_data = await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, {
client: client, client: client,
server: client.server server: client.server
}) }, preconnect)
if handle_data.feedback if handle_data.feedback
log.warn(handle_data.feedback.message, client.name, client.ip) log.warn(handle_data.feedback.message, client.name, client.ip)
if handle_data.feedback.type == "OVERSIZE" or ROOM_bad_ip[client.ip] > 5 if handle_data.feedback.type == "OVERSIZE" or handle_data.feedback.type == "INVALID_PACKET" or ROOM_bad_ip[client.ip] > 5
bad_ip_count = ROOM_bad_ip[client.ip] bad_ip_count = ROOM_bad_ip[client.ip]
if bad_ip_count if bad_ip_count
ROOM_bad_ip[client.ip] = bad_ip_count + 1 ROOM_bad_ip[client.ip] = bad_ip_count + 1
...@@ -2141,7 +2147,7 @@ netRequestHandler = (client) -> ...@@ -2141,7 +2147,7 @@ netRequestHandler = (client) ->
ROOM_bad_ip[client.ip] = 1 ROOM_bad_ip[client.ip] = 1
CLIENT_kick(client) CLIENT_kick(client)
return return
if !client.server if client.closed || !client.server
return return
if client.established if client.established
client.server.write buffer for buffer in handle_data.datas client.server.write buffer for buffer in handle_data.datas
...@@ -2177,6 +2183,11 @@ deck_name_match = global.deck_name_match = (deck_name, player_name) -> ...@@ -2177,6 +2183,11 @@ deck_name_match = global.deck_name_match = (deck_name, player_name) ->
# return true to cancel a synchronous message # return true to cancel a synchronous message
ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server, datas)-> ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server, datas)->
# second PLAYER_INFO = attack
if client.name
log.info 'DUP PLAYER_INFO', client.ip
CLIENT_kick client
return '_cancel'
# checkmate use username$password, but here don't # checkmate use username$password, but here don't
# so remove the password # so remove the password
name_full =info.name.replace(/\\/g, "").split("$") name_full =info.name.replace(/\\/g, "").split("$")
...@@ -2193,18 +2204,6 @@ ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server, datas)-> ...@@ -2193,18 +2204,6 @@ ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server, datas)->
return false return false
, name)) , name))
client.rag = true client.rag = true
if settings.modules.mycard.enabled and settings.modules.mycard.ban_get and !client.is_local
try
banMCRequest = await axios.get settings.modules.mycard.ban_get,
paramsSerializer: qs.stringify
params:
user: name
if typeof(banMCRequest.data) == "object"
client.ban_mc = banMCRequest.data
else
log.warn "ban get bad json", banMCRequest.data
catch e
log.warn 'ban get error', e.toString()
struct = ygopro.structs.get("CTOS_PlayerInfo") struct = ygopro.structs.get("CTOS_PlayerInfo")
struct._setBuff(buffer) struct._setBuff(buffer)
struct.set("name", name) struct.set("name", name)
...@@ -2314,6 +2313,19 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2314,6 +2313,19 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
if buffer.length != 6 if buffer.length != 6
ygopro.stoc_die(client, '${invalid_password_payload}') ygopro.stoc_die(client, '${invalid_password_payload}')
return return
if settings.modules.mycard.enabled and settings.modules.mycard.ban_get and !client.is_local
axios.get settings.modules.mycard.ban_get,
paramsSerializer: qs.stringify
params:
user: client.name
.then (banMCRequest) ->
if typeof(banMCRequest.data) == "object"
client.ban_mc = banMCRequest.data
else
log.warn "ban get bad json", banMCRequest.data
.catch (e) ->
log.warn 'ban get error', e.toString()
check_buffer_indentity = (buf)-> check_buffer_indentity = (buf)->
checksum = 0 checksum = 0
...@@ -2321,7 +2333,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2321,7 +2333,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
checksum += buf.readUInt8(i) checksum += buf.readUInt8(i)
(checksum & 0xFF) == 0 (checksum & 0xFF) == 0
create_room_with_action = (buffer, decrypted_buffer, match_permit)-> create_room_with_action = (buffer, decrypted_buffer)->
if client.closed if client.closed
return return
firstByte = buffer.readUInt8(1) firstByte = buffer.readUInt8(1)
...@@ -2349,9 +2361,9 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2349,9 +2361,9 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
options = { options = {
lflist: settings.hostinfo.lflist lflist: settings.hostinfo.lflist
time_limit: settings.hostinfo.time_limit time_limit: settings.hostinfo.time_limit
rule: (opt1 >> 5) & 0x7 # 0 1 2 3 4 rule: (opt1 >> 5) & 0x7 # 0 1 2 3 4 5
mode: (opt1 >> 3) & 0x3 # 0 1 2 mode: (opt1 >> 3) & 0x3 # 0 1 2
duel_rule: opt0 >> 1 # 1 2 3 4 5 duel_rule: (opt0 >> 1) || 5 # 1 2 3 4 5
no_check_deck: !!((opt1 >> 1) & 1) no_check_deck: !!((opt1 >> 1) & 1)
no_shuffle_deck: !!(opt1 & 1) no_shuffle_deck: !!(opt1 & 1)
start_lp: opt2 start_lp: opt2
...@@ -2361,7 +2373,10 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2361,7 +2373,10 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
auto_death: !!(opt0 & 0x1) ? 40 : false auto_death: !!(opt0 & 0x1) ? 40 : false
} }
#console.log(options) #console.log(options)
options.lflist = _.findIndex lflists, (list)-> ((options.rule == 1) == list.tcg) and list.date.isBefore() if options.rule == 2
options.lflist = -1
else if options.rule != 3
options.lflist = _.findIndex lflists, (list)-> ((options.rule == 1) == list.tcg) and list.date.isBefore()
room_title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ') room_title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ')
if badwordR.level3.test(room_title) if badwordR.level3.test(room_title)
log.warn("BAD ROOM NAME LEVEL 3", room_title, client.name, client.ip) log.warn("BAD ROOM NAME LEVEL 3", room_title, client.name, client.ip)
...@@ -2386,9 +2401,23 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2386,9 +2401,23 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
ygopro.stoc_die(client, '${invalid_password_not_found}') ygopro.stoc_die(client, '${invalid_password_not_found}')
return return
when 4 when 4
if match_permit and !match_permit.permit if settings.modules.arena_mode.check_permit
ygopro.stoc_die(client, '${invalid_password_unauthorized}') try
return matchPermitRes = await axios.get settings.modules.arena_mode.check_permit,
responseType: 'json'
timeout: 3000
params:
username: client.name,
password: info.pass,
arena: settings.modules.arena_mode.mode
match_permit = matchPermitRes.data
catch e
log.warn "match permit fail #{e.toString()}"
if client.closed
return
if match_permit and match_permit.permit == false
ygopro.stoc_die(client, '${invalid_password_unauthorized}')
return
room = await ROOM_find_or_create_by_name('M#' + info.pass.slice(8)) room = await ROOM_find_or_create_by_name('M#' + info.pass.slice(8))
if room if room
for player in room.get_playing_player() when player and player.name == client.name for player in room.get_playing_player() when player and player.name == client.name
...@@ -2417,93 +2446,46 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2417,93 +2446,46 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
room.join_player(client) room.join_player(client)
return return
_async.auto({ decrypted_buffer = null
match_permit: (done) ->
if client.closed
done()
return
if(!settings.modules.arena_mode.check_permit)
done(null, null)
return
request
url: settings.modules.arena_mode.check_permit,
json: true,
qs:
username: client.name,
password: info.pass,
arena: settings.modules.arena_mode.mode
, (error, response, body)->
if client.closed
done(null, null)
return
if !error and body
done(null, body)
else
log.warn("Match permit request error", error)
done(null, null)
return
return
get_user: (done) ->
if client.closed
done()
return
if id = users_cache[client.name]
secret = id % 65535 + 1
decrypted_buffer = Buffer.allocUnsafe(6)
for i in [0, 2, 4]
decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i)
if check_buffer_indentity(decrypted_buffer)
done(null, {
original: decrypted_buffer,
decrypted: decrypted_buffer
})
return
#TODO: query database directly, like preload.
request
baseUrl: settings.modules.mycard.auth_base_url,
url: '/users/' + encodeURIComponent(client.name) + '.json',
qs:
api_key: settings.modules.mycard.auth_key,
api_username: client.name,
skip_track_visit: true
json: true
, (error, response, body)->
if !error and body and body.user
users_cache[client.name] = body.user.id
secret = body.user.id % 65535 + 1
decrypted_buffer = Buffer.allocUnsafe(6)
for i in [0, 2, 4]
decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i)
if check_buffer_indentity(decrypted_buffer)
buffer = decrypted_buffer
else
log.warn("READ USER FAIL", client.name, error, body)
done("${load_user_info_fail}")
return
# buffer != decrypted_buffer ==> auth failed
if !check_buffer_indentity(buffer)
done('${invalid_password_checksum}')
return
done(null, {
original: buffer,
decrypted: decrypted_buffer
})
return
return
}, (err, data) ->
if(client.closed)
return
if(err)
ygopro.stoc_die(client, err)
return
create_room_with_action(data.get_user.original, data.get_user.decrypted, data.match_permit) if id = users_cache[client.name]
) secret = id % 65535 + 1
decrypted_buffer = Buffer.allocUnsafe(6)
for i in [0, 2, 4]
decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i)
if check_buffer_indentity(decrypted_buffer)
return create_room_with_action(decrypted_buffer, decrypted_buffer)
try
userUrl = "#{settings.modules.mycard.auth_base_url}/users/#{encodeURIComponent(client.name)}.json"
#console.log(userUrl)
userDataRes = await axios.get userUrl,
responseType: 'json'
timeout: 4000
params:
api_key: settings.modules.mycard.auth_key,
api_username: client.name,
skip_track_visit: true
userData = userDataRes.data
#console.log userData
catch e
log.warn("READ USER FAIL", client.name, e.toString())
if !client.closed
ygopro.stoc_die(client, '${load_user_info_fail}')
return
if client.closed
return
users_cache[client.name] = userData.user.id
secret = userData.user.id % 65535 + 1
decrypted_buffer = Buffer.allocUnsafe(6)
for i in [0, 2, 4]
decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i)
if check_buffer_indentity(decrypted_buffer)
buffer = decrypted_buffer
if !check_buffer_indentity(buffer)
ygopro.stoc_die(client, '${invalid_password_checksum}')
return
return create_room_with_action(buffer, decrypted_buffer)
else if settings.modules.challonge.enabled else if settings.modules.challonge.enabled
if info.version != settings.version and settings.alternative_versions.includes(info.version) if info.version != settings.version and settings.alternative_versions.includes(info.version)
...@@ -2562,9 +2544,13 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)-> ...@@ -2562,9 +2544,13 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
#if found.winnerId #if found.winnerId
# ygopro.stoc_die(client, '${challonge_match_already_finished}') # ygopro.stoc_die(client, '${challonge_match_already_finished}')
# return # return
create_room_name = 'M#' + found.id create_room_name = found.id.toString()
if recover_match if !settings.modules.challonge.no_match_mode
create_room_name = recover_match[0] + ',' + create_room_name create_room_name = 'M#' + create_room_name
if recover_match
create_room_name = recover_match[0] + ',' + create_room_name
else if recover_match
create_room_name = recover_match[0] + '#' + create_room_name
room = await ROOM_find_or_create_by_name(create_room_name) room = await ROOM_find_or_create_by_name(create_room_name)
if room if room
room.challonge_info = found room.challonge_info = found
...@@ -2757,7 +2743,7 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)-> ...@@ -2757,7 +2743,7 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
return true return true
else else
room.waiting_for_player = client room.waiting_for_player = client
room.last_active_time = moment_now_string room.refreshLastActiveTime()
#log.info("#{msg_name}等待#{room.waiting_for_player.name}") #log.info("#{msg_name}等待#{room.waiting_for_player.name}")
#log.info 'MSG', msg_name #log.info 'MSG', msg_name
...@@ -2873,34 +2859,38 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)-> ...@@ -2873,34 +2859,38 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
pos = 1 - pos unless client.is_first pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2 pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2) val = buffer.readInt32LE(2)
room.dueling_players[pos].lp -= val if room.dueling_players[pos]
room.dueling_players[pos].lp = 0 if room.dueling_players[pos].lp < 0 room.dueling_players[pos].lp -= val
if 0 < room.dueling_players[pos].lp <= 100 room.dueling_players[pos].lp = 0 if room.dueling_players[pos].lp < 0
ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK) if 0 < room.dueling_players[pos].lp <= 100
ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK)
if msg_name == 'RECOVER' and client.pos == 0 if msg_name == 'RECOVER' and client.pos == 0
pos = buffer.readUInt8(1) pos = buffer.readUInt8(1)
pos = 1 - pos unless client.is_first pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2 pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2) val = buffer.readInt32LE(2)
room.dueling_players[pos].lp += val if room.dueling_players[pos]
room.dueling_players[pos].lp += val
if msg_name == 'LPUPDATE' and client.pos == 0 if msg_name == 'LPUPDATE' and client.pos == 0
pos = buffer.readUInt8(1) pos = buffer.readUInt8(1)
pos = 1 - pos unless client.is_first pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2 pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2) val = buffer.readInt32LE(2)
room.dueling_players[pos].lp = val if room.dueling_players[pos]
room.dueling_players[pos].lp = val
if msg_name == 'PAY_LPCOST' and client.pos == 0 if msg_name == 'PAY_LPCOST' and client.pos == 0
pos = buffer.readUInt8(1) pos = buffer.readUInt8(1)
pos = 1 - pos unless client.is_first pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2 pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2) val = buffer.readInt32LE(2)
room.dueling_players[pos].lp -= val if room.dueling_players[pos]
room.dueling_players[pos].lp = 0 if room.dueling_players[pos].lp < 0 room.dueling_players[pos].lp -= val
if 0 < room.dueling_players[pos].lp <= 100 room.dueling_players[pos].lp = 0 if room.dueling_players[pos].lp < 0
ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK) if 0 < room.dueling_players[pos].lp <= 100
ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK)
#track card count #track card count
#todo: track card count in tag mode #todo: track card count in tag mode
...@@ -3103,7 +3093,8 @@ ygopro.stoc_follow 'HS_PLAYER_CHANGE', true, (buffer, info, client, server, data ...@@ -3103,7 +3093,8 @@ ygopro.stoc_follow 'HS_PLAYER_CHANGE', true, (buffer, info, client, server, data
if room.waiting_for_player != room.waiting_for_player2 if room.waiting_for_player != room.waiting_for_player2
room.waiting_for_player2 = room.waiting_for_player room.waiting_for_player2 = room.waiting_for_player
room.waiting_for_player_time = settings.modules.arena_mode.ready_time room.waiting_for_player_time = settings.modules.arena_mode.ready_time
room.waiting_for_player_interval = setInterval (()-> wait_room_start_arena(ROOM_all[client.rid]);return), 1000 if !room.waiting_for_player_interval
room.waiting_for_player_interval = setInterval (()-> wait_room_start_arena(ROOM_all[client.rid]);return), 1000
else if !room.waiting_for_player and room.waiting_for_player_interval else if !room.waiting_for_player and room.waiting_for_player_interval
clearInterval room.waiting_for_player_interval clearInterval room.waiting_for_player_interval
room.waiting_for_player_interval = null room.waiting_for_player_interval = null
...@@ -3144,6 +3135,7 @@ ygopro.stoc_follow 'DUEL_END', false, (buffer, info, client, server, datas)-> ...@@ -3144,6 +3135,7 @@ ygopro.stoc_follow 'DUEL_END', false, (buffer, info, client, server, datas)->
wait_room_start = (room, time)-> wait_room_start = (room, time)->
if room and room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and room.ready_player_count_without_host >= room.max_player - 1 if room and room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and room.ready_player_count_without_host >= room.max_player - 1
#log.info('wait room start', time)
time -= 1 time -= 1
if time if time
unless time % 5 unless time % 5
...@@ -3335,7 +3327,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)-> ...@@ -3335,7 +3327,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
return unless room return unless room
msg = _.trim(info.msg) msg = _.trim(info.msg)
cancel = _.startsWith(msg, "/") cancel = _.startsWith(msg, "/")
room.last_active_time = moment_now_string unless cancel or not (room.random_type or room.arena) or room.duel_stage == ygopro.constants.DUEL_STAGE.FINGER or room.duel_stage == ygopro.constants.DUEL_STAGE.FIRSTGO or room.duel_stage == ygopro.constants.DUEL_STAGE.SIDING room.refreshLastActiveTime() unless cancel or not (room.random_type or room.arena) or room.duel_stage == ygopro.constants.DUEL_STAGE.FINGER or room.duel_stage == ygopro.constants.DUEL_STAGE.FIRSTGO or room.duel_stage == ygopro.constants.DUEL_STAGE.SIDING
cmd = msg.split(' ') cmd = msg.split(' ')
isVip = await CLIENT_check_vip(client) isVip = await CLIENT_check_vip(client)
switch cmd[0] switch cmd[0]
...@@ -3349,7 +3341,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)-> ...@@ -3349,7 +3341,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
ygopro.ctos_send(client.server, 'SURRENDER') ygopro.ctos_send(client.server, 'SURRENDER')
else else
sur_player = CLIENT_get_partner(client) sur_player = CLIENT_get_partner(client)
if sur_player.closed or sur_player.is_local if !sur_player or sur_player.closed or sur_player.is_local
sur_player = client sur_player = client
if room.hostinfo.mode==2 and sur_player != client if room.hostinfo.mode==2 and sur_player != client
ygopro.stoc_send_chat(sur_player, "${surrender_confirm_tag}", ygopro.constants.COLORS.BABYBLUE) ygopro.stoc_send_chat(sur_player, "${surrender_confirm_tag}", ygopro.constants.COLORS.BABYBLUE)
...@@ -3362,6 +3354,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)-> ...@@ -3362,6 +3354,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
ygopro.stoc_send_chat(client, "${chat_order_main}") ygopro.stoc_send_chat(client, "${chat_order_main}")
ygopro.stoc_send_chat(client, "${chat_order_help}") ygopro.stoc_send_chat(client, "${chat_order_help}")
ygopro.stoc_send_chat(client, "${chat_order_refresh}")
ygopro.stoc_send_chat(client, "${chat_order_roomname}") if !settings.modules.mycard.enabled ygopro.stoc_send_chat(client, "${chat_order_roomname}") if !settings.modules.mycard.enabled
ygopro.stoc_send_chat(client, "${chat_order_windbot}") if settings.modules.windbot.enabled ygopro.stoc_send_chat(client, "${chat_order_windbot}") if settings.modules.windbot.enabled
ygopro.stoc_send_chat(client, "${chat_order_tip}") if settings.modules.tips.enabled ygopro.stoc_send_chat(client, "${chat_order_tip}") if settings.modules.tips.enabled
...@@ -3390,6 +3383,15 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)-> ...@@ -3390,6 +3383,15 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
when '/roomname' when '/roomname'
ygopro.stoc_send_chat(client, "${room_name} " + room.name, ygopro.constants.COLORS.BABYBLUE) if room ygopro.stoc_send_chat(client, "${room_name} " + room.name, ygopro.constants.COLORS.BABYBLUE) if room
when '/refresh'
if room.duel_stage == ygopro.constants.DUEL_STAGE.DUELING and client.last_game_msg and client.last_game_msg_title != 'WAITING'
if client.last_hint_msg
ygopro.stoc_send(client, 'GAME_MSG', client.last_hint_msg)
ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg)
ygopro.stoc_send_chat(client, '${refresh_success}', ygopro.constants.COLORS.BABYBLUE)
else
ygopro.stoc_send_chat(client, '${refresh_fail}', ygopro.constants.COLORS.RED)
when '/color' when '/color'
if settings.modules.chat_color.enabled if settings.modules.chat_color.enabled
...@@ -3501,7 +3503,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)-> ...@@ -3501,7 +3503,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
client.abuse_count=client.abuse_count+2 if client.abuse_count client.abuse_count=client.abuse_count+2 if client.abuse_count
ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED) ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED)
cancel = true cancel = true
if !(room and (room.random_type or room.arena)) if !(room and (room.random_type or room.arena)) and not settings.modules.mycard.enabled
if !cancel and settings.modules.display_watchers and client.is_post_watcher if !cancel and settings.modules.display_watchers and client.is_post_watcher
ygopro.stoc_send_chat_to_room(room, "#{client.name}: #{msg}", 9) ygopro.stoc_send_chat_to_room(room, "#{client.name}: #{msg}", 9)
return true return true
...@@ -3615,7 +3617,7 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)-> ...@@ -3615,7 +3617,7 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
if room.random_type or room.arena if room.random_type or room.arena
if client.pos == 0 if client.pos == 0
room.waiting_for_player = room.waiting_for_player2 room.waiting_for_player = room.waiting_for_player2
room.last_active_time = moment_now_string room.refreshLastActiveTime()
if room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and room.recovering if room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and room.recovering
recover_player_data = _.find(room.recover_duel_log.players, (player) -> recover_player_data = _.find(room.recover_duel_log.players, (player) ->
return player.realName == client.name_vpass and buffer.compare(Buffer.from(player.startDeckBuffer, "base64")) == 0 return player.realName == client.name_vpass and buffer.compare(Buffer.from(player.startDeckBuffer, "base64")) == 0
...@@ -3632,48 +3634,63 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)-> ...@@ -3632,48 +3634,63 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
struct.set("sidec", 1) struct.set("sidec", 1)
struct.set("deckbuf", [4392470, 4392470]) struct.set("deckbuf", [4392470, 4392470])
ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED) ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED)
else if room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and settings.modules.tournament_mode.enabled and settings.modules.tournament_mode.deck_check return false
decks = await fs.promises.readdir(settings.modules.tournament_mode.deck_path) else
if decks.length if room.arena and settings.modules.athletic_check.enabled and settings.modules.athletic_check.banCount
struct.set("mainc", 1) athleticCheckResult = await athleticChecker.checkAthletic({main: buff_main, side: buff_side})
struct.set("sidec", 1) if athleticCheckResult.success
struct.set("deckbuf", [4392470, 4392470]) if athleticCheckResult.athletic and athleticCheckResult.athletic <= settings.modules.athletic_check.banCount
buffer = struct.buffer struct.set("mainc", 1)
found_deck=false struct.set("sidec", 1)
for deck in decks struct.set("deckbuf", [4392470, 4392470])
if deck_name_match(deck, client.name) ygopro.stoc_send_chat(client, "${banned_athletic_deck_part1}#{settings.modules.athletic_check.banCount}${banned_athletic_deck_part2}", ygopro.constants.COLORS.RED)
found_deck=deck return false
if found_deck
deck_text = await fs.promises.readFile(settings.modules.tournament_mode.deck_path+found_deck,{encoding:"ASCII"})
deck_array=deck_text.split("\n")
deck_main=[]
deck_side=[]
current_deck=deck_main
for line in deck_array
if line.indexOf("!side")>=0
current_deck=deck_side
card=parseInt(line)
current_deck.push(card) unless isNaN(card)
if _.isEqual(buff_main, deck_main) and _.isEqual(buff_side, deck_side)
deckbuf=deck_main.concat(deck_side)
struct.set("mainc", deck_main.length)
struct.set("sidec", deck_side.length)
struct.set("deckbuf", deckbuf)
buffer = struct.buffer
#log.info("deck ok: " + client.name)
ygopro.stoc_send_chat(client, "${deck_correct_part1} #{found_deck} ${deck_correct_part2}", ygopro.constants.COLORS.BABYBLUE)
else
#log.info("bad deck: " + client.name + " / " + buff_main + " / " + buff_side)
ygopro.stoc_send_chat(client, "${deck_incorrect_part1} #{found_deck} ${deck_incorrect_part2}", ygopro.constants.COLORS.RED)
else else
#log.info("player deck not found: " + client.name) log.warn("GET ATHLETIC FAIL", client.name, athleticCheckResult.message)
ygopro.stoc_send_chat(client, "#{client.name}${deck_not_found}", ygopro.constants.COLORS.RED) if room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and settings.modules.tournament_mode.enabled and settings.modules.tournament_mode.deck_check
decks = await fs.promises.readdir(settings.modules.tournament_mode.deck_path)
if decks.length
struct.set("mainc", 1)
struct.set("sidec", 1)
struct.set("deckbuf", [4392470, 4392470])
buffer = struct.buffer
found_deck=false
for deck in decks
if deck_name_match(deck, client.name)
found_deck=deck
if found_deck
deck_text = await fs.promises.readFile(settings.modules.tournament_mode.deck_path+found_deck,{encoding:"ASCII"})
deck_array=deck_text.split("\n")
deck_main=[]
deck_side=[]
current_deck=deck_main
for line in deck_array
if line.indexOf("!side")>=0
current_deck=deck_side
card=parseInt(line)
current_deck.push(card) unless isNaN(card)
if _.isEqual(buff_main, deck_main) and _.isEqual(buff_side, deck_side)
deckbuf=deck_main.concat(deck_side)
struct.set("mainc", deck_main.length)
struct.set("sidec", deck_side.length)
struct.set("deckbuf", deckbuf)
buffer = struct.buffer
#log.info("deck ok: " + client.name)
ygopro.stoc_send_chat(client, "${deck_correct_part1} #{found_deck} ${deck_correct_part2}", ygopro.constants.COLORS.BABYBLUE)
else
#log.info("bad deck: " + client.name + " / " + buff_main + " / " + buff_side)
ygopro.stoc_send_chat(client, "${deck_incorrect_part1} #{found_deck} ${deck_incorrect_part2}", ygopro.constants.COLORS.RED)
return false
else
#log.info("player deck not found: " + client.name)
ygopro.stoc_send_chat(client, "#{client.name}${deck_not_found}", ygopro.constants.COLORS.RED)
return false
await return false await return false
ygopro.ctos_follow 'RESPONSE', false, (buffer, info, client, server, datas)-> ygopro.ctos_follow 'RESPONSE', false, (buffer, info, client, server, datas)->
room=ROOM_all[client.rid] room=ROOM_all[client.rid]
return unless room and (room.random_type or room.arena) return unless room and (room.random_type or room.arena)
room.last_active_time = moment_now_string room.refreshLastActiveTime()
await return await return
ygopro.stoc_follow 'TIME_LIMIT', true, (buffer, info, client, server, datas)-> ygopro.stoc_follow 'TIME_LIMIT', true, (buffer, info, client, server, datas)->
...@@ -3742,7 +3759,7 @@ ygopro.ctos_follow 'HAND_RESULT', false, (buffer, info, client, server, datas)-> ...@@ -3742,7 +3759,7 @@ ygopro.ctos_follow 'HAND_RESULT', false, (buffer, info, client, server, datas)->
if room.random_type or room.arena if room.random_type or room.arena
if client.pos == 0 if client.pos == 0
room.waiting_for_player = room.waiting_for_player2 room.waiting_for_player = room.waiting_for_player2
room.last_active_time = moment_long_ago_string room.refreshLastActiveTime(true)
await return await return
ygopro.ctos_follow 'TP_RESULT', false, (buffer, info, client, server, datas)-> ygopro.ctos_follow 'TP_RESULT', false, (buffer, info, client, server, datas)->
...@@ -3751,7 +3768,7 @@ ygopro.ctos_follow 'TP_RESULT', false, (buffer, info, client, server, datas)-> ...@@ -3751,7 +3768,7 @@ ygopro.ctos_follow 'TP_RESULT', false, (buffer, info, client, server, datas)->
client.selected_preduel = true client.selected_preduel = true
# room.selecting_tp = false # room.selecting_tp = false
return unless room.random_type or room.arena return unless room.random_type or room.arena
room.last_active_time = moment_now_string room.refreshLastActiveTime()
await return await return
ygopro.stoc_follow 'CHAT', true, (buffer, info, client, server, datas)-> ygopro.stoc_follow 'CHAT', true, (buffer, info, client, server, datas)->
...@@ -3790,7 +3807,7 @@ ygopro.stoc_follow 'SELECT_HAND', true, (buffer, info, client, server, datas)-> ...@@ -3790,7 +3807,7 @@ ygopro.stoc_follow 'SELECT_HAND', true, (buffer, info, client, server, datas)->
room.waiting_for_player = client room.waiting_for_player = client
else else
room.waiting_for_player2 = client room.waiting_for_player2 = client
room.last_active_time = moment_long_ago_string room.refreshLastActiveTime(true)
if room.determine_firstgo if room.determine_firstgo
ygopro.ctos_send(server, "HAND_RESULT", { ygopro.ctos_send(server, "HAND_RESULT", {
res: if client.pos == 0 then 2 else 1 res: if client.pos == 0 then 2 else 1
...@@ -3811,7 +3828,7 @@ ygopro.stoc_follow 'SELECT_TP', true, (buffer, info, client, server, datas)-> ...@@ -3811,7 +3828,7 @@ ygopro.stoc_follow 'SELECT_TP', true, (buffer, info, client, server, datas)->
room.duel_stage = ygopro.constants.DUEL_STAGE.FIRSTGO room.duel_stage = ygopro.constants.DUEL_STAGE.FIRSTGO
if room.random_type or room.arena if room.random_type or room.arena
room.waiting_for_player = client room.waiting_for_player = client
room.last_active_time = moment_now_string room.refreshLastActiveTime()
if room.determine_firstgo if room.determine_firstgo
ygopro.ctos_send(server, "TP_RESULT", { ygopro.ctos_send(server, "TP_RESULT", {
res: if room.determine_firstgo == client then 1 else 0 res: if room.determine_firstgo == client then 1 else 0
...@@ -3867,7 +3884,7 @@ ygopro.stoc_follow 'CHANGE_SIDE', false, (buffer, info, client, server, datas)-> ...@@ -3867,7 +3884,7 @@ ygopro.stoc_follow 'CHANGE_SIDE', false, (buffer, info, client, server, datas)->
room.waiting_for_player = client room.waiting_for_player = client
else else
room.waiting_for_player2 = client room.waiting_for_player2 = client
room.last_active_time = moment_now_string room.refreshLastActiveTime()
await return await return
ygopro.stoc_follow 'REPLAY', true, (buffer, info, client, server, datas)-> ygopro.stoc_follow 'REPLAY', true, (buffer, info, client, server, datas)->
......
...@@ -36,8 +36,6 @@ ...@@ -36,8 +36,6 @@
request = require('request'); request = require('request');
axios = require('axios');
qs = require("querystring"); qs = require("querystring");
zlib = require('zlib'); zlib = require('zlib');
...@@ -520,6 +518,7 @@ ...@@ -520,6 +518,7 @@
await setting_save(settings); await setting_save(settings);
} }
if (settings.modules.mysql.enabled) { if (settings.modules.mysql.enabled) {
global.PrimaryKeyType = settings.modules.mysql.db.type === 'sqlite' ? 'integer' : 'bigint';
DataManager = require('./data-manager/DataManager.js').DataManager; DataManager = require('./data-manager/DataManager.js').DataManager;
dataManager = global.dataManager = new DataManager(settings.modules.mysql.db, log); dataManager = global.dataManager = new DataManager(settings.modules.mysql.db, log);
log.info('Connecting to database.'); log.info('Connecting to database.');
...@@ -624,9 +623,9 @@ ...@@ -624,9 +623,9 @@
badwordR.level2 = new RegExp('(?:' + badwords.level2.join(')|(?:') + ')', 'i'); badwordR.level2 = new RegExp('(?:' + badwords.level2.join(')|(?:') + ')', 'i');
badwordR.level3 = new RegExp('(?:' + badwords.level3.join(')|(?:') + ')', 'i'); badwordR.level3 = new RegExp('(?:' + badwords.level3.join(')|(?:') + ')', 'i');
setInterval(function() { setInterval(function() {
moment_now = moment(); moment_now = global.moment_now = moment();
moment_now_string = moment_now.format(); moment_now_string = global.moment_now_string = moment_now.format();
moment_long_ago_string = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's').format(); moment_long_ago_string = global.moment_long_ago_string = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's').format();
}, 500); }, 500);
if (settings.modules.max_rooms_count) { if (settings.modules.max_rooms_count) {
rooms_count = 0; rooms_count = 0;
...@@ -787,17 +786,32 @@ ...@@ -787,17 +786,32 @@
load_tips_zh(); load_tips_zh();
} }
if (settings.modules.tips.enabled) { if (settings.modules.tips.enabled) {
setInterval(function() { if (settings.modules.tips.interval) {
var l, len1, room; setInterval(function() {
for (l = 0, len1 = ROOM_all.length; l < len1; l++) { var l, len1, room;
room = ROOM_all[l]; for (l = 0, len1 = ROOM_all.length; l < len1; l++) {
if (room && room.established) { room = ROOM_all[l];
if (room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING || room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) { if (room && room.established && room.duel_stage !== ygopro.constants.END) {
ygopro.stoc_send_random_tip_to_room(room); if (room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING) {
ygopro.stoc_send_random_tip_to_room(room);
}
} }
} }
} }, settings.modules.tips.interval);
}, 30000); }
if (settings.modules.tips.interval_ingame) {
setInterval(function() {
var l, len1, room;
for (l = 0, len1 = ROOM_all.length; l < len1; l++) {
room = ROOM_all[l];
if (room && room.established && room.duel_stage !== ygopro.constants.END) {
if (room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING) {
ygopro.stoc_send_random_tip_to_room(room);
}
}
}
}, settings.modules.tips.interval_ingame);
}
} }
if (settings.modules.dialogues.enabled && settings.modules.dialogues.get) { if (settings.modules.dialogues.enabled && settings.modules.dialogues.get) {
load_dialogues(); load_dialogues();
...@@ -832,9 +846,9 @@ ...@@ -832,9 +846,9 @@
continue; continue;
} }
time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000); time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000);
//log.info time_passed //log.info time_passed, moment_now_string
if (time_passed >= settings.modules.random_duel.hang_timeout) { if (time_passed >= settings.modules.random_duel.hang_timeout) {
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
await ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}"); await ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}");
room.scores[room.waiting_for_player.name_vpass] = -9; room.scores[room.waiting_for_player.name_vpass] = -9;
//log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass] //log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
...@@ -859,7 +873,7 @@ ...@@ -859,7 +873,7 @@
time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000); time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000);
//log.info time_passed //log.info time_passed
if (time_passed >= settings.modules.random_duel.hang_timeout) { if (time_passed >= settings.modules.random_duel.hang_timeout) {
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
ygopro.stoc_send_chat_to_room(room, `${room.waiting_for_player.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED); ygopro.stoc_send_chat_to_room(room, `${room.waiting_for_player.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED);
room.scores[room.waiting_for_player.name_vpass] = -9; room.scores[room.waiting_for_player.name_vpass] = -9;
//log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass] //log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
...@@ -1449,7 +1463,7 @@ ...@@ -1449,7 +1463,7 @@
return false; return false;
} }
disconnect_info = disconnect_list[CLIENT_get_authorize_key(client)]; disconnect_info = disconnect_list[CLIENT_get_authorize_key(client)];
if (!disconnect_info) { if (!(disconnect_info && disconnect_info.deckbuf)) {
return false; return false;
} }
room = ROOM_all[disconnect_info.room_id]; room = ROOM_all[disconnect_info.room_id];
...@@ -1579,7 +1593,7 @@ ...@@ -1579,7 +1593,7 @@
client.established = true; client.established = true;
client.pre_establish_buffers = []; client.pre_establish_buffers = [];
if (room.random_type || room.arena) { if (room.random_type || room.arena) {
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
} }
CLIENT_import_data(client, dinfo.old_client, room); CLIENT_import_data(client, dinfo.old_client, room);
CLIENT_send_reconnect_info(client, client.server, room); CLIENT_send_reconnect_info(client, client.server, room);
...@@ -1611,7 +1625,7 @@ ...@@ -1611,7 +1625,7 @@
client.established = true; client.established = true;
client.pre_establish_buffers = []; client.pre_establish_buffers = [];
if (room.random_type || room.arena) { if (room.random_type || room.arena) {
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
} }
CLIENT_import_data(client, player, room); CLIENT_import_data(client, player, room);
CLIENT_send_reconnect_info(client, client.server, room); CLIENT_send_reconnect_info(client, client.server, room);
...@@ -1720,27 +1734,9 @@ ...@@ -1720,27 +1734,9 @@
}; };
getSeedTimet = global.getSeedTimet = function(count) { getSeedTimet = global.getSeedTimet = function(count) {
var curTime, i, j, offset, ref, ret; return _.range(count).map(() => {
ret = []; return 0;
for (i = j = 0, ref = count; (0 <= ref ? j < ref : j > ref); i = 0 <= ref ? ++j : --j) {
curTime = null;
while (!curTime || _.any(ret, function(time) {
return time === curTime.unix();
})) {
curTime = moment_now;
offset = Math.floor(Math.random() * 240) - 120;
if (offset > 0) {
curTime = curTime.add(offset, "s");
} else if (offset < 0) {
curTime = curTime.subtract(-offset, "s");
}
}
ret.push(curTime.unix());
}
ret.sort(function(a, b) {
return a - b;
}); });
return ret;
}; };
Room = class Room { Room = class Room {
...@@ -1786,14 +1782,14 @@ ...@@ -1786,14 +1782,14 @@
this.hostinfo.mode = 2; this.hostinfo.mode = 2;
this.hostinfo.start_lp = 16000; this.hostinfo.start_lp = 16000;
} else if (name.slice(0, 3) === 'AI#') { } else if (name.slice(0, 3) === 'AI#') {
this.hostinfo.rule = 2; this.hostinfo.rule = 5;
this.hostinfo.lflist = -1; this.hostinfo.lflist = -1;
this.hostinfo.time_limit = 0; this.hostinfo.time_limit = 0;
this.hostinfo.no_check_deck = true; this.hostinfo.no_check_deck = true;
} else if ((param = name.match(/^(\d)(\d)(T|F)(T|F)(T|F)(\d+),(\d+),(\d+)/i))) { } else if ((param = name.match(/^(\d)(\d)([12345TF])(T|F)(T|F)(\d+),(\d+),(\d+)/i))) {
this.hostinfo.rule = parseInt(param[1]); this.hostinfo.rule = parseInt(param[1]);
this.hostinfo.mode = parseInt(param[2]); this.hostinfo.mode = parseInt(param[2]);
this.hostinfo.duel_rule = (param[3] === 'T' ? 3 : 4); this.hostinfo.duel_rule = (parseInt(param[3]) ? parseInt(param[3]) : (param[3] === 'T' ? 3 : 5));
this.hostinfo.no_check_deck = param[4] === 'T'; this.hostinfo.no_check_deck = param[4] === 'T';
this.hostinfo.no_shuffle_deck = param[5] === 'T'; this.hostinfo.no_shuffle_deck = param[5] === 'T';
this.hostinfo.start_lp = parseInt(param[6]); this.hostinfo.start_lp = parseInt(param[6]);
...@@ -1813,11 +1809,11 @@ ...@@ -1813,11 +1809,11 @@
this.hostinfo.lflist = 0; this.hostinfo.lflist = 0;
} }
if (rule.match(/(^|,|,)(OR|OCGRANDOM)(,|,|$)/)) { if (rule.match(/(^|,|,)(OR|OCGRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 2; this.hostinfo.rule = 5;
this.hostinfo.lflist = 0; this.hostinfo.lflist = 0;
} }
if (rule.match(/(^|,|,)(CR|CCGRANDOM)(,|,|$)/)) { if (rule.match(/(^|,|,)(CR|CCGRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 4; this.hostinfo.rule = 2;
this.hostinfo.lflist = -1; this.hostinfo.lflist = -1;
} }
if (rule.match(/(^|,|,)(TOR|TCGONLYRANDOM)(,|,|$)/)) { if (rule.match(/(^|,|,)(TOR|TCGONLYRANDOM)(,|,|$)/)) {
...@@ -1827,7 +1823,7 @@ ...@@ -1827,7 +1823,7 @@
}); });
} }
if (rule.match(/(^|,|,)(TR|TCGRANDOM)(,|,|$)/)) { if (rule.match(/(^|,|,)(TR|TCGRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 2; this.hostinfo.rule = 5;
this.hostinfo.lflist = _.findIndex(lflists, function(list) { this.hostinfo.lflist = _.findIndex(lflists, function(list) {
return list.tcg; return list.tcg;
}); });
...@@ -1838,12 +1834,12 @@ ...@@ -1838,12 +1834,12 @@
this.hostinfo.mode = 1; this.hostinfo.mode = 1;
} }
if (rule.match(/(^|,|,)(OMR|OCGMATCHRANDOM)(,|,|$)/)) { if (rule.match(/(^|,|,)(OMR|OCGMATCHRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 2; this.hostinfo.rule = 5;
this.hostinfo.lflist = 0; this.hostinfo.lflist = 0;
this.hostinfo.mode = 1; this.hostinfo.mode = 1;
} }
if (rule.match(/(^|,|,)(CMR|CCGMATCHRANDOM)(,|,|$)/)) { if (rule.match(/(^|,|,)(CMR|CCGMATCHRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 4; this.hostinfo.rule = 2;
this.hostinfo.lflist = -1; this.hostinfo.lflist = -1;
this.hostinfo.mode = 1; this.hostinfo.mode = 1;
} }
...@@ -1855,7 +1851,7 @@ ...@@ -1855,7 +1851,7 @@
this.hostinfo.mode = 1; this.hostinfo.mode = 1;
} }
if (rule.match(/(^|,|,)(TMR|TCGMATCHRANDOM)(,|,|$)/)) { if (rule.match(/(^|,|,)(TMR|TCGMATCHRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 2; this.hostinfo.rule = 5;
this.hostinfo.lflist = _.findIndex(lflists, function(list) { this.hostinfo.lflist = _.findIndex(lflists, function(list) {
return list.tcg; return list.tcg;
}); });
...@@ -1872,10 +1868,10 @@ ...@@ -1872,10 +1868,10 @@
this.hostinfo.lflist = 0; this.hostinfo.lflist = 0;
} }
if (rule.match(/(^|,|,)(OT|TCG)(,|,|$)/)) { if (rule.match(/(^|,|,)(OT|TCG)(,|,|$)/)) {
this.hostinfo.rule = 2; this.hostinfo.rule = 5;
} }
if (rule.match(/(^|,|,)(CN|CCG|CHINESE)(,|,|$)/)) { if (rule.match(/(^|,|,)(SC|CN|CCG|CHINESE)(,|,|$)/)) {
this.hostinfo.rule = 4; this.hostinfo.rule = 2;
this.hostinfo.lflist = -1; this.hostinfo.lflist = -1;
} }
if ((param = rule.match(/(^|,|,)LP(\d+)(,|,|$)/))) { if ((param = rule.match(/(^|,|,)LP(\d+)(,|,|$)/))) {
...@@ -1926,6 +1922,9 @@ ...@@ -1926,6 +1922,9 @@
this.hostinfo.lflist = -1; this.hostinfo.lflist = -1;
} }
if (rule.match(/(^|,|,)(NOUNIQUE|NU)(,|,|$)/)) { if (rule.match(/(^|,|,)(NOUNIQUE|NU)(,|,|$)/)) {
this.hostinfo.rule = 4;
}
if (rule.match(/(^|,|,)(CUSTOM|DIY)(,|,|$)/)) {
this.hostinfo.rule = 3; this.hostinfo.rule = 3;
} }
if (rule.match(/(^|,|,)(NOCHECK|NC)(,|,|$)/)) { if (rule.match(/(^|,|,)(NOCHECK|NC)(,|,|$)/)) {
...@@ -2419,7 +2418,7 @@ ...@@ -2419,7 +2418,7 @@
this.finished = true; this.finished = true;
if (!this.finished_by_death) { if (!this.finished_by_death) {
this.scores[client.name_vpass] = -9; this.scores[client.name_vpass] = -9;
if (this.random_type && !client.flee_free && (!settings.modules.reconnect.enabled || this.get_disconnected_count() === 0)) { if (this.random_type && !client.flee_free && (!settings.modules.reconnect.enabled || this.get_disconnected_count() === 0) && !client.kicked_by_system && !client.kicked_by_player) {
ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}"); ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}");
if (settings.modules.random_duel.record_match_scores && this.random_type === 'M') { if (settings.modules.random_duel.record_match_scores && this.random_type === 'M') {
ROOM_player_flee(client.name_vpass); ROOM_player_flee(client.name_vpass);
...@@ -2653,6 +2652,14 @@ ...@@ -2653,6 +2652,14 @@
return results; return results;
} }
refreshLastActiveTime(longAgo) {
if (longAgo) {
return this.last_active_time = moment_long_ago_string;
} else {
return this.last_active_time = moment_now_string;
}
}
}; };
// 网络连接 // 网络连接
...@@ -2666,7 +2673,11 @@ ...@@ -2666,7 +2673,11 @@
} }
ROOM_connected_ip[client.ip] = connect_count; ROOM_connected_ip[client.ip] = connect_count;
//log.info "connect", client.ip, ROOM_connected_ip[client.ip] //log.info "connect", client.ip, ROOM_connected_ip[client.ip]
if (ROOM_bad_ip[client.ip] > 5 || ROOM_connected_ip[client.ip] > 10) {
log.info('BAD IP', client.ip);
client.destroy();
return;
}
// server stand for the connection to ygopro server process // server stand for the connection to ygopro server process
server = new net.Socket(); server = new net.Socket();
client.server = server; client.server = server;
...@@ -2766,11 +2777,6 @@ ...@@ -2766,11 +2777,6 @@
SERVER_clear_disconnect(server); SERVER_clear_disconnect(server);
} }
}); });
if (ROOM_bad_ip[client.ip] > 5 || ROOM_connected_ip[client.ip] > 10) {
log.info('BAD IP', client.ip);
CLIENT_kick(client);
return;
}
client.playLines = function(lines) { client.playLines = function(lines) {
var j, len, line, ref, results; var j, len, line, ref, results;
ref = _.lines(lines); ref = _.lines(lines);
...@@ -2808,7 +2814,7 @@ ...@@ -2808,7 +2814,7 @@
// 客户端到服务端(ctos)协议分析 // 客户端到服务端(ctos)协议分析
client.pre_establish_buffers = new Array(); client.pre_establish_buffers = new Array();
client.on('data', async function(ctos_buffer) { client.on('data', async function(ctos_buffer) {
var bad_ip_count, buffer, ctos_filter, handle_data, j, l, len, len1, len2, m, ref, ref1, ref2, room; var bad_ip_count, buffer, ctos_filter, handle_data, j, l, len, len1, len2, m, preconnect, ref, ref1, ref2, room;
if (client.is_post_watcher) { if (client.is_post_watcher) {
room = ROOM_all[client.rid]; room = ROOM_all[client.rid];
if (room) { if (room) {
...@@ -2836,14 +2842,22 @@ ...@@ -2836,14 +2842,22 @@
} }
} }
} else { } else {
ctos_filter = settings.modules.reconnect.enabled && client.pre_reconnecting ? ["UPDATE_DECK"] : null; ctos_filter = null;
preconnect = false;
if (settings.modules.reconnect.enabled && client.pre_reconnecting_to_room) {
ctos_filter = ["UPDATE_DECK"];
}
if (client.name === null) {
ctos_filter = ["JOIN_GAME", "PLAYER_INFO"];
preconnect = true;
}
handle_data = (await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, { handle_data = (await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, {
client: client, client: client,
server: client.server server: client.server
})); }, preconnect));
if (handle_data.feedback) { if (handle_data.feedback) {
log.warn(handle_data.feedback.message, client.name, client.ip); log.warn(handle_data.feedback.message, client.name, client.ip);
if (handle_data.feedback.type === "OVERSIZE" || ROOM_bad_ip[client.ip] > 5) { if (handle_data.feedback.type === "OVERSIZE" || handle_data.feedback.type === "INVALID_PACKET" || ROOM_bad_ip[client.ip] > 5) {
bad_ip_count = ROOM_bad_ip[client.ip]; bad_ip_count = ROOM_bad_ip[client.ip];
if (bad_ip_count) { if (bad_ip_count) {
ROOM_bad_ip[client.ip] = bad_ip_count + 1; ROOM_bad_ip[client.ip] = bad_ip_count + 1;
...@@ -2854,7 +2868,7 @@ ...@@ -2854,7 +2868,7 @@
return; return;
} }
} }
if (!client.server) { if (client.closed || !client.server) {
return; return;
} }
if (client.established) { if (client.established) {
...@@ -2908,7 +2922,13 @@ ...@@ -2908,7 +2922,13 @@
// 功能模块 // 功能模块
// return true to cancel a synchronous message // return true to cancel a synchronous message
ygopro.ctos_follow('PLAYER_INFO', true, async function(buffer, info, client, server, datas) { ygopro.ctos_follow('PLAYER_INFO', true, async function(buffer, info, client, server, datas) {
var banMCRequest, e, geo, lang, name, name_full, struct, vpass; var geo, lang, name, name_full, struct, vpass;
// second PLAYER_INFO = attack
if (client.name) {
log.info('DUP PLAYER_INFO', client.ip);
CLIENT_kick(client);
return '_cancel';
}
// checkmate use username$password, but here don't // checkmate use username$password, but here don't
// so remove the password // so remove the password
name_full = info.name.replace(/\\/g, "").split("$"); name_full = info.name.replace(/\\/g, "").split("$");
...@@ -2929,24 +2949,6 @@ ...@@ -2929,24 +2949,6 @@
}, name)) { }, name)) {
client.rag = true; client.rag = true;
} }
if (settings.modules.mycard.enabled && settings.modules.mycard.ban_get && !client.is_local) {
try {
banMCRequest = (await axios.get(settings.modules.mycard.ban_get, {
paramsSerializer: qs.stringify,
params: {
user: name
}
}));
if (typeof banMCRequest.data === "object") {
client.ban_mc = banMCRequest.data;
} else {
log.warn("ban get bad json", banMCRequest.data);
}
} catch (error1) {
e = error1;
log.warn('ban get error', e.toString());
}
}
struct = ygopro.structs.get("CTOS_PlayerInfo"); struct = ygopro.structs.get("CTOS_PlayerInfo");
struct._setBuff(buffer); struct._setBuff(buffer);
struct.set("name", name); struct.set("name", name);
...@@ -2975,7 +2977,7 @@ ...@@ -2975,7 +2977,7 @@
}); });
ygopro.ctos_follow('JOIN_GAME', true, async function(buffer, info, client, server, datas) { ygopro.ctos_follow('JOIN_GAME', true, async function(buffer, info, client, server, datas) {
var available_logs, check_buffer_indentity, create_room_with_action, duelLog, exactBan, index, j, l, len, len1, pre_room, recover_match, replay, replay_id, replays, room, struct; var available_logs, check_buffer_indentity, create_room_with_action, decrypted_buffer, duelLog, e, exactBan, i, id, index, j, l, len, len1, len2, len3, m, n, pre_room, recover_match, ref, ref1, replay, replay_id, replays, room, secret, struct, userData, userDataRes, userUrl;
//log.info info //log.info info
info.pass = info.pass.trim(); info.pass = info.pass.trim();
client.pass = info.pass; client.pass = info.pass;
...@@ -3055,6 +3057,22 @@ ...@@ -3055,6 +3057,22 @@
ygopro.stoc_die(client, '${invalid_password_payload}'); ygopro.stoc_die(client, '${invalid_password_payload}');
return; return;
} }
if (settings.modules.mycard.enabled && settings.modules.mycard.ban_get && !client.is_local) {
axios.get(settings.modules.mycard.ban_get, {
paramsSerializer: qs.stringify,
params: {
user: client.name
}
}).then(function(banMCRequest) {
if (typeof banMCRequest.data === "object") {
return client.ban_mc = banMCRequest.data;
} else {
return log.warn("ban get bad json", banMCRequest.data);
}
}).catch(function(e) {
return log.warn('ban get error', e.toString());
});
}
check_buffer_indentity = function(buf) { check_buffer_indentity = function(buf) {
var checksum, i, m, ref; var checksum, i, m, ref;
checksum = 0; checksum = 0;
...@@ -3063,8 +3081,8 @@ ...@@ -3063,8 +3081,8 @@
} }
return (checksum & 0xFF) === 0; return (checksum & 0xFF) === 0;
}; };
create_room_with_action = async function(buffer, decrypted_buffer, match_permit) { create_room_with_action = async function(buffer, decrypted_buffer) {
var action, firstByte, len2, m, name, opt0, opt1, opt2, opt3, options, player, ref, ref1, room, room_title, title; var action, e, firstByte, len2, m, matchPermitRes, match_permit, name, opt0, opt1, opt2, opt3, options, player, ref, ref1, room, room_title, title;
if (client.closed) { if (client.closed) {
return; return;
} }
...@@ -3094,9 +3112,9 @@ ...@@ -3094,9 +3112,9 @@
options = { options = {
lflist: settings.hostinfo.lflist, lflist: settings.hostinfo.lflist,
time_limit: settings.hostinfo.time_limit, time_limit: settings.hostinfo.time_limit,
rule: (opt1 >> 5) & 0x7, // 0 1 2 3 4 rule: (opt1 >> 5) & 0x7, // 0 1 2 3 4 5
mode: (opt1 >> 3) & 0x3, // 0 1 2 mode: (opt1 >> 3) & 0x3, // 0 1 2
duel_rule: opt0 >> 1, // 1 2 3 4 5 duel_rule: (opt0 >> 1) || 5, // 1 2 3 4 5
no_check_deck: !!((opt1 >> 1) & 1), no_check_deck: !!((opt1 >> 1) & 1),
no_shuffle_deck: !!(opt1 & 1), no_shuffle_deck: !!(opt1 & 1),
start_lp: opt2, start_lp: opt2,
...@@ -3108,9 +3126,13 @@ ...@@ -3108,9 +3126,13 @@
} }
}; };
//console.log(options) //console.log(options)
options.lflist = _.findIndex(lflists, function(list) { if (options.rule === 2) {
return ((options.rule === 1) === list.tcg) && list.date.isBefore(); options.lflist = -1;
}); } else if (options.rule !== 3) {
options.lflist = _.findIndex(lflists, function(list) {
return ((options.rule === 1) === list.tcg) && list.date.isBefore();
});
}
room_title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' '); room_title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ');
if (badwordR.level3.test(room_title)) { if (badwordR.level3.test(room_title)) {
log.warn("BAD ROOM NAME LEVEL 3", room_title, client.name, client.ip); log.warn("BAD ROOM NAME LEVEL 3", room_title, client.name, client.ip);
...@@ -3140,9 +3162,29 @@ ...@@ -3140,9 +3162,29 @@
} }
break; break;
case 4: case 4:
if (match_permit && !match_permit.permit) { if (settings.modules.arena_mode.check_permit) {
ygopro.stoc_die(client, '${invalid_password_unauthorized}'); try {
return; matchPermitRes = (await axios.get(settings.modules.arena_mode.check_permit, {
responseType: 'json',
timeout: 3000,
params: {
username: client.name,
password: info.pass,
arena: settings.modules.arena_mode.mode
}
}));
match_permit = matchPermitRes.data;
} catch (error1) {
e = error1;
log.warn(`match permit fail ${e.toString()}`);
}
if (client.closed) {
return;
}
if (match_permit && match_permit.permit === false) {
ygopro.stoc_die(client, '${invalid_password_unauthorized}');
return;
}
} }
room = (await ROOM_find_or_create_by_name('M#' + info.pass.slice(8))); room = (await ROOM_find_or_create_by_name('M#' + info.pass.slice(8)));
if (room) { if (room) {
...@@ -3183,108 +3225,60 @@ ...@@ -3183,108 +3225,60 @@
room.join_player(client); room.join_player(client);
} }
}; };
_async.auto({ decrypted_buffer = null;
match_permit: function(done) { if (id = users_cache[client.name]) {
if (client.closed) { secret = id % 65535 + 1;
done(); decrypted_buffer = Buffer.allocUnsafe(6);
return; ref = [0, 2, 4];
} for (m = 0, len2 = ref.length; m < len2; m++) {
if (!settings.modules.arena_mode.check_permit) { i = ref[m];
done(null, null); decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
return;
}
request({
url: settings.modules.arena_mode.check_permit,
json: true,
qs: {
username: client.name,
password: info.pass,
arena: settings.modules.arena_mode.mode
}
}, function(error, response, body) {
if (client.closed) {
done(null, null);
return;
}
if (!error && body) {
done(null, body);
} else {
log.warn("Match permit request error", error);
done(null, null);
}
});
},
get_user: function(done) {
var decrypted_buffer, i, id, len2, m, ref, secret;
if (client.closed) {
done();
return;
}
if (id = users_cache[client.name]) {
secret = id % 65535 + 1;
decrypted_buffer = Buffer.allocUnsafe(6);
ref = [0, 2, 4];
for (m = 0, len2 = ref.length; m < len2; m++) {
i = ref[m];
decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
}
if (check_buffer_indentity(decrypted_buffer)) {
done(null, {
original: decrypted_buffer,
decrypted: decrypted_buffer
});
return;
}
}
//TODO: query database directly, like preload.
request({
baseUrl: settings.modules.mycard.auth_base_url,
url: '/users/' + encodeURIComponent(client.name) + '.json',
qs: {
api_key: settings.modules.mycard.auth_key,
api_username: client.name,
skip_track_visit: true
},
json: true
}, function(error, response, body) {
var len3, n, ref1;
if (!error && body && body.user) {
users_cache[client.name] = body.user.id;
secret = body.user.id % 65535 + 1;
decrypted_buffer = Buffer.allocUnsafe(6);
ref1 = [0, 2, 4];
for (n = 0, len3 = ref1.length; n < len3; n++) {
i = ref1[n];
decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
}
if (check_buffer_indentity(decrypted_buffer)) {
buffer = decrypted_buffer;
}
} else {
log.warn("READ USER FAIL", client.name, error, body);
done("${load_user_info_fail}");
return;
}
if (!check_buffer_indentity(buffer)) {
done('${invalid_password_checksum}');
return;
}
done(null, {
original: buffer,
decrypted: decrypted_buffer
});
});
} }
}, function(err, data) { if (check_buffer_indentity(decrypted_buffer)) {
if (client.closed) { return create_room_with_action(decrypted_buffer, decrypted_buffer);
return;
} }
if (err) { }
ygopro.stoc_die(client, err); try {
return; userUrl = `${settings.modules.mycard.auth_base_url}/users/${encodeURIComponent(client.name)}.json`;
//console.log(userUrl)
userDataRes = (await axios.get(userUrl, {
responseType: 'json',
timeout: 4000,
params: {
api_key: settings.modules.mycard.auth_key,
api_username: client.name,
skip_track_visit: true
}
}));
userData = userDataRes.data;
} catch (error1) {
//console.log userData
e = error1;
log.warn("READ USER FAIL", client.name, e.toString());
if (!client.closed) {
ygopro.stoc_die(client, '${load_user_info_fail}');
} }
return create_room_with_action(data.get_user.original, data.get_user.decrypted, data.match_permit); return;
}); }
if (client.closed) {
return;
}
users_cache[client.name] = userData.user.id;
secret = userData.user.id % 65535 + 1;
decrypted_buffer = Buffer.allocUnsafe(6);
ref1 = [0, 2, 4];
for (n = 0, len3 = ref1.length; n < len3; n++) {
i = ref1[n];
decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
}
if (check_buffer_indentity(decrypted_buffer)) {
buffer = decrypted_buffer;
}
if (!check_buffer_indentity(buffer)) {
ygopro.stoc_die(client, '${invalid_password_checksum}');
return;
}
return create_room_with_action(buffer, decrypted_buffer);
} else if (settings.modules.challonge.enabled) { } else if (settings.modules.challonge.enabled) {
if (info.version !== settings.version && settings.alternative_versions.includes(info.version)) { if (info.version !== settings.version && settings.alternative_versions.includes(info.version)) {
info.version = settings.version; info.version = settings.version;
...@@ -3316,7 +3310,7 @@ ...@@ -3316,7 +3310,7 @@
}); });
} }
}, async function(err, datas) { }, async function(err, datas) {
var create_room_name, found, k, match, ref, ref1, room, user; var create_room_name, found, k, match, ref2, ref3, room, user;
if (client.closed) { if (client.closed) {
return; return;
} }
...@@ -3326,9 +3320,9 @@ ...@@ -3326,9 +3320,9 @@
return; return;
} }
found = false; found = false;
ref = datas.participant_data; ref2 = datas.participant_data;
for (k in ref) { for (k in ref2) {
user = ref[k]; user = ref2[k];
if (user.participant && user.participant.name && deck_name_match(user.participant.name, client.name)) { if (user.participant && user.participant.name && deck_name_match(user.participant.name, client.name)) {
found = user.participant; found = user.participant;
break; break;
...@@ -3340,9 +3334,9 @@ ...@@ -3340,9 +3334,9 @@
} }
client.challonge_info = found; client.challonge_info = found;
found = false; found = false;
ref1 = datas.match_data; ref3 = datas.match_data;
for (k in ref1) { for (k in ref3) {
match = ref1[k]; match = ref3[k];
if (match && match.match && !match.match.winnerId && match.match.state !== "complete" && match.match.player1Id && match.match.player2Id && (match.match.player1Id === client.challonge_info.id || match.match.player2Id === client.challonge_info.id)) { if (match && match.match && !match.match.winnerId && match.match.state !== "complete" && match.match.player1Id && match.match.player2Id && (match.match.player1Id === client.challonge_info.id || match.match.player2Id === client.challonge_info.id)) {
found = match.match; found = match.match;
break; break;
...@@ -3355,9 +3349,14 @@ ...@@ -3355,9 +3349,14 @@
//if found.winnerId //if found.winnerId
// ygopro.stoc_die(client, '${challonge_match_already_finished}') // ygopro.stoc_die(client, '${challonge_match_already_finished}')
// return // return
create_room_name = 'M#' + found.id; create_room_name = found.id.toString();
if (recover_match) { if (!settings.modules.challonge.no_match_mode) {
create_room_name = recover_match[0] + ',' + create_room_name; create_room_name = 'M#' + create_room_name;
if (recover_match) {
create_room_name = recover_match[0] + ',' + create_room_name;
}
} else if (recover_match) {
create_room_name = recover_match[0] + '#' + create_room_name;
} }
room = (await ROOM_find_or_create_by_name(create_room_name)); room = (await ROOM_find_or_create_by_name(create_room_name));
if (room) { if (room) {
...@@ -3588,7 +3587,7 @@ ...@@ -3588,7 +3587,7 @@
return true; return true;
} else { } else {
room.waiting_for_player = client; room.waiting_for_player = client;
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
} }
} }
//log.info("#{msg_name}等待#{room.waiting_for_player.name}") //log.info("#{msg_name}等待#{room.waiting_for_player.name}")
...@@ -3747,12 +3746,14 @@ ...@@ -3747,12 +3746,14 @@
pos = pos * 2; pos = pos * 2;
} }
val = buffer.readInt32LE(2); val = buffer.readInt32LE(2);
room.dueling_players[pos].lp -= val; if (room.dueling_players[pos]) {
if (room.dueling_players[pos].lp < 0) { room.dueling_players[pos].lp -= val;
room.dueling_players[pos].lp = 0; if (room.dueling_players[pos].lp < 0) {
} room.dueling_players[pos].lp = 0;
if ((0 < (ref1 = room.dueling_players[pos].lp) && ref1 <= 100)) { }
ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK); if ((0 < (ref1 = room.dueling_players[pos].lp) && ref1 <= 100)) {
ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK);
}
} }
} }
if (msg_name === 'RECOVER' && client.pos === 0) { if (msg_name === 'RECOVER' && client.pos === 0) {
...@@ -3764,7 +3765,9 @@ ...@@ -3764,7 +3765,9 @@
pos = pos * 2; pos = pos * 2;
} }
val = buffer.readInt32LE(2); val = buffer.readInt32LE(2);
room.dueling_players[pos].lp += val; if (room.dueling_players[pos]) {
room.dueling_players[pos].lp += val;
}
} }
if (msg_name === 'LPUPDATE' && client.pos === 0) { if (msg_name === 'LPUPDATE' && client.pos === 0) {
pos = buffer.readUInt8(1); pos = buffer.readUInt8(1);
...@@ -3775,7 +3778,9 @@ ...@@ -3775,7 +3778,9 @@
pos = pos * 2; pos = pos * 2;
} }
val = buffer.readInt32LE(2); val = buffer.readInt32LE(2);
room.dueling_players[pos].lp = val; if (room.dueling_players[pos]) {
room.dueling_players[pos].lp = val;
}
} }
if (msg_name === 'PAY_LPCOST' && client.pos === 0) { if (msg_name === 'PAY_LPCOST' && client.pos === 0) {
pos = buffer.readUInt8(1); pos = buffer.readUInt8(1);
...@@ -3786,12 +3791,14 @@ ...@@ -3786,12 +3791,14 @@
pos = pos * 2; pos = pos * 2;
} }
val = buffer.readInt32LE(2); val = buffer.readInt32LE(2);
room.dueling_players[pos].lp -= val; if (room.dueling_players[pos]) {
if (room.dueling_players[pos].lp < 0) { room.dueling_players[pos].lp -= val;
room.dueling_players[pos].lp = 0; if (room.dueling_players[pos].lp < 0) {
} room.dueling_players[pos].lp = 0;
if ((0 < (ref2 = room.dueling_players[pos].lp) && ref2 <= 100)) { }
ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK); if ((0 < (ref2 = room.dueling_players[pos].lp) && ref2 <= 100)) {
ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK);
}
} }
} }
//track card count //track card count
...@@ -4073,9 +4080,11 @@ ...@@ -4073,9 +4080,11 @@
if (room.waiting_for_player !== room.waiting_for_player2) { if (room.waiting_for_player !== room.waiting_for_player2) {
room.waiting_for_player2 = room.waiting_for_player; room.waiting_for_player2 = room.waiting_for_player;
room.waiting_for_player_time = settings.modules.arena_mode.ready_time; room.waiting_for_player_time = settings.modules.arena_mode.ready_time;
room.waiting_for_player_interval = setInterval((function() { if (!room.waiting_for_player_interval) {
wait_room_start_arena(ROOM_all[client.rid]); room.waiting_for_player_interval = setInterval((function() {
}), 1000); wait_room_start_arena(ROOM_all[client.rid]);
}), 1000);
}
} else if (!room.waiting_for_player && room.waiting_for_player_interval) { } else if (!room.waiting_for_player && room.waiting_for_player_interval) {
clearInterval(room.waiting_for_player_interval); clearInterval(room.waiting_for_player_interval);
room.waiting_for_player_interval = null; room.waiting_for_player_interval = null;
...@@ -4144,6 +4153,7 @@ ...@@ -4144,6 +4153,7 @@
wait_room_start = async function(room, time) { wait_room_start = async function(room, time) {
var j, len, player, ref; var j, len, player, ref;
if (room && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.ready_player_count_without_host >= room.max_player - 1) { if (room && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.ready_player_count_without_host >= room.max_player - 1) {
//log.info('wait room start', time)
time -= 1; time -= 1;
if (time) { if (time) {
if (!(time % 5)) { if (!(time % 5)) {
...@@ -4435,7 +4445,7 @@ ...@@ -4435,7 +4445,7 @@
msg = _.trim(info.msg); msg = _.trim(info.msg);
cancel = _.startsWith(msg, "/"); cancel = _.startsWith(msg, "/");
if (!(cancel || !(room.random_type || room.arena) || room.duel_stage === ygopro.constants.DUEL_STAGE.FINGER || room.duel_stage === ygopro.constants.DUEL_STAGE.FIRSTGO || room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING)) { if (!(cancel || !(room.random_type || room.arena) || room.duel_stage === ygopro.constants.DUEL_STAGE.FINGER || room.duel_stage === ygopro.constants.DUEL_STAGE.FIRSTGO || room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING)) {
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
} }
cmd = msg.split(' '); cmd = msg.split(' ');
isVip = (await CLIENT_check_vip(client)); isVip = (await CLIENT_check_vip(client));
...@@ -4453,7 +4463,7 @@ ...@@ -4453,7 +4463,7 @@
ygopro.ctos_send(client.server, 'SURRENDER'); ygopro.ctos_send(client.server, 'SURRENDER');
} else { } else {
sur_player = CLIENT_get_partner(client); sur_player = CLIENT_get_partner(client);
if (sur_player.closed || sur_player.is_local) { if (!sur_player || sur_player.closed || sur_player.is_local) {
sur_player = client; sur_player = client;
} }
if (room.hostinfo.mode === 2 && sur_player !== client) { if (room.hostinfo.mode === 2 && sur_player !== client) {
...@@ -4468,6 +4478,7 @@ ...@@ -4468,6 +4478,7 @@
case '/help': case '/help':
ygopro.stoc_send_chat(client, "${chat_order_main}"); ygopro.stoc_send_chat(client, "${chat_order_main}");
ygopro.stoc_send_chat(client, "${chat_order_help}"); ygopro.stoc_send_chat(client, "${chat_order_help}");
ygopro.stoc_send_chat(client, "${chat_order_refresh}");
if (!settings.modules.mycard.enabled) { if (!settings.modules.mycard.enabled) {
ygopro.stoc_send_chat(client, "${chat_order_roomname}"); ygopro.stoc_send_chat(client, "${chat_order_roomname}");
} }
...@@ -4519,6 +4530,17 @@ ...@@ -4519,6 +4530,17 @@
ygopro.stoc_send_chat(client, "${room_name} " + room.name, ygopro.constants.COLORS.BABYBLUE); ygopro.stoc_send_chat(client, "${room_name} " + room.name, ygopro.constants.COLORS.BABYBLUE);
} }
break; break;
case '/refresh':
if (room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING && client.last_game_msg && client.last_game_msg_title !== 'WAITING') {
if (client.last_hint_msg) {
ygopro.stoc_send(client, 'GAME_MSG', client.last_hint_msg);
}
ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg);
ygopro.stoc_send_chat(client, '${refresh_success}', ygopro.constants.COLORS.BABYBLUE);
} else {
ygopro.stoc_send_chat(client, '${refresh_fail}', ygopro.constants.COLORS.RED);
}
break;
case '/color': case '/color':
if (settings.modules.chat_color.enabled) { if (settings.modules.chat_color.enabled) {
cip = CLIENT_get_authorize_key(client); cip = CLIENT_get_authorize_key(client);
...@@ -4661,7 +4683,7 @@ ...@@ -4661,7 +4683,7 @@
ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED); ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
cancel = true; cancel = true;
} }
if (!(room && (room.random_type || room.arena))) { if (!(room && (room.random_type || room.arena)) && !settings.modules.mycard.enabled) {
if (!cancel && settings.modules.display_watchers && client.is_post_watcher) { if (!cancel && settings.modules.display_watchers && client.is_post_watcher) {
ygopro.stoc_send_chat_to_room(room, `${client.name}: ${msg}`, 9); ygopro.stoc_send_chat_to_room(room, `${client.name}: ${msg}`, 9);
return true; return true;
...@@ -4739,7 +4761,7 @@ ...@@ -4739,7 +4761,7 @@
}); });
ygopro.ctos_follow('UPDATE_DECK', true, async function(buffer, info, client, server, datas) { ygopro.ctos_follow('UPDATE_DECK', true, async function(buffer, info, client, server, datas) {
var buff_main, buff_side, card, current_deck, deck, deck_array, deck_main, deck_side, deck_text, deckbuf, decks, found_deck, i, j, l, len, len1, line, oppo_pos, recover_player_data, recoveredDeck, room, struct, win_pos; var athleticCheckResult, buff_main, buff_side, card, current_deck, deck, deck_array, deck_main, deck_side, deck_text, deckbuf, decks, found_deck, i, j, l, len, len1, line, oppo_pos, recover_player_data, recoveredDeck, room, struct, win_pos;
if (settings.modules.reconnect.enabled && client.pre_reconnecting) { if (settings.modules.reconnect.enabled && client.pre_reconnecting) {
if (!CLIENT_is_able_to_reconnect(client) && !CLIENT_is_able_to_kick_reconnect(client)) { if (!CLIENT_is_able_to_reconnect(client) && !CLIENT_is_able_to_kick_reconnect(client)) {
ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED); ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED);
...@@ -4815,7 +4837,7 @@ ...@@ -4815,7 +4837,7 @@
if (client.pos === 0) { if (client.pos === 0) {
room.waiting_for_player = room.waiting_for_player2; room.waiting_for_player = room.waiting_for_player2;
} }
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
} }
if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.recovering) { if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.recovering) {
recover_player_data = _.find(room.recover_duel_log.players, function(player) { recover_player_data = _.find(room.recover_duel_log.players, function(player) {
...@@ -4834,54 +4856,76 @@ ...@@ -4834,54 +4856,76 @@
struct.set("sidec", 1); struct.set("sidec", 1);
struct.set("deckbuf", [4392470, 4392470]); struct.set("deckbuf", [4392470, 4392470]);
ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED); ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED);
return false;
} }
} else if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.deck_check) { } else {
decks = (await fs.promises.readdir(settings.modules.tournament_mode.deck_path)); if (room.arena && settings.modules.athletic_check.enabled && settings.modules.athletic_check.banCount) {
if (decks.length) { athleticCheckResult = (await athleticChecker.checkAthletic({
struct.set("mainc", 1); main: buff_main,
struct.set("sidec", 1); side: buff_side
struct.set("deckbuf", [4392470, 4392470]); }));
buffer = struct.buffer; if (athleticCheckResult.success) {
found_deck = false; if (athleticCheckResult.athletic && athleticCheckResult.athletic <= settings.modules.athletic_check.banCount) {
for (j = 0, len = decks.length; j < len; j++) { struct.set("mainc", 1);
deck = decks[j]; struct.set("sidec", 1);
if (deck_name_match(deck, client.name)) { struct.set("deckbuf", [4392470, 4392470]);
found_deck = deck; ygopro.stoc_send_chat(client, `\${banned_athletic_deck_part1}${settings.modules.athletic_check.banCount}\${banned_athletic_deck_part2}`, ygopro.constants.COLORS.RED);
return false;
} }
} } else {
if (found_deck) { log.warn("GET ATHLETIC FAIL", client.name, athleticCheckResult.message);
deck_text = (await fs.promises.readFile(settings.modules.tournament_mode.deck_path + found_deck, { }
encoding: "ASCII" }
})); if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.deck_check) {
deck_array = deck_text.split("\n"); decks = (await fs.promises.readdir(settings.modules.tournament_mode.deck_path));
deck_main = []; if (decks.length) {
deck_side = []; struct.set("mainc", 1);
current_deck = deck_main; struct.set("sidec", 1);
for (l = 0, len1 = deck_array.length; l < len1; l++) { struct.set("deckbuf", [4392470, 4392470]);
line = deck_array[l]; buffer = struct.buffer;
if (line.indexOf("!side") >= 0) { found_deck = false;
current_deck = deck_side; for (j = 0, len = decks.length; j < len; j++) {
} deck = decks[j];
card = parseInt(line); if (deck_name_match(deck, client.name)) {
if (!isNaN(card)) { found_deck = deck;
current_deck.push(card);
} }
} }
if (_.isEqual(buff_main, deck_main) && _.isEqual(buff_side, deck_side)) { if (found_deck) {
deckbuf = deck_main.concat(deck_side); deck_text = (await fs.promises.readFile(settings.modules.tournament_mode.deck_path + found_deck, {
struct.set("mainc", deck_main.length); encoding: "ASCII"
struct.set("sidec", deck_side.length); }));
struct.set("deckbuf", deckbuf); deck_array = deck_text.split("\n");
buffer = struct.buffer; deck_main = [];
//log.info("deck ok: " + client.name) deck_side = [];
ygopro.stoc_send_chat(client, `\${deck_correct_part1} ${found_deck} \${deck_correct_part2}`, ygopro.constants.COLORS.BABYBLUE); current_deck = deck_main;
for (l = 0, len1 = deck_array.length; l < len1; l++) {
line = deck_array[l];
if (line.indexOf("!side") >= 0) {
current_deck = deck_side;
}
card = parseInt(line);
if (!isNaN(card)) {
current_deck.push(card);
}
}
if (_.isEqual(buff_main, deck_main) && _.isEqual(buff_side, deck_side)) {
deckbuf = deck_main.concat(deck_side);
struct.set("mainc", deck_main.length);
struct.set("sidec", deck_side.length);
struct.set("deckbuf", deckbuf);
buffer = struct.buffer;
//log.info("deck ok: " + client.name)
ygopro.stoc_send_chat(client, `\${deck_correct_part1} ${found_deck} \${deck_correct_part2}`, ygopro.constants.COLORS.BABYBLUE);
} else {
//log.info("bad deck: " + client.name + " / " + buff_main + " / " + buff_side)
ygopro.stoc_send_chat(client, `\${deck_incorrect_part1} ${found_deck} \${deck_incorrect_part2}`, ygopro.constants.COLORS.RED);
return false;
}
} else { } else {
//log.info("bad deck: " + client.name + " / " + buff_main + " / " + buff_side) //log.info("player deck not found: " + client.name)
ygopro.stoc_send_chat(client, `\${deck_incorrect_part1} ${found_deck} \${deck_incorrect_part2}`, ygopro.constants.COLORS.RED); ygopro.stoc_send_chat(client, `${client.name}\${deck_not_found}`, ygopro.constants.COLORS.RED);
return false;
} }
} else {
//log.info("player deck not found: " + client.name)
ygopro.stoc_send_chat(client, `${client.name}\${deck_not_found}`, ygopro.constants.COLORS.RED);
} }
} }
} }
...@@ -4894,7 +4938,7 @@ ...@@ -4894,7 +4938,7 @@
if (!(room && (room.random_type || room.arena))) { if (!(room && (room.random_type || room.arena))) {
return; return;
} }
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
}); });
ygopro.stoc_follow('TIME_LIMIT', true, async function(buffer, info, client, server, datas) { ygopro.stoc_follow('TIME_LIMIT', true, async function(buffer, info, client, server, datas) {
...@@ -4993,7 +5037,7 @@ ...@@ -4993,7 +5037,7 @@
if (client.pos === 0) { if (client.pos === 0) {
room.waiting_for_player = room.waiting_for_player2; room.waiting_for_player = room.waiting_for_player2;
} }
room.last_active_time = moment_long_ago_string; room.refreshLastActiveTime(true);
} }
}); });
...@@ -5008,7 +5052,7 @@ ...@@ -5008,7 +5052,7 @@
if (!(room.random_type || room.arena)) { if (!(room.random_type || room.arena)) {
return; return;
} }
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
}); });
ygopro.stoc_follow('CHAT', true, async function(buffer, info, client, server, datas) { ygopro.stoc_follow('CHAT', true, async function(buffer, info, client, server, datas) {
...@@ -5065,7 +5109,7 @@ ...@@ -5065,7 +5109,7 @@
} else { } else {
room.waiting_for_player2 = client; room.waiting_for_player2 = client;
} }
room.last_active_time = moment_long_ago_string; room.refreshLastActiveTime(true);
} }
if (room.determine_firstgo) { if (room.determine_firstgo) {
ygopro.ctos_send(server, "HAND_RESULT", { ygopro.ctos_send(server, "HAND_RESULT", {
...@@ -5096,7 +5140,7 @@ ...@@ -5096,7 +5140,7 @@
room.duel_stage = ygopro.constants.DUEL_STAGE.FIRSTGO; room.duel_stage = ygopro.constants.DUEL_STAGE.FIRSTGO;
if (room.random_type || room.arena) { if (room.random_type || room.arena) {
room.waiting_for_player = client; room.waiting_for_player = client;
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
} }
if (room.determine_firstgo) { if (room.determine_firstgo) {
ygopro.ctos_send(server, "TP_RESULT", { ygopro.ctos_send(server, "TP_RESULT", {
...@@ -5165,7 +5209,7 @@ ...@@ -5165,7 +5209,7 @@
} else { } else {
room.waiting_for_player2 = client; room.waiting_for_player2 = client;
} }
room.last_active_time = moment_now_string; room.refreshLastActiveTime();
} }
}); });
......
...@@ -113,4 +113,4 @@ translateHandler = (handler) -> ...@@ -113,4 +113,4 @@ translateHandler = (handler) ->
if client if client
client.system_kicked = true client.system_kicked = true
client.destroy() client.destroy()
return return '_cancel'
...@@ -185,6 +185,7 @@ ...@@ -185,6 +185,7 @@
client.system_kicked = true; client.system_kicked = true;
client.destroy(); client.destroy();
} }
return '_cancel';
}; };
}).call(this); }).call(this);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment