Commit 295bab2e authored by nanahira's avatar nanahira

Merge remote-tracking branch 'origin/msg-encode'

# Conflicts:
#	package-lock.json
#	package.json
parents 9de7c60b ab9e3c3d
......@@ -37,3 +37,4 @@ ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
.DS_Store
/scripts
......@@ -3,17 +3,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.YGOProMessagesHelper = void 0;
const struct_1 = require("./struct");
exports.YGOProMessagesHelper = exports.LegacyStruct = exports.LegacyStructInst = void 0;
const underscore_1 = __importDefault(require("underscore"));
const structs_json_1 = __importDefault(require("./data/structs.json"));
const typedefs_json_1 = __importDefault(require("./data/typedefs.json"));
const load_constants_1 = __importDefault(require("./load-constants"));
const ygopro_msg_encode_1 = require("ygopro-msg-encode");
const ygopro_msg_struct_compat_1 = require("./ygopro-msg-struct-compat");
const proto_structs_json_1 = __importDefault(require("./data/proto_structs.json"));
const constants_json_1 = __importDefault(require("./data/constants.json"));
const utility_1 = require("./utility");
class Handler {
constructor(handler, synchronous) {
this.handler = handler;
this.synchronous = synchronous || false;
this.synchronous = synchronous;
}
async handle(buffer, info, datas, params) {
if (this.synchronous) {
......@@ -27,8 +27,42 @@ class Handler {
}
}
}
class LegacyStructInst {
constructor(cls) {
this.cls = cls;
}
_setBuff(buff) {
this.buffer = buff;
}
set(field, value) {
if (!this.buffer || !this.cls)
return;
const inst = (0, ygopro_msg_struct_compat_1.applyYGOProMsgStructCompat)(new this.cls().fromPayload(this.buffer));
inst[field] = value;
(0, utility_1.overwriteBuffer)(this.buffer, inst.toPayload());
}
}
exports.LegacyStructInst = LegacyStructInst;
class LegacyStruct {
constructor(helper) {
this.helper = helper;
this.protoClasses = new Map();
for (const [direction, list] of Object.entries(proto_structs_json_1.default)) {
for (const [protoStr, structName] of Object.entries(list)) {
if (!structName)
continue;
this.protoClasses.set(structName, this.helper.getProtoClass(protoStr, direction));
}
}
}
get(structName) {
return new LegacyStructInst(this.protoClasses.get(structName));
}
}
exports.LegacyStruct = LegacyStruct;
class YGOProMessagesHelper {
constructor(singleHandleLimit) {
constructor(singleHandleLimit = 1000) {
this.singleHandleLimit = singleHandleLimit;
this.handlers = {
STOC: [new Map(),
new Map(),
......@@ -43,56 +77,8 @@ class YGOProMessagesHelper {
new Map(),
]
};
this.initDatas();
this.initStructs();
if (singleHandleLimit) {
this.singleHandleLimit = singleHandleLimit;
}
else {
this.singleHandleLimit = 1000;
}
}
initDatas() {
this.structs_declaration = structs_json_1.default;
this.typedefs = typedefs_json_1.default;
this.proto_structs = proto_structs_json_1.default;
this.constants = constants_json_1.default;
}
initStructs() {
this.structs = new Map();
for (let name in this.structs_declaration) {
const declaration = this.structs_declaration[name];
let result = (0, struct_1.Struct)();
for (let field of declaration) {
if (field.encoding) {
switch (field.encoding) {
case "UTF-16LE":
result.chars(field.name, field.length * 2, field.encoding);
break;
default:
throw `unsupported encoding: ${field.encoding}`;
}
}
else {
let type = field.type;
if (this.typedefs[type]) {
type = this.typedefs[type];
}
if (field.length) {
result.array(field.name, field.length, type); //不支持结构体
}
else {
if (this.structs.has(type)) {
result.struct(field.name, this.structs.get(type));
}
else {
result[type](field.name);
}
}
}
}
this.structs.set(name, result);
}
this.constants = (0, load_constants_1.default)();
this.structs = new LegacyStruct(this);
}
getDirectionAndProto(protoStr) {
const protoStrMatch = protoStr.match(/^(STOC|CTOS)_([_A-Z]+)$/);
......@@ -117,11 +103,27 @@ class YGOProMessagesHelper {
}
return parseInt(translatedProto);
}
getProtoClass(proto, direction) {
const identifier = typeof proto === 'number' ? proto : this.translateProto(proto, direction);
const registry = direction === 'CTOS' ? ygopro_msg_encode_1.YGOProCtos : direction === 'STOC' ? ygopro_msg_encode_1.YGOProStoc : null;
if (!registry) {
throw `Invalid direction: ${direction}`;
}
return registry.get(identifier);
}
classToProtoStr(cls) {
const registry = cls.prototype instanceof ygopro_msg_encode_1.YGOProCtosBase ? ygopro_msg_encode_1.YGOProCtos : cls.prototype instanceof ygopro_msg_encode_1.YGOProStocBase ? ygopro_msg_encode_1.YGOProStoc : null;
if (!registry) {
throw `Invalid class: ${cls.name}`;
}
const identifier = cls.identifier;
const direction = cls.prototype instanceof ygopro_msg_encode_1.YGOProCtosBase ? 'CTOS' : 'STOC';
return `${direction}_${this.constants[direction][identifier]}`;
}
prepareMessage(protostr, info) {
const { direction, proto } = this.getDirectionAndProto(protostr);
const translatedProto = this.translateProto(proto, direction);
let buffer;
//console.log(proto, this.proto_structs[direction][proto]);
//const directionProtoList = this.constants[direction];
if (typeof info === 'undefined') {
buffer = null;
}
......@@ -129,12 +131,12 @@ class YGOProMessagesHelper {
buffer = info;
}
else {
let struct = this.structs.get(this.proto_structs[direction][proto]);
struct.allocate();
struct.set(info);
buffer = struct.buffer();
const protoCls = this.getProtoClass(translatedProto, direction);
if (!protoCls) {
throw `No proto class for ${protostr}`;
}
buffer = Buffer.from((0, ygopro_msg_struct_compat_1.fromPartialCompat)(protoCls, info).toPayload());
}
const translatedProto = this.translateProto(proto, direction);
let sendBuffer = Buffer.allocUnsafe(3 + (buffer ? buffer.length : 0));
if (buffer) {
sendBuffer.writeUInt16LE(buffer.length + 1, 0);
......@@ -231,13 +233,11 @@ class YGOProMessagesHelper {
}
const handlerCollection = this.handlers[direction][priority];
if (proto && handlerCollection.has(bufferProto)) {
let struct = this.structs.get(this.proto_structs[direction][proto]);
for (const handler of handlerCollection.get(bufferProto)) {
let info = null;
if (struct) {
struct._setBuff(buffer);
info = underscore_1.default.clone(struct.fields);
}
const protoCls = this.getProtoClass(bufferProto, direction);
const info = protoCls
? (0, ygopro_msg_struct_compat_1.applyYGOProMsgStructCompat)(new protoCls().fromPayload(buffer))
: null;
cancel = await handler.handle(buffer, info, datas, params);
if (cancel) {
if (Buffer.isBuffer(cancel)) {
......
import { Struct } from "./struct";
import _ from "underscore";
import structs_declaration from "./data/structs.json";
import typedefs from "./data/typedefs.json";
import proto_structs from "./data/proto_structs.json";
import constants from "./data/constants.json";
import loadConstants from "./load-constants";
import net from "net";
import { YGOProCtos, YGOProCtosBase, YGOProStoc, YGOProStocBase } from "ygopro-msg-encode";
import { applyYGOProMsgStructCompat, fromPartialCompat } from "./ygopro-msg-struct-compat";
import legacyProtoStructs from "./data/proto_structs.json";
import { overwriteBuffer } from "./utility";
class Handler {
private handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string | Buffer>;
synchronous: boolean;
constructor(handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string | Buffer>, synchronous: boolean) {
this.handler = handler;
this.synchronous = synchronous || false;
}
async handle(buffer: Buffer, info: any, datas: Buffer[], params: any): Promise<boolean | string | Buffer> {
constructor(
private handler: (buffer: Buffer, info: YGOProStocBase | YGOProCtosBase, datas: Buffer[], params: any) => Promise<boolean | string | Buffer>,
public synchronous: boolean
) {}
async handle(buffer: Buffer, info: YGOProStocBase | YGOProCtosBase, datas: Buffer[], params: any): Promise<boolean | string | Buffer> {
if (this.synchronous) {
return await this.handler(buffer, info, datas, params);
} else {
......@@ -31,12 +29,21 @@ interface HandlerList {
CTOS: Map<number, Handler[]>[];
}
interface DirectionBase {
STOC: typeof YGOProStocBase;
CTOS: typeof YGOProCtosBase;
}
type DirectionToBase<T>
= T extends `${infer K extends keyof DirectionBase}_${string}` ? DirectionBase[K] : DirectionBase[keyof DirectionBase];
interface DirectionAndProto {
direction: string;
direction: keyof HandlerList;
proto: string;
}
export interface Feedback{
export interface Feedback {
type: string;
message: string;
}
......@@ -64,18 +71,41 @@ export interface Constants {
MSG: Record<string, string>;
}
export class YGOProMessagesHelper {
export class LegacyStructInst {
buffer: Buffer;
constructor(private cls?: typeof YGOProCtosBase | typeof YGOProStocBase) {}
_setBuff(buff: Buffer) {
this.buffer = buff;
}
set(field: string, value: any) {
if (!this.buffer || !this.cls) return;
const inst = applyYGOProMsgStructCompat(new this.cls().fromPayload(this.buffer));
inst[field] = value;
overwriteBuffer(this.buffer, inst.toPayload());
}
}
export class LegacyStruct {
private protoClasses = new Map<string, typeof YGOProCtosBase | typeof YGOProStocBase>();
constructor(private helper: YGOProMessagesHelper) {
for (const [direction, list] of Object.entries(legacyProtoStructs)) {
for (const [protoStr, structName] of Object.entries(list)) {
if(!structName) continue;
this.protoClasses.set(structName, this.helper.getProtoClass(protoStr, direction as keyof HandlerList));
}
}
}
get(structName: string) {
return new LegacyStructInst(this.protoClasses.get(structName));
}
}
handlers: HandlerList;
structs: Map<string, Struct>;
structs_declaration: Record<string, Struct>;
typedefs: Record<string, string>;
proto_structs: Record<'CTOS' | 'STOC', Record<string, string>>;
constants: Constants;
singleHandleLimit: number;
export class YGOProMessagesHelper {
constructor(singleHandleLimit?: number) {
this.handlers = {
handlers: HandlerList = {
STOC: [new Map(),
new Map(),
new Map(),
......@@ -88,56 +118,12 @@ export class YGOProMessagesHelper {
new Map(),
new Map(),
]
}
this.initDatas();
this.initStructs();
if (singleHandleLimit) {
this.singleHandleLimit = singleHandleLimit;
} else {
this.singleHandleLimit = 1000;
}
}
};
constants = loadConstants();
initDatas() {
this.structs_declaration = structs_declaration;
this.typedefs = typedefs;
this.proto_structs = proto_structs;
this.constants = constants;
}
constructor(public singleHandleLimit = 1000) {}
initStructs() {
this.structs = new Map();
for (let name in this.structs_declaration) {
const declaration = this.structs_declaration[name];
let result = Struct();
for (let field of declaration) {
if (field.encoding) {
switch (field.encoding) {
case "UTF-16LE":
result.chars(field.name, field.length * 2, field.encoding);
break;
default:
throw `unsupported encoding: ${field.encoding}`;
}
} else {
let type = field.type;
if (this.typedefs[type]) {
type = this.typedefs[type];
}
if (field.length) {
result.array(field.name, field.length, type); //不支持结构体
} else {
if (this.structs.has(type)) {
result.struct(field.name, this.structs.get(type));
} else {
result[type](field.name);
}
}
}
}
this.structs.set(name, result);
}
}
structs = new LegacyStruct(this);
getDirectionAndProto(protoStr: string): DirectionAndProto {
const protoStrMatch = protoStr.match(/^(STOC|CTOS)_([_A-Z]+)$/);
......@@ -145,13 +131,12 @@ export class YGOProMessagesHelper {
throw `Invalid proto string: ${protoStr}`
}
return {
direction: protoStrMatch[1].toUpperCase(),
direction: protoStrMatch[1].toUpperCase() as keyof HandlerList,
proto: protoStrMatch[2].toUpperCase()
}
}
translateProto(proto: string | number, direction: string): number {
translateProto(proto: string | number, direction: keyof HandlerList): number {
const directionProtoList = this.constants[direction];
if (typeof proto !== "string") {
return proto;
......@@ -165,25 +150,43 @@ export class YGOProMessagesHelper {
return parseInt(translatedProto);
}
getProtoClass<T extends string | number>(proto: T, direction: keyof HandlerList): DirectionToBase<T> {
const identifier = typeof proto === 'number' ? proto : this.translateProto(proto, direction);
const registry = direction === 'CTOS' ? YGOProCtos : direction === 'STOC' ? YGOProStoc : null;
if (!registry) {
throw `Invalid direction: ${direction}`;
}
return registry.get(identifier) as DirectionToBase<T>;
}
classToProtoStr(cls: typeof YGOProCtosBase | typeof YGOProStocBase): string {
const registry = cls.prototype instanceof YGOProCtosBase ? YGOProCtos : cls.prototype instanceof YGOProStocBase ? YGOProStoc : null;
if (!registry) {
throw `Invalid class: ${cls.name}`;
}
const identifier = cls.identifier;
const direction = cls.prototype instanceof YGOProCtosBase ? 'CTOS' : 'STOC';
return `${direction}_${this.constants[direction][identifier]}`;
}
prepareMessage(protostr: string, info?: string | Buffer | any): Buffer {
const {
direction,
proto
} = this.getDirectionAndProto(protostr);
const translatedProto = this.translateProto(proto, direction);
let buffer: Buffer;
//console.log(proto, this.proto_structs[direction][proto]);
//const directionProtoList = this.constants[direction];
if (typeof info === 'undefined') {
buffer = null;
} else if (Buffer.isBuffer(info)) {
buffer = info;
} else {
let struct = this.structs.get(this.proto_structs[direction][proto]);
struct.allocate();
struct.set(info);
buffer = struct.buffer();
const protoCls = this.getProtoClass(translatedProto, direction);
if (!protoCls) {
throw `No proto class for ${protostr}`;
}
buffer = Buffer.from(fromPartialCompat(protoCls, info).toPayload());
}
const translatedProto = this.translateProto(proto, direction);
let sendBuffer = Buffer.allocUnsafe(3 + (buffer ? buffer.length : 0));
if (buffer) {
sendBuffer.writeUInt16LE(buffer.length + 1, 0);
......@@ -214,7 +217,7 @@ export class YGOProMessagesHelper {
return this.send(socket, sendBuffer);
}
addHandler(protostr: string, handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean | string>, synchronous: boolean, priority: number) {
addHandler<T extends string>(protostr: T, handler: (buffer: Buffer, info: InstanceType<DirectionToBase<T>>, datas: Buffer[], params: any) => Promise<boolean | string>, synchronous: boolean, priority: number) {
if (priority < 0 || priority > 4) {
throw "Invalid priority: " + priority;
}
......@@ -232,7 +235,7 @@ export class YGOProMessagesHelper {
handlerCollection.get(translatedProto).push(handlerObj);
}
async handleBuffer(messageBuffer: Buffer, direction: string, protoFilter?: string[], params?: any, preconnect = false): Promise<HandleResult> {
async handleBuffer(messageBuffer: Buffer, direction: keyof HandlerList, protoFilter?: string[], params?: any, preconnect = false): Promise<HandleResult> {
let feedback: Feedback = null;
let messageLength = 0;
let bufferProto = 0;
......@@ -281,13 +284,11 @@ export class YGOProMessagesHelper {
}
const handlerCollection: Map<number, Handler[]> = this.handlers[direction][priority];
if (proto && handlerCollection.has(bufferProto)) {
let struct = this.structs.get(this.proto_structs[direction][proto]);
for (const handler of handlerCollection.get(bufferProto)) {
let info = null;
if (struct) {
struct._setBuff(buffer);
info = _.clone(struct.fields);
}
const protoCls = this.getProtoClass(bufferProto, direction);
const info = protoCls
? applyYGOProMsgStructCompat(new protoCls().fromPayload(buffer))
: null;
cancel = await handler.handle(buffer, info, datas, params);
if (cancel) {
if (Buffer.isBuffer(cancel)) {
......
......@@ -12,52 +12,6 @@
"5": "TYPE_PLAYER6",
"7": "TYPE_OBSERVER"
},
"CTOS": {
"1": "RESPONSE",
"2": "UPDATE_DECK",
"3": "HAND_RESULT",
"4": "TP_RESULT",
"16": "PLAYER_INFO",
"17": "CREATE_GAME",
"18": "JOIN_GAME",
"19": "LEAVE_GAME",
"20": "SURRENDER",
"21": "TIME_CONFIRM",
"22": "CHAT",
"23": "EXTERNAL_ADDRESS",
"32": "HS_TODUELIST",
"33": "HS_TOOBSERVER",
"34": "HS_READY",
"35": "HS_NOTREADY",
"36": "HS_KICK",
"37": "HS_START",
"48": "REQUEST_FIELD"
},
"STOC": {
"1": "GAME_MSG",
"2": "ERROR_MSG",
"3": "SELECT_HAND",
"4": "SELECT_TP",
"5": "HAND_RESULT",
"6": "TP_RESULT",
"7": "CHANGE_SIDE",
"8": "WAITING_SIDE",
"9": "DECK_COUNT",
"17": "CREATE_GAME",
"18": "JOIN_GAME",
"19": "TYPE_CHANGE",
"20": "LEAVE_GAME",
"21": "DUEL_START",
"22": "DUEL_END",
"23": "REPLAY",
"24": "TIME_LIMIT",
"25": "CHAT",
"32": "HS_PLAYER_ENTER",
"33": "HS_PLAYER_CHANGE",
"34": "HS_WATCH_CHANGE",
"35": "TEAMMATE_SURRENDER",
"48": "FIELD_FINISH"
},
"PLAYERCHANGE":{
"8": "OBSERVE",
"9": "READY",
......@@ -75,203 +29,6 @@
"1": "MATCH",
"2": "TAG"
},
"MSG": {
"1": "RETRY",
"2": "HINT",
"3": "WAITING",
"4": "START",
"5": "WIN",
"6": "UPDATE_DATA",
"7": "UPDATE_CARD",
"8": "REQUEST_DECK",
"10": "SELECT_BATTLECMD",
"11": "SELECT_IDLECMD",
"12": "SELECT_EFFECTYN",
"13": "SELECT_YESNO",
"14": "SELECT_OPTION",
"15": "SELECT_CARD",
"16": "SELECT_CHAIN",
"18": "SELECT_PLACE",
"19": "SELECT_POSITION",
"20": "SELECT_TRIBUTE",
"21": "SORT_CHAIN",
"22": "SELECT_COUNTER",
"23": "SELECT_SUM",
"24": "SELECT_DISFIELD",
"25": "SORT_CARD",
"26": "SELECT_UNSELECT_CARD",
"30": "CONFIRM_DECKTOP",
"31": "CONFIRM_CARDS",
"32": "SHUFFLE_DECK",
"33": "SHUFFLE_HAND",
"34": "REFRESH_DECK",
"35": "SWAP_GRAVE_DECK",
"36": "SHUFFLE_SET_CARD",
"37": "REVERSE_DECK",
"38": "DECK_TOP",
"39": "MSG_SHUFFLE_EXTRA",
"40": "NEW_TURN",
"41": "NEW_PHASE",
"42": "CONFIRM_EXTRATOP",
"50": "MOVE",
"53": "POS_CHANGE",
"54": "SET",
"55": "SWAP",
"56": "FIELD_DISABLED",
"60": "SUMMONING",
"61": "SUMMONED",
"62": "SPSUMMONING",
"63": "SPSUMMONED",
"64": "FLIPSUMMONING",
"65": "FLIPSUMMONED",
"70": "CHAINING",
"71": "CHAINED",
"72": "CHAIN_SOLVING",
"73": "CHAIN_SOLVED",
"74": "CHAIN_END",
"75": "CHAIN_NEGATED",
"76": "CHAIN_DISABLED",
"80": "CARD_SELECTED",
"81": "RANDOM_SELECTED",
"83": "BECOME_TARGET",
"90": "DRAW",
"91": "DAMAGE",
"92": "RECOVER",
"93": "EQUIP",
"94": "LPUPDATE",
"95": "UNEQUIP",
"96": "CARD_TARGET",
"97": "CANCEL_TARGET",
"100": "PAY_LPCOST",
"101": "ADD_COUNTER",
"102": "REMOVE_COUNTER",
"110": "ATTACK",
"111": "BATTLE",
"112": "ATTACK_DISABLED",
"113": "DAMAGE_STEP_START",
"114": "DAMAGE_STEP_END",
"120": "MISSED_EFFECT",
"121": "BE_CHAIN_TARGET",
"122": "CREATE_RELATION",
"123": "RELEASE_RELATION",
"130": "TOSS_COIN",
"131": "TOSS_DICE",
"132": "ROCK_PAPER_SCISSORS",
"133": "HAND_RES",
"140": "ANNOUNCE_RACE",
"141": "ANNOUNCE_ATTRIB",
"142": "ANNOUNCE_CARD",
"143": "ANNOUNCE_NUMBER",
"160": "CARD_HINT",
"161": "TAG_SWAP",
"162": "RELOAD_FIELD",
"163": "AI_NAME",
"164": "SHOW_HINT",
"170": "MATCH_KILL",
"180": "CUSTOM_MSG"
},
"TIMING":{
"1": "DRAW_PHASE",
"2": "STANDBY_PHASE",
"4": "MAIN_END",
"8": "BATTLE_START",
"16": "BATTLE_END",
"32": "END_PHASE",
"64": "SUMMON",
"128": "SPSUMMON",
"256": "FLIPSUMMON",
"512": "MSET",
"1024": "SSET",
"2048": "POS_CHANGE",
"4096": "ATTACK",
"8192": "DAMAGE_STEP",
"16384": "DAMAGE_CAL",
"32768": "CHAIN_END",
"65536": "DRAW",
"131072": "DAMAGE",
"262144": "RECOVER",
"524288": "DESTROY",
"1048576": "REMOVE",
"2097152": "TOHAND",
"4194304": "TODECK",
"8388608": "TOGRAVE",
"16777216": "BATTLE_PHASE",
"33554432": "EQUIP"
},
"TYPES": {
"TYPE_MONSTER": 1,
"TYPE_SPELL": 2,
"TYPE_TRAP": 4,
"TYPE_NORMAL": 16,
"TYPE_EFFECT": 32,
"TYPE_FUSION": 64,
"TYPE_RITUAL": 128,
"TYPE_TRAPMONSTER": 256,
"TYPE_SPIRIT": 512,
"TYPE_UNION": 1024,
"TYPE_DUAL": 2048,
"TYPE_TUNER": 4096,
"TYPE_SYNCHRO": 8192,
"TYPE_TOKEN": 16384,
"TYPE_QUICKPLAY": 65536,
"TYPE_CONTINUOUS": 131072,
"TYPE_EQUIP": 262144,
"TYPE_FIELD": 524288,
"TYPE_COUNTER": 1048576,
"TYPE_FLIP": 2097152,
"TYPE_TOON": 4194304,
"TYPE_XYZ": 8388608,
"TYPE_PENDULUM": 16777216,
"TYPE_SPSUMMON": 33554432,
"TYPE_LINK": 67108864
},
"RACES": {
"RACE_WARRIOR": 1,
"RACE_SPELLCASTER": 2,
"RACE_FAIRY": 4,
"RACE_FIEND": 8,
"RACE_ZOMBIE": 16,
"RACE_MACHINE": 32,
"RACE_AQUA": 64,
"RACE_PYRO": 128,
"RACE_ROCK": 256,
"RACE_WINDBEAST": 512,
"RACE_PLANT": 1024,
"RACE_INSECT": 2048,
"RACE_THUNDER": 4096,
"RACE_DRAGON": 8192,
"RACE_BEAST": 16384,
"RACE_BEASTWARRIOR": 32768,
"RACE_DINOSAUR": 65536,
"RACE_FISH": 131072,
"RACE_SEASERPENT": 262144,
"RACE_REPTILE": 524288,
"RACE_PSYCHO": 1048576,
"RACE_DEVINE": 2097152,
"RACE_CREATORGOD": 4194304,
"RACE_WYRM": 8388608,
"RACE_CYBERS": 16777216,
"RACE_ILLUSION": 33554432
},
"ATTRIBUTES": {
"ATTRIBUTE_EARTH": 1,
"ATTRIBUTE_WATER": 2,
"ATTRIBUTE_FIRE": 4,
"ATTRIBUTE_WIND": 8,
"ATTRIBUTE_LIGHT": 16,
"ATTRIBUTE_DARK": 32,
"ATTRIBUTE_DEVINE": 64
},
"LINK_MARKERS": {
"LINK_MARKER_BOTTOM_LEFT": 1,
"LINK_MARKER_BOTTOM": 2,
"LINK_MARKER_BOTTOM_RIGHT": 4,
"LINK_MARKER_LEFT": 8,
"LINK_MARKER_RIGHT": 32,
"LINK_MARKER_TOP_LEFT": 64,
"LINK_MARKER_TOP": 128,
"LINK_MARKER_TOP_RIGHT": 256
},
"DUEL_STAGE": {
"BEGIN": 0,
"FINGER": 1,
......
{
"HostInfo": [
{"name": "lflist", "type": "unsigned int"},
{"name": "rule", "type": "unsigned char"},
{"name": "mode", "type": "unsigned char"},
{"name": "duel_rule", "type": "unsigned char"},
{"name": "no_check_deck", "type": "bool"},
{"name": "no_shuffle_deck", "type": "bool"},
{"name": "start_lp", "type": "unsigned int"},
{"name": "start_hand", "type": "unsigned char"},
{"name": "draw_count", "type": "unsigned char"},
{"name": "time_limit", "type": "unsigned short"}
],
"HostPacket": [
{"name": "identifier", "type": "unsigned short"},
{"name": "version", "type": "unsigned short"},
{"name": "port", "type": "unsigned short"},
{"name": "ipaddr", "type": "unsigned int"},
{"name": "name", "type": "unsigned short", "length": 20, "encoding": "UTF-16LE"},
{"name": "host", "type": "HostInfo"}
],
"HostRequest": [
{"name": "identifier", "type": "unsigned short"}
],
"CTOS_HandResult": [
{"name": "res", "type": "unsigned char"}
],
"CTOS_TPResult": [
{"name": "res", "type": "unsigned char"}
],
"CTOS_PlayerInfo": [
{"name": "name", "type": "unsigned short", "length": 20, "encoding": "UTF-16LE"}
],
"CTOS_CreateGame": [
{"name": "info", "type": "HostInfo"},
{"name": "name", "type": "unsigned short", "length": 20, "encoding": "UTF-16LE"},
{"name": "pass", "type": "unsigned short", "length": 20, "encoding": "UTF-16LE"}
],
"CTOS_JoinGame": [
{"name": "version", "type": "unsigned short"},
{"name": "align", "type": "unsigned short"},
{"name": "gameid", "type": "unsigned int"},
{"name": "pass", "type": "unsigned short", "length": 20, "encoding": "UTF-16LE"}
],
"CTOS_ExternalAddress": [
{"name": "real_ip", "type": "unsigned int"},
{"name": "hostname", "type": "unsigned short", "length":"256", "encoding": "UTF-16LE"}
],
"CTOS_Kick": [
{"name": "pos", "type": "unsigned char"}
],
"STOC_ErrorMsg": [
{"name": "msg", "type": "unsigned char"},
{"name": "align1", "type": "unsigned char"},
{"name": "align2", "type": "unsigned char"},
{"name": "align3", "type": "unsigned char"},
{"name": "code", "type": "unsigned int"}
],
"STOC_HandResult": [
{"name": "res1", "type": "unsigned char"},
{"name": "res2", "type": "unsigned char"}
],
"STOC_CreateGame": [
{"name": "gameid", "type": "unsigned int"}
],
"STOC_JoinGame": [
{"name": "info", "type": "HostInfo"}
],
"STOC_TypeChange": [
{"name": "type", "type": "unsigned char"}
],
"STOC_ExitGame": [
{"name": "pos", "type": "unsigned char"}
],
"STOC_TimeLimit": [
{"name": "player", "type": "unsigned char"},
{"name": "left_time", "type": "unsigned short"}
],
"STOC_Chat": [
{"name": "player", "type": "unsigned short"},
{"name": "msg", "type": "unsigned short", "length": 255, "encoding": "UTF-16LE"}
],
"STOC_HS_PlayerEnter": [
{"name": "name", "type": "unsigned short", "length": 20, "encoding": "UTF-16LE"},
{"name": "pos", "type": "unsigned char"},
{"name": "padding", "type": "unsigned char"}
],
"STOC_HS_PlayerChange": [
{"name": "status", "type": "unsigned char"}
],
"STOC_HS_WatchChange": [
{"name": "watch_count", "type": "unsigned short"}
],
"GameMsg_Hint_Card_only": [
{"name": "curmsg", "type": "word8Ule"},
{"name": "type", "type": "word8"},
{"name": "player", "type": "word8"},
{"name": "data", "type": "word32Ule"}
],
"deck": [
{"name": "mainc", "type": "unsigned int"},
{"name": "sidec", "type": "unsigned int"},
{"name": "deckbuf", "type": "unsigned int", "length": 90}
],
"chat": [
{"name": "msg", "type": "unsigned short", "length":"255", "encoding": "UTF-16LE"}
],
"STOC_DeckCount": [
{"name": "mainc_s", "type": "unsigned short"},
{"name": "sidec_s", "type": "unsigned short"},
{"name": "extrac_s", "type": "unsigned short"},
{"name": "mainc_o", "type": "unsigned short"},
{"name": "sidec_o", "type": "unsigned short"},
{"name": "extrac_o", "type": "unsigned short"}
]
}
{
"unsigned int": "word32Ule",
"unsigned short": "word16Ule",
"unsigned char": "word8",
"bool": "bool2"
}
\ No newline at end of file
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadConstants = void 0;
const ygopro_msg_encode_1 = require("ygopro-msg-encode");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const loadConstantsJson = () => {
const filePath = path_1.default.join(__dirname, "data", "constants.json");
const raw = fs_1.default.readFileSync(filePath, "utf8");
return JSON.parse(raw);
};
const addMissingNumberEntries = (target, source, prefix) => {
for (const [key, value] of Object.entries(source)) {
if (!key.startsWith(prefix)) {
continue;
}
if (target[key] === undefined) {
target[key] = value;
}
}
};
const addMissingStringEntries = (target, source, prefix) => {
for (const [key, value] of Object.entries(source)) {
if (!key.startsWith(prefix)) {
continue;
}
const codeKey = String(value);
if (target[codeKey] === undefined) {
target[codeKey] = key.slice(prefix.length);
}
}
};
const legacyMsgFallback = {
"3": "WAITING",
"4": "START",
"6": "UPDATE_DATA",
"8": "REQUEST_DECK",
"21": "SORT_CHAIN",
"34": "REFRESH_DECK",
"39": "MSG_SHUFFLE_EXTRA",
"80": "CARD_SELECTED",
"95": "UNEQUIP",
"121": "BE_CHAIN_TARGET",
"122": "CREATE_RELATION",
"123": "RELEASE_RELATION",
};
const toConstantName = (name) => name
.replace(/^_+|_+$/g, "")
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
.toUpperCase();
const normalizeProtoName = (name) => name
.replace("TO_OBSERVER", "TOOBSERVER")
.replace("TO_DUELIST", "TODUELIST")
.replace("HS_NOT_READY", "HS_NOTREADY")
.replace("KICK", "HS_KICK");
const buildProtoMap = (registry, classPrefix) => {
const out = {};
for (const [id, cls] of registry.protos.entries()) {
const rawName = cls.name.startsWith(classPrefix)
? cls.name.slice(classPrefix.length)
: cls.name;
const name = normalizeProtoName(toConstantName(rawName));
out[String(id)] = name;
}
return out;
};
const loadConstants = () => {
const result = loadConstantsJson();
if (!result.TYPES)
result.TYPES = {};
if (!result.RACES)
result.RACES = {};
if (!result.ATTRIBUTES)
result.ATTRIBUTES = {};
if (!result.LINK_MARKERS)
result.LINK_MARKERS = {};
if (!result.MSG)
result.MSG = {};
if (!result.TIMING)
result.TIMING = {};
if (!result.CTOS)
result.CTOS = {};
if (!result.STOC)
result.STOC = {};
if (!result.NETWORK)
result.NETWORK = {};
if (!result.NETPLAYER)
result.NETPLAYER = {};
if (!result.PLAYERCHANGE)
result.PLAYERCHANGE = {};
if (!result.ERRMSG)
result.ERRMSG = {};
if (!result.MODE)
result.MODE = {};
if (!result.DUEL_STAGE)
result.DUEL_STAGE = {};
if (!result.COLORS)
result.COLORS = {};
addMissingNumberEntries(result.TYPES, ygopro_msg_encode_1.OcgcoreCommonConstants, "TYPE_");
addMissingNumberEntries(result.RACES, ygopro_msg_encode_1.OcgcoreCommonConstants, "RACE_");
addMissingNumberEntries(result.ATTRIBUTES, ygopro_msg_encode_1.OcgcoreCommonConstants, "ATTRIBUTE_");
addMissingNumberEntries(result.ATTRIBUTES, ygopro_msg_encode_1.OcgcoreScriptConstants, "ATTRIBUTE_");
addMissingNumberEntries(result.LINK_MARKERS, ygopro_msg_encode_1.OcgcoreCommonConstants, "LINK_MARKER_");
addMissingStringEntries(result.MSG, ygopro_msg_encode_1.OcgcoreCommonConstants, "MSG_");
addMissingStringEntries(result.TIMING, ygopro_msg_encode_1.OcgcoreScriptConstants, "TIMING_");
for (const [code, name] of Object.entries(legacyMsgFallback)) {
result.MSG[code] = name;
}
const ctosMap = buildProtoMap(ygopro_msg_encode_1.YGOProCtos, "YGOProCtos");
const stocMap = buildProtoMap(ygopro_msg_encode_1.YGOProStoc, "YGOProStoc");
const mismatches = [];
for (const [code, name] of Object.entries(ctosMap)) {
if (result.CTOS[code] !== undefined && result.CTOS[code] !== name) {
mismatches.push(`CTOS ${code}: ${result.CTOS[code]} != ${name}`);
}
result.CTOS[code] = name;
}
for (const [code, name] of Object.entries(stocMap)) {
if (result.STOC[code] !== undefined && result.STOC[code] !== name) {
mismatches.push(`STOC ${code}: ${result.STOC[code]} != ${name}`);
}
result.STOC[code] = name;
}
if (mismatches.length) {
throw new Error(`CTOS/STOC name mismatch between constants.json and registry:\\n${mismatches.join("\\n")}`);
}
if (result.RACES.RACE_CYBERS === undefined &&
result.RACES.RACE_CYBERSE !== undefined) {
result.RACES.RACE_CYBERS = result.RACES.RACE_CYBERSE;
}
return result;
};
exports.loadConstants = loadConstants;
exports.default = exports.loadConstants;
if (require.main === module) {
console.log(JSON.stringify((0, exports.loadConstants)(), null, 2));
}
import {
OcgcoreCommonConstants,
OcgcoreScriptConstants,
YGOProCtos,
YGOProStoc,
} from "ygopro-msg-encode";
import fs from "fs";
import path from "path";
export interface ConstantsShape {
TYPES: Record<string, number>;
RACES: Record<string, number>;
ATTRIBUTES: Record<string, number>;
LINK_MARKERS: Record<string, number>;
DUEL_STAGE: Record<string, number>;
COLORS: Record<string, number>;
TIMING: Record<string, string>;
NETWORK: Record<string, string>;
NETPLAYER: Record<string, string>;
CTOS: Record<string, string>;
STOC: Record<string, string>;
PLAYERCHANGE: Record<string, string>;
ERRMSG: Record<string, string>;
MODE: Record<string, string>;
MSG: Record<string, string>;
}
type StringMap = Record<string, string>;
type NumberMap = Record<string, number>;
const loadConstantsJson = (): Partial<ConstantsShape> => {
const filePath = path.join(__dirname, "data", "constants.json");
const raw = fs.readFileSync(filePath, "utf8");
return JSON.parse(raw) as Partial<ConstantsShape>;
};
const addMissingNumberEntries = (
target: NumberMap,
source: Record<string, number>,
prefix: string
) => {
for (const [key, value] of Object.entries(source)) {
if (!key.startsWith(prefix)) {
continue;
}
if (target[key] === undefined) {
target[key] = value;
}
}
};
const addMissingStringEntries = (
target: StringMap,
source: Record<string, number>,
prefix: string
) => {
for (const [key, value] of Object.entries(source)) {
if (!key.startsWith(prefix)) {
continue;
}
const codeKey = String(value);
if (target[codeKey] === undefined) {
target[codeKey] = key.slice(prefix.length);
}
}
};
const legacyMsgFallback: Record<string, string> = {
"3": "WAITING",
"4": "START",
"6": "UPDATE_DATA",
"8": "REQUEST_DECK",
"21": "SORT_CHAIN",
"34": "REFRESH_DECK",
"39": "MSG_SHUFFLE_EXTRA",
"80": "CARD_SELECTED",
"95": "UNEQUIP",
"121": "BE_CHAIN_TARGET",
"122": "CREATE_RELATION",
"123": "RELEASE_RELATION",
};
const toConstantName = (name: string) =>
name
.replace(/^_+|_+$/g, "")
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
.toUpperCase();
const normalizeProtoName = (name: string) =>
name
.replace("TO_OBSERVER", "TOOBSERVER")
.replace("TO_DUELIST", "TODUELIST")
.replace("HS_NOT_READY", "HS_NOTREADY")
.replace("KICK", "HS_KICK");
const buildProtoMap = (
registry: { protos: Map<number, { name: string }> },
classPrefix: string
) => {
const out: Record<string, string> = {};
for (const [id, cls] of registry.protos.entries()) {
const rawName = cls.name.startsWith(classPrefix)
? cls.name.slice(classPrefix.length)
: cls.name;
const name = normalizeProtoName(toConstantName(rawName));
out[String(id)] = name;
}
return out;
};
export const loadConstants = () => {
const result = loadConstantsJson();
if (!result.TYPES) result.TYPES = {};
if (!result.RACES) result.RACES = {};
if (!result.ATTRIBUTES) result.ATTRIBUTES = {};
if (!result.LINK_MARKERS) result.LINK_MARKERS = {};
if (!result.MSG) result.MSG = {};
if (!result.TIMING) result.TIMING = {};
if (!result.CTOS) result.CTOS = {};
if (!result.STOC) result.STOC = {};
if (!result.NETWORK) result.NETWORK = {};
if (!result.NETPLAYER) result.NETPLAYER = {};
if (!result.PLAYERCHANGE) result.PLAYERCHANGE = {};
if (!result.ERRMSG) result.ERRMSG = {};
if (!result.MODE) result.MODE = {};
if (!result.DUEL_STAGE) result.DUEL_STAGE = {};
if (!result.COLORS) result.COLORS = {};
addMissingNumberEntries(result.TYPES, OcgcoreCommonConstants, "TYPE_");
addMissingNumberEntries(result.RACES, OcgcoreCommonConstants, "RACE_");
addMissingNumberEntries(result.ATTRIBUTES, OcgcoreCommonConstants, "ATTRIBUTE_");
addMissingNumberEntries(result.ATTRIBUTES, OcgcoreScriptConstants, "ATTRIBUTE_");
addMissingNumberEntries(result.LINK_MARKERS, OcgcoreCommonConstants, "LINK_MARKER_");
addMissingStringEntries(result.MSG, OcgcoreCommonConstants, "MSG_");
addMissingStringEntries(result.TIMING, OcgcoreScriptConstants, "TIMING_");
for (const [code, name] of Object.entries(legacyMsgFallback)) {
result.MSG[code] = name;
}
const ctosMap = buildProtoMap(YGOProCtos, "YGOProCtos");
const stocMap = buildProtoMap(YGOProStoc, "YGOProStoc");
const mismatches: string[] = [];
for (const [code, name] of Object.entries(ctosMap)) {
if (result.CTOS[code] !== undefined && result.CTOS[code] !== name) {
mismatches.push(`CTOS ${code}: ${result.CTOS[code]} != ${name}`);
}
result.CTOS[code] = name;
}
for (const [code, name] of Object.entries(stocMap)) {
if (result.STOC[code] !== undefined && result.STOC[code] !== name) {
mismatches.push(`STOC ${code}: ${result.STOC[code]} != ${name}`);
}
result.STOC[code] = name;
}
if (mismatches.length) {
throw new Error(
`CTOS/STOC name mismatch between constants.json and registry:\\n${mismatches.join("\\n")}`
);
}
if (
result.RACES.RACE_CYBERS === undefined &&
result.RACES.RACE_CYBERSE !== undefined
) {
result.RACES.RACE_CYBERS = result.RACES.RACE_CYBERSE;
}
return result as ConstantsShape;
};
export default loadConstants;
if (require.main === module) {
console.log(JSON.stringify(loadConstants(), null, 2));
}
......@@ -10,7 +10,6 @@
"license": "AGPL-3.0",
"dependencies": {
"aragami": "^1.2.5",
"async": "^3.2.0",
"axios": "^0.19.2",
"bunyan": "^1.8.14",
"deepmerge": "^4.2.2",
......@@ -23,8 +22,6 @@
"mysql": "^2.18.1",
"node-os-utils": "^1.3.2",
"p-queue": "^6.6.2",
"pg": "^6.4.2",
"q": "^1.5.1",
"querystring": "^0.2.0",
"reflect-metadata": "^0.1.13",
"request": "^2.88.2",
......@@ -38,7 +35,6 @@
"ygopro-yrp-encode": "^1.0.1"
},
"devDependencies": {
"@types/async": "^3.2.25",
"@types/bunyan": "^1.8.8",
"@types/formidable": "^3.4.6",
"@types/ip6addr": "^0.2.3",
......@@ -105,13 +101,6 @@
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz",
"integrity": "sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q=="
},
"node_modules/@types/async": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.25.tgz",
"integrity": "sha512-O6Th/DI18XjrL9TX8LO9F/g26qAz5vynmQqlXt/qLGrskvzCKXKc5/tATz3G2N6lM8eOf3M8/StB14FncAmocg==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/bunyan": {
"version": "1.8.8",
"resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.8.tgz",
......@@ -289,11 +278,6 @@
"node": ">=0.8"
}
},
"node_modules/async": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
"integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
......@@ -426,11 +410,6 @@
"ieee754": "^1.1.13"
}
},
"node_modules/buffer-writer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz",
"integrity": "sha1-Iqk2kB4wKa/NdUfrRIfOtpejvwg="
},
"node_modules/buffers": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
......@@ -1147,14 +1126,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/generic-pool": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.4.3.tgz",
"integrity": "sha1-eAw29p360FpaBF3Te+etyhGk9v8=",
"engines": {
"node": ">= 0.2.0"
}
},
"node_modules/geoip-country-lite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/geoip-country-lite/-/geoip-country-lite-1.0.0.tgz",
......@@ -1586,14 +1557,6 @@
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"node_modules/js-string-escape": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
"integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
......@@ -1972,11 +1935,6 @@
"node": ">=6"
}
},
"node_modules/packet-reader": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz",
"integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc="
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
......@@ -2041,82 +1999,6 @@
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"node_modules/pg": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/pg/-/pg-6.4.2.tgz",
"integrity": "sha1-w2QBEGDqx6UHoq4GPrhX7OkQ4n8=",
"dependencies": {
"buffer-writer": "1.0.1",
"js-string-escape": "1.0.1",
"packet-reader": "0.3.1",
"pg-connection-string": "0.1.3",
"pg-pool": "1.*",
"pg-types": "1.*",
"pgpass": "1.*",
"semver": "4.3.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/pg-connection-string": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz",
"integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc="
},
"node_modules/pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/pg-pool": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-1.8.0.tgz",
"integrity": "sha1-9+xzgkw3oD8Hb1G/33DjQBR8Tzc=",
"dependencies": {
"generic-pool": "2.4.3",
"object-assign": "4.1.0"
}
},
"node_modules/pg-pool/node_modules/object-assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
"integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/pg-types": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.13.0.tgz",
"integrity": "sha512-lfKli0Gkl/+za/+b6lzENajczwZHc7D5kiUCZfgm914jipD2kIOIvEkAhZ8GrW3/TUoP9w8FHjwpPObBye5KQQ==",
"dependencies": {
"pg-int8": "1.0.1",
"postgres-array": "~1.0.0",
"postgres-bytea": "~1.0.0",
"postgres-date": "~1.0.0",
"postgres-interval": "^1.1.0"
}
},
"node_modules/pg/node_modules/semver": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
"integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/pgpass": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz",
"integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=",
"dependencies": {
"split": "^1.0.0"
}
},
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
......@@ -2126,41 +2008,6 @@
"node": ">= 0.4"
}
},
"node_modules/postgres-array": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz",
"integrity": "sha1-jgsy6wO/d6XAp4UeBEHBaaJWojg=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-bytea": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
"integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-date": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.3.tgz",
"integrity": "sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-interval": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.2.tgz",
"integrity": "sha512-fC3xNHeTskCxL1dC8KOtxXt7YeFmlbTYtn7ul8MkVERuTmf7pI4DrkAxcw3kh1fQ9uz4wQmd03a1mRiXUZChfQ==",
"dependencies": {
"xtend": "^4.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
......@@ -2188,15 +2035,6 @@
"node": ">=6"
}
},
"node_modules/q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
"engines": {
"node": ">=0.6.0",
"teleport": ">=0.2.0"
}
},
"node_modules/qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
......@@ -2396,17 +2234,6 @@
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
},
"node_modules/split": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
"integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
"dependencies": {
"through": "2"
},
"engines": {
"node": "*"
}
},
"node_modules/sprintf-js": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
......@@ -2526,11 +2353,6 @@
"node": ">=0.8"
}
},
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"node_modules/to-buffer": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
......@@ -2993,14 +2815,6 @@
"node": ">=4.0"
}
},
"node_modules/xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
"engines": {
"node": ">=0.4"
}
},
"node_modules/y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
......@@ -3261,12 +3075,6 @@
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.2.tgz",
"integrity": "sha512-/5O7Fq6Vnv8L6ucmPjaWbVG1XkP4FO+w5glqfkIsq3Xw4oyNAdJddbnYodNDAfjVUvo/rrSCTom4kAND7T1o5Q=="
},
"@types/async": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.25.tgz",
"integrity": "sha512-O6Th/DI18XjrL9TX8LO9F/g26qAz5vynmQqlXt/qLGrskvzCKXKc5/tATz3G2N6lM8eOf3M8/StB14FncAmocg==",
"dev": true
},
"@types/bunyan": {
"version": "1.8.8",
"resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.8.tgz",
......@@ -3418,11 +3226,6 @@
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"async": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
"integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
......@@ -3509,11 +3312,6 @@
"ieee754": "^1.1.13"
}
},
"buffer-writer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz",
"integrity": "sha1-Iqk2kB4wKa/NdUfrRIfOtpejvwg="
},
"buffers": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
......@@ -4031,11 +3829,6 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
},
"generic-pool": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.4.3.tgz",
"integrity": "sha1-eAw29p360FpaBF3Te+etyhGk9v8="
},
"geoip-country-lite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/geoip-country-lite/-/geoip-country-lite-1.0.0.tgz",
......@@ -4340,11 +4133,6 @@
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"js-string-escape": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
"integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
......@@ -4646,11 +4434,6 @@
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
},
"packet-reader": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz",
"integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc="
},
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
......@@ -4700,102 +4483,11 @@
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"pg": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/pg/-/pg-6.4.2.tgz",
"integrity": "sha1-w2QBEGDqx6UHoq4GPrhX7OkQ4n8=",
"requires": {
"buffer-writer": "1.0.1",
"js-string-escape": "1.0.1",
"packet-reader": "0.3.1",
"pg-connection-string": "0.1.3",
"pg-pool": "1.*",
"pg-types": "1.*",
"pgpass": "1.*",
"semver": "4.3.2"
},
"dependencies": {
"semver": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
"integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c="
}
}
},
"pg-connection-string": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz",
"integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc="
},
"pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="
},
"pg-pool": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-1.8.0.tgz",
"integrity": "sha1-9+xzgkw3oD8Hb1G/33DjQBR8Tzc=",
"requires": {
"generic-pool": "2.4.3",
"object-assign": "4.1.0"
},
"dependencies": {
"object-assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
"integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A="
}
}
},
"pg-types": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.13.0.tgz",
"integrity": "sha512-lfKli0Gkl/+za/+b6lzENajczwZHc7D5kiUCZfgm914jipD2kIOIvEkAhZ8GrW3/TUoP9w8FHjwpPObBye5KQQ==",
"requires": {
"pg-int8": "1.0.1",
"postgres-array": "~1.0.0",
"postgres-bytea": "~1.0.0",
"postgres-date": "~1.0.0",
"postgres-interval": "^1.1.0"
}
},
"pgpass": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz",
"integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=",
"requires": {
"split": "^1.0.0"
}
},
"possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="
},
"postgres-array": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz",
"integrity": "sha1-jgsy6wO/d6XAp4UeBEHBaaJWojg="
},
"postgres-bytea": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
"integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU="
},
"postgres-date": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.3.tgz",
"integrity": "sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g="
},
"postgres-interval": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.2.tgz",
"integrity": "sha512-fC3xNHeTskCxL1dC8KOtxXt7YeFmlbTYtn7ul8MkVERuTmf7pI4DrkAxcw3kh1fQ9uz4wQmd03a1mRiXUZChfQ==",
"requires": {
"xtend": "^4.0.0"
}
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
......@@ -4820,11 +4512,6 @@
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
......@@ -4977,14 +4664,6 @@
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
},
"split": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
"integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
"requires": {
"through": "2"
}
},
"sprintf-js": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
......@@ -5078,11 +4757,6 @@
"thenify": ">= 3.1.0 < 4"
}
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"to-buffer": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
......@@ -5412,11 +5086,6 @@
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
},
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
......
......@@ -12,7 +12,6 @@
"author": "zh99998 <zh99998@gmail.com>, mercury233 <me@mercury233.me>, Nanahira <78877@qq.com>",
"dependencies": {
"aragami": "^1.2.5",
"async": "^3.2.0",
"axios": "^0.19.2",
"bunyan": "^1.8.14",
"deepmerge": "^4.2.2",
......@@ -25,8 +24,6 @@
"mysql": "^2.18.1",
"node-os-utils": "^1.3.2",
"p-queue": "^6.6.2",
"pg": "^6.4.2",
"q": "^1.5.1",
"querystring": "^0.2.0",
"reflect-metadata": "^0.1.13",
"request": "^2.88.2",
......@@ -49,7 +46,6 @@
"webhook": "node ygopro-webhook.js"
},
"devDependencies": {
"@types/async": "^3.2.25",
"@types/bunyan": "^1.8.8",
"@types/formidable": "^3.4.6",
"@types/ip6addr": "^0.2.3",
......
// a special version of node-struct by xdenser
// https://github.com/xdenser/node-struct/tree/f843487d6768cd0bf20c2ce7803dde2d92df5694
function byteField(p, offset) {
this.length = 1;
this.get = function () {
return p.buf[offset];
}
this.set = function (val) {
p.buf[offset] = val;
}
}
function boolField(p, offset, length) {
this.length = length;
this.get = function () {
return (p.buf[offset] > 0 );
}
this.set = function (val) {
p.buf[offset] = val ? 1 : 0;
}
}
function intField(p, offset, length, le, signed) {
this.length = length;
function bec(cb) {
for (var i = 0; i < length; i++)
cb(i, length - i - 1);
}
function lec(cb) {
for (var i = 0; i < length; i++)
cb(i, i);
}
function getUVal(bor) {
var val = 0;
bor(function (i, o) {
val += Math.pow(256, o) * p.buf[offset + i];
})
return val;
}
function getSVal(bor) {
var val = getUVal(bor);
if ((p.buf[offset + ( le ? (length - 1) : 0)] & 0x80) == 0x80) {
val -= Math.pow(256, length);
}
return val;
}
function setVal(bor, val) {
bor(function (i, o) {
p.buf[offset + i] = Math.floor(val / Math.pow(256, o)) & 0xff;
});
}
this.get = function () {
var bor = le ? lec : bec;
return ( signed ? getSVal(bor) : getUVal(bor));
}
this.set = function (val) {
var bor = le ? lec : bec;
setVal(bor, val);
}
}
function charField(p, offset, length, encoding) {
this.length = length;
this.encoding = encoding;
this.get = function () {
var result = p.buf.toString(this.encoding, offset, offset + length);
var strlen = result.indexOf("\0");
if (strlen == -1) {
return result;
} else {
return result.slice(0, strlen);
}
}
this.set = function (val) {
val += "\0";
if (val.length > length)
val = val.substring(0, length);
p.buf.write(val, offset, this.encoding);
}
}
function structField(p, offset, struct) {
this.length = struct.length();
this.get = function () {
return struct;
}
this.set = function (val) {
struct.set(val);
}
this.allocate = function () {
struct._setBuff(p.buf.slice(offset, offset + struct.length()));
}
}
function arrayField(p, offset, len, type) {
var as = Struct();
var args = [].slice.call(arguments, 4);
args.unshift(0);
for (var i = 0; i < len; i++) {
if (type instanceof Struct) {
as.struct(i, type.clone());
} else if (type in as) {
args[0] = i;
as[type].apply(as, args);
}
}
this.length = as.length();
this.allocate = function () {
as._setBuff(p.buf.slice(offset, offset + as.length()));
}
this.get = function () {
return as;
}
this.set = function (val) {
as.set(val);
}
}
function Struct() {
if (!(this instanceof Struct))
return new Struct;
var priv = {
buf: {},
allocated: false,
len: 0,
fields: {},
closures: []
}, self = this;
function checkAllocated() {
if (priv.allocated)
throw new Error('Cant change struct after allocation');
}
this.word8 = function (key) {
checkAllocated();
priv.closures.push(function (p) {
p.fields[key] = new byteField(p, p.len);
p.len++;
});
return this;
};
// Create handlers for various Bool Field Variants
[1, 2, 3, 4].forEach(function (n) {
self['bool' + (n == 1 ? '' : n)] = function (key) {
checkAllocated();
priv.closures.push(function (p) {
p.fields[key] = new boolField(p, p.len, n);
p.len += n;
});
return this;
}
});
// Create handlers for various Integer Field Variants
[1, 2, 3, 4, 6, 8].forEach(function (n) {
[true, false].forEach(function (le) {
[true, false].forEach(function (signed) {
var name = 'word' + (n * 8) + ( signed ? 'S' : 'U') + ( le ? 'le' : 'be');
self[name] = function (key) {
checkAllocated();
priv.closures.push(function (p) {
p.fields[key] = new intField(p, p.len, n, le, signed);
p.len += n;
});
return this;
};
});
});
});
this.chars = function (key, length, encoding) {
checkAllocated();
priv.closures.push(function (p) {
p.fields[key] = new charField(p, p.len, length, encoding || 'ascii');
p.len += length;
});
return this;
}
this.struct = function (key, struct) {
checkAllocated();
priv.closures.push(function (p) {
p.fields[key] = new structField(p, p.len, struct.clone());
p.len += p.fields[key].length;
});
return this;
}
function construct(constructor, args) {
function F() {
return constructor.apply(this, args);
}
F.prototype = constructor.prototype;
return new F();
}
this.array = function (key, length, type) {
checkAllocated();
var args = [].slice.call(arguments, 1);
args.unshift(null);
args.unshift(null);
priv.closures.push(function (p) {
args[0] = p;
args[1] = p.len;
p.fields[key] = construct(arrayField, args);
p.len += p.fields[key].length;
});
return this;
}
var beenHere = false;
function applyClosures(p) {
if (beenHere)
return;
p.closures.forEach(function (el) {
el(p);
});
beenHere = true;
}
function allocateFields() {
for (var key in priv.fields) {
if ('allocate' in priv.fields[key])
priv.fields[key].allocate();
}
}
this._setBuff = function (buff) {
priv.buf = buff;
applyClosures(priv);
allocateFields();
priv.allocated = true;
}
this.allocate = function () {
applyClosures(priv);
priv.buf = Buffer.alloc(priv.len);
allocateFields();
priv.allocated = true;
return this;
}
this._getPriv = function () {
return priv;
}
this.clone = function () {
var c = new Struct;
var p = c._getPriv();
p.closures = priv.closures;
return c;
}
this.length = function () {
applyClosures(priv);
return priv.len;
}
this.get = function (key) {
if (key in priv.fields) {
return priv.fields[key].get();
} else
throw new Error('Can not find field ' + key);
}
this.set = function (key, val) {
if (arguments.length == 2) {
if (key in priv.fields) {
priv.fields[key].set(val);
} else
throw new Error('Can not find field ' + key);
} else if (Buffer.isBuffer(key)) {
this._setBuff(key);
} else {
for (var k in key) {
this.set(k, key[k]);
}
}
}
this.buffer = function () {
return priv.buf;
}
function getFields() {
var fields = {};
Object.keys(priv.fields).forEach(function (key) {
Object.defineProperty(fields, key, {
get: function () {
var res = self.get(key);
if (res instanceof Struct) return res.fields;
else return res;
},
set: function (newVal) {
self.set(key, newVal);
},
enumerable: true
});
});
return fields;
};
var _fields;
Object.defineProperty(this, 'fields', {
get: function () {
if (_fields) return _fields;
return (_fields = getFields());
},
enumerable: true,
configurable: true
});
}
exports.Struct = Struct;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.overwriteBuffer = void 0;
exports.retry = retry;
async function retry(fn, count, delayFn = (attempt) => Math.pow(2, attempt) * 100) {
let lastError;
......@@ -18,3 +19,13 @@ async function retry(fn, count, delayFn = (attempt) => Math.pow(2, attempt) * 10
// 如果全部尝试失败,抛出最后一个错误
throw lastError;
}
const overwriteBuffer = (buf, _input) => {
const input = Buffer.isBuffer(_input) ? _input : Buffer.from(_input);
if (input.length >= buf.length) {
input.copy(buf, 0, 0, buf.length);
}
else {
input.copy(buf, 0, 0, input.length);
}
};
exports.overwriteBuffer = overwriteBuffer;
......@@ -20,3 +20,13 @@ export async function retry<T>(
// 如果全部尝试失败,抛出最后一个错误
throw lastError;
}
export const overwriteBuffer = (buf: Buffer, _input: Buffer | Uint8Array) => {
const input = Buffer.isBuffer(_input) ? _input : Buffer.from(_input);
if (input.length >= buf.length) {
input.copy(buf, 0, 0, buf.length);
} else {
input.copy(buf, 0, 0, input.length);
}
}
......@@ -10,7 +10,7 @@ var fs = require('fs');
var initSqlJs = require('sql.js');
var loadJSON = require('load-json-file').sync;
var config = loadJSON('./config/deckstats.json'); //{ "deckpath": "../decks", "dbfile": "cards.cdb" }
var constants = loadJSON('./data/constants.json');
var constants = require('./load-constants').loadConstants();
var ALL_MAIN_CARDS={};
var ALL_SIDE_CARDS={};
......
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fromPartialCompat = exports.applyYGOProMsgStructCompat = exports.defineYGOProMsgStructCompat = exports.YGOProMsgStructCompat = void 0;
const ygopro_deck_encode_1 = __importDefault(require("ygopro-deck-encode"));
const ygopro_msg_encode_1 = require("ygopro-msg-encode");
exports.YGOProMsgStructCompat = new Map();
const defineYGOProMsgStructCompat = (cls, field, getterAndSetter) => {
if (!exports.YGOProMsgStructCompat.has(cls)) {
exports.YGOProMsgStructCompat.set(cls, []);
}
exports.YGOProMsgStructCompat.get(cls).push((inst) => {
Object.defineProperty(inst, field, {
get() {
return getterAndSetter.get(inst);
},
set(value) {
getterAndSetter.set(inst, value);
}
});
});
};
exports.defineYGOProMsgStructCompat = defineYGOProMsgStructCompat;
const applyYGOProMsgStructCompat = (inst) => {
const compatList = exports.YGOProMsgStructCompat.get(inst.constructor);
if (compatList) {
compatList.forEach(compat => compat(inst));
}
return inst;
};
exports.applyYGOProMsgStructCompat = applyYGOProMsgStructCompat;
const fromPartialCompat = (cls, input) => {
const inst1 = new cls();
(0, exports.applyYGOProMsgStructCompat)(inst1);
Object.assign(inst1, input);
const inst2 = new cls().fromPartial(inst1);
(0, exports.applyYGOProMsgStructCompat)(inst2);
return inst2;
};
exports.fromPartialCompat = fromPartialCompat;
const compatDeckState = new WeakMap();
const getCompatDeckState = (inst) => {
let state = compatDeckState.get(inst);
if (!state) {
state = {};
compatDeckState.set(inst, state);
}
return state;
};
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProStocChat, "player", {
get(inst) {
return inst.player_type;
},
set(inst, value) {
inst.player_type = value;
},
});
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProStocDeckCount, "mainc_s", {
get(inst) {
return inst.player0DeckCount?.main ?? 0;
},
set(inst, value) {
if (!inst.player0DeckCount) {
inst.player0DeckCount = new ygopro_msg_encode_1.YGOProStocDeckCount_DeckInfo();
}
inst.player0DeckCount.main = value;
},
});
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProStocDeckCount, "sidec_s", {
get(inst) {
return inst.player0DeckCount?.side ?? 0;
},
set(inst, value) {
if (!inst.player0DeckCount) {
inst.player0DeckCount = new ygopro_msg_encode_1.YGOProStocDeckCount_DeckInfo();
}
inst.player0DeckCount.side = value;
},
});
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProStocDeckCount, "extrac_s", {
get(inst) {
return inst.player0DeckCount?.extra ?? 0;
},
set(inst, value) {
if (!inst.player0DeckCount) {
inst.player0DeckCount = new ygopro_msg_encode_1.YGOProStocDeckCount_DeckInfo();
}
inst.player0DeckCount.extra = value;
},
});
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProStocDeckCount, "mainc_o", {
get(inst) {
return inst.player1DeckCount?.main ?? 0;
},
set(inst, value) {
if (!inst.player1DeckCount) {
inst.player1DeckCount = new ygopro_msg_encode_1.YGOProStocDeckCount_DeckInfo();
}
inst.player1DeckCount.main = value;
},
});
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProStocDeckCount, "sidec_o", {
get(inst) {
return inst.player1DeckCount?.side ?? 0;
},
set(inst, value) {
if (!inst.player1DeckCount) {
inst.player1DeckCount = new ygopro_msg_encode_1.YGOProStocDeckCount_DeckInfo();
}
inst.player1DeckCount.side = value;
},
});
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProStocDeckCount, "extrac_o", {
get(inst) {
return inst.player1DeckCount?.extra ?? 0;
},
set(inst, value) {
if (!inst.player1DeckCount) {
inst.player1DeckCount = new ygopro_msg_encode_1.YGOProStocDeckCount_DeckInfo();
}
inst.player1DeckCount.extra = value;
},
});
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProCtosUpdateDeck, "mainc", {
get(inst) {
return inst.deck.main.length + inst.deck.extra.length;
},
set(inst, value) {
const state = getCompatDeckState(inst);
state.mainc = value;
},
});
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProCtosUpdateDeck, "sidec", {
get(inst) {
return inst.deck.side.length;
},
set(inst, value) {
const state = getCompatDeckState(inst);
state.sidec = value;
},
});
(0, exports.defineYGOProMsgStructCompat)(ygopro_msg_encode_1.YGOProCtosUpdateDeck, "deckbuf", {
get(inst) {
return [...inst.deck.main, ...inst.deck.extra, ...inst.deck.side];
},
set(inst, value) {
const state = getCompatDeckState(inst);
const deckbuf = Array.isArray(value) ? value.slice() : [];
state.deckbuf = deckbuf;
if (!inst.deck) {
inst.deck = new ygopro_deck_encode_1.default();
}
const hasMainc = state.mainc !== undefined;
const hasSidec = state.sidec !== undefined;
if (!hasMainc && !hasSidec) {
inst.deck.main = deckbuf.slice();
inst.deck.extra = [];
inst.deck.side = [];
return;
}
if (hasMainc && !hasSidec) {
const mainc = Math.max(0, state.mainc | 0);
const mainWithExtra = deckbuf.slice(0, mainc);
const side = deckbuf.slice(mainc);
inst.deck.main = mainWithExtra.slice();
inst.deck.extra = [];
inst.deck.side = side.slice();
return;
}
if (!hasMainc && hasSidec) {
const sidec = Math.max(0, state.sidec | 0);
const split = Math.max(0, deckbuf.length - sidec);
const mainWithExtra = deckbuf.slice(0, split);
const side = deckbuf.slice(split);
inst.deck.main = mainWithExtra.slice();
inst.deck.extra = [];
inst.deck.side = side.slice();
return;
}
const mainc = Math.max(0, state.mainc | 0);
const sidec = Math.max(0, state.sidec | 0);
const mainWithExtra = deckbuf.slice(0, mainc);
const side = deckbuf.slice(mainc, mainc + sidec);
inst.deck.main = mainWithExtra.slice();
inst.deck.extra = [];
inst.deck.side = side.slice();
},
});
import YGOProDeck from "ygopro-deck-encode";
import {
YGOProCtosUpdateDeck,
YGOProCtosBase, YGOProStocBase,
YGOProStocChat,
YGOProStocDeckCount,
YGOProStocDeckCount_DeckInfo,
} from "ygopro-msg-encode";
export const YGOProMsgStructCompat = new Map<new (...args: any[]) => YGOProCtosBase | YGOProStocBase, ((inst: YGOProCtosBase | YGOProStocBase) => void)[]>();
export const defineYGOProMsgStructCompat = <T extends YGOProCtosBase | YGOProStocBase>(cls: new (...args: any[]) => T, field: string, getterAndSetter: {
get: (inst: T) => any,
set: (inst: T, value: any) => void
}) => {
if (!YGOProMsgStructCompat.has(cls)) {
YGOProMsgStructCompat.set(cls, []);
}
YGOProMsgStructCompat.get(cls)!.push((inst: YGOProCtosBase | YGOProStocBase) => {
Object.defineProperty(inst, field, {
get() {
return getterAndSetter.get(inst as T);
},
set(value) {
getterAndSetter.set(inst as T, value);
}
})
})
}
export const applyYGOProMsgStructCompat = (inst: YGOProCtosBase | YGOProStocBase) => {
const compatList = YGOProMsgStructCompat.get(inst.constructor as typeof YGOProCtosBase | typeof YGOProStocBase);
if (compatList) {
compatList.forEach(compat => compat(inst));
}
return inst;
}
export const fromPartialCompat = <T extends YGOProCtosBase | YGOProStocBase>(
cls: new (...args: any[]) => T,
input: Partial<T>
): T => {
const inst1 = new cls();
applyYGOProMsgStructCompat(inst1);
Object.assign(inst1, input);
const inst2 = new cls().fromPartial(inst1 as Partial<T>) as T;
applyYGOProMsgStructCompat(inst2);
return inst2;
};
const compatDeckState = new WeakMap<
YGOProCtosUpdateDeck,
{ mainc?: number; sidec?: number; deckbuf?: number[] }
>();
const getCompatDeckState = (inst: YGOProCtosUpdateDeck) => {
let state = compatDeckState.get(inst);
if (!state) {
state = {};
compatDeckState.set(inst, state);
}
return state;
};
defineYGOProMsgStructCompat(YGOProStocChat, "player", {
get(inst) {
return inst.player_type;
},
set(inst, value) {
inst.player_type = value;
},
});
defineYGOProMsgStructCompat(YGOProStocDeckCount, "mainc_s", {
get(inst) {
return inst.player0DeckCount?.main ?? 0;
},
set(inst, value) {
if (!inst.player0DeckCount) {
inst.player0DeckCount = new YGOProStocDeckCount_DeckInfo();
}
inst.player0DeckCount.main = value;
},
});
defineYGOProMsgStructCompat(YGOProStocDeckCount, "sidec_s", {
get(inst) {
return inst.player0DeckCount?.side ?? 0;
},
set(inst, value) {
if (!inst.player0DeckCount) {
inst.player0DeckCount = new YGOProStocDeckCount_DeckInfo();
}
inst.player0DeckCount.side = value;
},
});
defineYGOProMsgStructCompat(YGOProStocDeckCount, "extrac_s", {
get(inst) {
return inst.player0DeckCount?.extra ?? 0;
},
set(inst, value) {
if (!inst.player0DeckCount) {
inst.player0DeckCount = new YGOProStocDeckCount_DeckInfo();
}
inst.player0DeckCount.extra = value;
},
});
defineYGOProMsgStructCompat(YGOProStocDeckCount, "mainc_o", {
get(inst) {
return inst.player1DeckCount?.main ?? 0;
},
set(inst, value) {
if (!inst.player1DeckCount) {
inst.player1DeckCount = new YGOProStocDeckCount_DeckInfo();
}
inst.player1DeckCount.main = value;
},
});
defineYGOProMsgStructCompat(YGOProStocDeckCount, "sidec_o", {
get(inst) {
return inst.player1DeckCount?.side ?? 0;
},
set(inst, value) {
if (!inst.player1DeckCount) {
inst.player1DeckCount = new YGOProStocDeckCount_DeckInfo();
}
inst.player1DeckCount.side = value;
},
});
defineYGOProMsgStructCompat(YGOProStocDeckCount, "extrac_o", {
get(inst) {
return inst.player1DeckCount?.extra ?? 0;
},
set(inst, value) {
if (!inst.player1DeckCount) {
inst.player1DeckCount = new YGOProStocDeckCount_DeckInfo();
}
inst.player1DeckCount.extra = value;
},
});
defineYGOProMsgStructCompat(YGOProCtosUpdateDeck, "mainc", {
get(inst) {
return inst.deck.main.length + inst.deck.extra.length;
},
set(inst, value) {
const state = getCompatDeckState(inst);
state.mainc = value;
},
});
defineYGOProMsgStructCompat(YGOProCtosUpdateDeck, "sidec", {
get(inst) {
return inst.deck.side.length;
},
set(inst, value) {
const state = getCompatDeckState(inst);
state.sidec = value;
},
});
defineYGOProMsgStructCompat(YGOProCtosUpdateDeck, "deckbuf", {
get(inst) {
return [...inst.deck.main, ...inst.deck.extra, ...inst.deck.side];
},
set(inst, value) {
const state = getCompatDeckState(inst);
const deckbuf = Array.isArray(value) ? value.slice() : [];
state.deckbuf = deckbuf;
if (!inst.deck) {
inst.deck = new YGOProDeck();
}
const hasMainc = state.mainc !== undefined;
const hasSidec = state.sidec !== undefined;
if (!hasMainc && !hasSidec) {
inst.deck.main = deckbuf.slice();
inst.deck.extra = [];
inst.deck.side = [];
return;
}
if (hasMainc && !hasSidec) {
const mainc = Math.max(0, state.mainc | 0);
const mainWithExtra = deckbuf.slice(0, mainc);
const side = deckbuf.slice(mainc);
inst.deck.main = mainWithExtra.slice();
inst.deck.extra = [];
inst.deck.side = side.slice();
return;
}
if (!hasMainc && hasSidec) {
const sidec = Math.max(0, state.sidec | 0);
const split = Math.max(0, deckbuf.length - sidec);
const mainWithExtra = deckbuf.slice(0, split);
const side = deckbuf.slice(split);
inst.deck.main = mainWithExtra.slice();
inst.deck.extra = [];
inst.deck.side = side.slice();
return;
}
const mainc = Math.max(0, state.mainc | 0);
const sidec = Math.max(0, state.sidec | 0);
const mainWithExtra = deckbuf.slice(0, mainc);
const side = deckbuf.slice(mainc, mainc + sidec);
inst.deck.main = mainWithExtra.slice();
inst.deck.extra = [];
inst.deck.side = side.slice();
},
});
......@@ -22,7 +22,7 @@ var loadJSON = require('load-json-file').sync;
var auth = require('./ygopro-auth.js');
var constants = loadJSON('./data/constants.json');
var constants = require('./load-constants').loadConstants();
var settings = loadJSON('./config/config.json');
config = settings.modules.pre_util;
......@@ -34,7 +34,6 @@ var cardHTMLs=[];
var responder;
//URL里的更新时间戳
var dataver = moment().format("YYYYMMDDHHmmss");
const _async = require("async");
var sqlJsPromise;
var SQL = null;
......@@ -53,6 +52,8 @@ function ensureSqlJs() {
return sqlJsPromise;
}
var execAsync = util.promisify(exec);
//输出反馈信息,如有http长连接则输出到http,否则输出到控制台
var sendResponse = function(text) {
text=""+text;
......@@ -221,57 +222,55 @@ var loadDb = function(db_file, callback) {
}
//将cardHTMLs中内容更新到指定列表页,同步
var writeToFile = function(message, callback) {
var fileContent=fs.readFileSync(config.html_path+config.html_filename, {"encoding":"utf-8"});
var newContent=cardHTMLs.join("\n");
fileContent=fileContent.replace(/<tbody class="auto-generated">[\w\W]*<\/tbody>/,'<tbody class="auto-generated">\n'+newContent+'\n</tbody>');
fileContent = fileContent.replace(/data-ygosrv233-download="(http.+)" href="http.+"/g, 'data-ygosrv233-download="$1" href="$1"');
fileContent = fileContent.replace(/href="(http.+)dataver/g, 'href="$1' + dataver);
if (message) {
message="<li>"+moment().format('L HH:mm')+"<ul><li>"+message.split("!换行符!").join("</li><li>")+"</li></ul></li>";
fileContent=fileContent.replace(/<ul class="auto-generated">/,'<ul class="auto-generated">\n'+message);
}
_async.auto({
write: (done) => {
fs.writeFile(config.html_path + config.html_filename, fileContent, done)
},
copy: ["write", (results, done) => {
if (!config.cdn.enabled) {
copyImages(done);
} else {
done();
}
}]
}, (err) => {
if (!err) {
sendResponse("列表更新完成。");
var writeToFile = async function(message, callback) {
try {
var fileContent=fs.readFileSync(config.html_path+config.html_filename, {"encoding":"utf-8"});
var newContent=cardHTMLs.join("\n");
fileContent=fileContent.replace(/<tbody class="auto-generated">[\w\W]*<\/tbody>/,'<tbody class="auto-generated">\n'+newContent+'\n</tbody>');
fileContent = fileContent.replace(/data-ygosrv233-download="(http.+)" href="http.+"/g, 'data-ygosrv233-download="$1" href="$1"');
fileContent = fileContent.replace(/href="(http.+)dataver/g, 'href="$1' + dataver);
if (message) {
message="<li>"+moment().format('L HH:mm')+"<ul><li>"+message.split("!换行符!").join("</li><li>")+"</li></ul></li>";
fileContent=fileContent.replace(/<ul class="auto-generated">/,'<ul class="auto-generated">\n'+message);
}
await fs.promises.writeFile(config.html_path + config.html_filename, fileContent);
if (!config.cdn.enabled) {
await util.promisify(copyImages)();
}
callback(err);
})
sendResponse("列表更新完成。");
callback(null);
} catch (err) {
callback(err);
}
}
//读取指定文件夹里所有数据库,异步
var loadAllDbs = function(callback) {
cardHTMLs=[];
_async.auto({
files: (done) => {
fs.readdir(config.db_path + "expansions/", done);
},
loadDbs: ["files", (results, done) => {
_async.each(results.files.filter((filename) => {
return filename.slice(-4) === ".cdb" && (!config.only_show_dbs || config.only_show_dbs.length == 0 || config.only_show_dbs[filename])
} ).map(filename => config.db_path + "expansions/" + filename), loadDb, done);
}]
}, callback);
var loadAllDbs = async function(callback) {
try {
cardHTMLs=[];
var files = await fs.promises.readdir(config.db_path + "expansions/");
var list = files.filter((filename) => {
return filename.slice(-4) === ".cdb" && (!config.only_show_dbs || config.only_show_dbs.length == 0 || config.only_show_dbs[filename]);
}).map(filename => config.db_path + "expansions/" + filename);
for (var i = 0; i < list.length; i++) {
await util.promisify(loadDb)(list[i]);
}
callback(null);
} catch (err) {
callback(err);
}
}
function execCommands(commands, callback) {
_async.eachSeries(commands, (command, done) => {
exec(command, (err) => {
done(err);
});
}, callback);
async function execCommands(commands, callback) {
try {
for (var i = 0; i < commands.length; i++) {
await execAsync(commands[i]);
}
callback(null);
} catch (err) {
callback(err);
}
}
//从远程更新数据库,异步
......@@ -303,20 +302,17 @@ var fetchDatas = function() {
}
//更新本地网页到服务器,异步
var pushDatas = function(callback) {
if (config.cdn.enabled) {
_async.auto({
local: (done) => {
uploadCDN(config.cdn.local, config.cdn.remote + "/" + dataver, done);
},
pics: ["local", (results, done) => {
uploadCDN(config.db_path + "pics", config.cdn.pics_remote + "pics", done);
}],
push: ["local", "pics", (results, done) => {
sendResponse("CDN上传全部完成。");
pushHTMLs(done);
}]
}, callback);
var pushDatas = async function(callback) {
try {
if (config.cdn.enabled) {
await util.promisify(uploadCDN)(config.cdn.local, config.cdn.remote + "/" + dataver);
await util.promisify(uploadCDN)(config.db_path + "pics", config.cdn.pics_remote + "pics");
sendResponse("CDN上传全部完成。");
await util.promisify(pushHTMLs)();
}
callback(null);
} catch (err) {
callback(err);
}
}
......@@ -429,85 +425,59 @@ function run7z(params, cwd, callback) {
}
//生成更新包,异步
var packDatas = function (callback) {
var packDatas = async function (callback) {
file_path = config.html_path;
if (config.cdn.enabled) {
file_path = config.cdn.local;
}
_async.auto({
preCommands: (done) => {
execCommands([
'rm -rf "' + config.db_path +'expansions/' + config.ypk_name + '"',
'rm -rf "' + config.db_path +'expansions/script"',
'rm -rf "' + config.db_path +'expansions/pics"',
'rm -rf "' + config.db_path +'cdb"',
'rm -rf "' + config.db_path +'picture"',
'mkdir "' + config.db_path +'picture"',
'cp -r "' + config.db_path + 'expansions" "' + config.db_path + 'cdb"',
'cp -r "' + config.db_path + 'pics" "' + config.db_path + 'expansions/pics"',
'cp -r "' + config.db_path + 'field" "' + config.db_path + 'expansions/pics/field"',
'cp -r "' + config.db_path + 'script" "' + config.db_path + 'expansions/script"',
'cp -r "' + config.db_path + 'pics" "' + config.db_path + 'picture/card"',
'cp -r "' + config.db_path + 'field" "' + config.db_path + 'picture/field"'
], done);
},
run7zYPK: ["preCommands", (results, done) => {
run7z(["a", "-tzip", "-x!*.ypk", config.ypk_name, "*"], config.db_path + "expansions/", done);
}],
run7zPC: ["run7zYPK", (results, done) => {
run7z(["a", "-x!*.zip", "-x!.git", "-x!LICENSE", "-x!README.md",
"-x!cdb", "-x!picture", "-x!field", "-x!script", "-x!pics",
"-x!expansions/pics", "-x!expansions/script", "-x!expansions/*.cdb", "-x!expansions/*.conf",
"ygosrv233-pre.zip", "*"], config.db_path, done);
}],
run7zMobile: ["run7zYPK", (results, done) => {
run7z(["a", "-x!*.zip", "-x!.git", "-x!LICENSE", "-x!README.md",
"-x!cdb", "-x!picture", "-x!field", "-x!script", "-x!pics",
"-x!expansions/pics", "-x!expansions/script", "-x!expansions/*.cdb", "-x!expansions/*.conf",
"ygosrv233-pre-mobile.zip", "*"], config.db_path, done);
}],
run7zPro2: ["preCommands", (results, done) => {
run7z(["a", "-x!*.zip", "-x!.git", "-x!LICENSE", "-x!README.md",
"-x!expansions", "-x!pics", "-x!field",
"ygosrv233-pre-2.zip", "*"], config.db_path, done);
}],
commandsAfterPC: ["run7zPC", (results, done) => {
execCommands([
'mv -f "' + config.db_path + 'ygosrv233-pre.zip" "' + file_path + '"'
], (err) => {
if (!err) {
sendResponse("电脑更新包打包完成。");
}
done(err);
});
}],
commandsAfterMobile: ["run7zPC", "run7zMobile", (results, done) => {
execCommands([
'mv -f "' + config.db_path +'ygosrv233-pre-mobile.zip" "'+ file_path +'"',
'rm -rf "' + config.db_path +'expansions/' + config.ypk_name + '"',
'rm -rf "' + config.db_path +'expansions/script"',
'rm -rf "' + config.db_path +'expansions/pics"'
], (err) => {
if (!err) {
sendResponse("手机更新包打包完成。");
}
done(err);
});
}],
commandsAfterPro2: ["run7zPro2", (results, done) => {
execCommands([
'mv -f "' + config.db_path + 'ygosrv233-pre-2.zip" "' + file_path + '"',
'rm -rf "' + config.db_path +'cdb"',
'rm -rf "' + config.db_path +'picture"'
], (err) => {
if (!err) {
sendResponse("Pro2更新包打包完成。");
}
done(err);
});
}]
}, callback);
try {
await util.promisify(execCommands)([
'rm -rf "' + config.db_path +'expansions/' + config.ypk_name + '"',
'rm -rf "' + config.db_path +'expansions/script"',
'rm -rf "' + config.db_path +'expansions/pics"',
'rm -rf "' + config.db_path +'cdb"',
'rm -rf "' + config.db_path +'picture"',
'mkdir "' + config.db_path +'picture"',
'cp -r "' + config.db_path + 'expansions" "' + config.db_path + 'cdb"',
'cp -r "' + config.db_path + 'pics" "' + config.db_path + 'expansions/pics"',
'cp -r "' + config.db_path + 'field" "' + config.db_path + 'expansions/pics/field"',
'cp -r "' + config.db_path + 'script" "' + config.db_path + 'expansions/script"',
'cp -r "' + config.db_path + 'pics" "' + config.db_path + 'picture/card"',
'cp -r "' + config.db_path + 'field" "' + config.db_path + 'picture/field"'
]);
await util.promisify(run7z)(["a", "-tzip", "-x!*.ypk", config.ypk_name, "*"], config.db_path + "expansions/");
await util.promisify(run7z)(["a", "-x!*.zip", "-x!.git", "-x!LICENSE", "-x!README.md",
"-x!cdb", "-x!picture", "-x!field", "-x!script", "-x!pics",
"-x!expansions/pics", "-x!expansions/script", "-x!expansions/*.cdb", "-x!expansions/*.conf",
"ygosrv233-pre.zip", "*"], config.db_path);
await util.promisify(execCommands)([
'mv -f "' + config.db_path + 'ygosrv233-pre.zip" "' + file_path + '"'
]);
sendResponse("电脑更新包打包完成。");
await util.promisify(run7z)(["a", "-x!*.zip", "-x!.git", "-x!LICENSE", "-x!README.md",
"-x!cdb", "-x!picture", "-x!field", "-x!script", "-x!pics",
"-x!expansions/pics", "-x!expansions/script", "-x!expansions/*.cdb", "-x!expansions/*.conf",
"ygosrv233-pre-mobile.zip", "*"], config.db_path);
await util.promisify(execCommands)([
'mv -f "' + config.db_path +'ygosrv233-pre-mobile.zip" "'+ file_path +'"',
'rm -rf "' + config.db_path +'expansions/' + config.ypk_name + '"',
'rm -rf "' + config.db_path +'expansions/script"',
'rm -rf "' + config.db_path +'expansions/pics"'
]);
sendResponse("手机更新包打包完成。");
await util.promisify(run7z)(["a", "-x!*.zip", "-x!.git", "-x!LICENSE", "-x!README.md",
"-x!expansions", "-x!pics", "-x!field",
"ygosrv233-pre-2.zip", "*"], config.db_path);
await util.promisify(execCommands)([
'mv -f "' + config.db_path + 'ygosrv233-pre-2.zip" "' + file_path + '"',
'rm -rf "' + config.db_path +'cdb"',
'rm -rf "' + config.db_path +'picture"'
]);
sendResponse("Pro2更新包打包完成。");
callback(null);
} catch (err) {
callback(err);
}
}
//建立一个http服务器,接收API操作
......
......@@ -9,7 +9,6 @@ exec = require('child_process').exec
execFile = require('child_process').execFile
spawn = require('child_process').spawn
spawnSync = require('child_process').spawnSync
_async = require('async')
# ts utility
utility = require './utility.js'
......@@ -91,10 +90,9 @@ loadJSONAsync = require('load-json-file')
util = require("util")
Q = require("q")
YGOProDeck = require('ygopro-deck-encode').default
YGOProYrp = require('ygopro-yrp-encode').YGOProYrp
YGOProMsg = require 'ygopro-msg-encode'
Aragami = require('aragami').Aragami
......@@ -720,17 +718,12 @@ ROOM_ban_player = global.ROOM_ban_player = (name, ip, reason, countadd = 1)->
ROOM_kick = (name, callback)->
found = false
_async.each(ROOM_all, (room, done)->
if !(room and room.established and (name == "all" or name == room.process_pid.toString() or name == room.name))
done()
return
for room in ROOM_all when room and room.established
continue unless name == "all" or name == room.process_pid.toString() or name == room.name
found = true
room.terminate()
done()
, (err)->
callback(null, found)
return
)
callback(null, found)
return
ROOM_player_win = global.ROOM_player_win = (name)->
......@@ -2687,24 +2680,25 @@ load_dialogues = global.load_dialogues = () ->
ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
room=ROOM_all[client.rid]
return unless room and !client.reconnecting
msg = buffer.readInt8(0)
msg_name = ygopro.constants.MSG[msg]
new_buf = await msg_polyfill.polyfillGameMsg(client.actual_version, msg_name, buffer)
msg_inst = info.msg
msg_name = if msg_inst then ygopro.constants.MSG[msg_inst.identifier] else null
new_buf = if msg_name then await msg_polyfill.polyfillGameMsg(client.actual_version, msg_name, buffer) else undefined
if new_buf
buffer = new_buf
return new_buf unless msg_inst
record_last_game_msg = () ->
client.last_game_msg = buffer
client.last_game_msg_title = msg_name
#console.log client.pos, "MSG", msg_name
if msg_name == 'RETRY' and room.recovering
if msg_inst instanceof YGOProMsg.YGOProMsgRetry and room.recovering
room.finish_recover(true)
return true
if settings.modules.retry_handle.enabled
if msg_name == 'RETRY'
if msg_inst instanceof YGOProMsg.YGOProMsgRetry
if !client.retry_count?
client.retry_count = 0
client.retry_count++
log.warn "MSG_RETRY detected", client.name, client.ip, msg, client.retry_count
log.warn "MSG_RETRY detected", client.name, client.ip, msg_inst.identifier, client.retry_count
if settings.modules.retry_handle.max_retry_count and client.retry_count >= settings.modules.retry_handle.max_retry_count
ygopro.stoc_send_chat_to_room(room, client.name + "${retry_too_much_room_part1}" + settings.modules.retry_handle.max_retry_count + "${retry_too_much_room_part2}", ygopro.constants.COLORS.BABYBLUE)
ygopro.stoc_send_chat(client, "${retry_too_much_part1}" + settings.modules.retry_handle.max_retry_count + "${retry_too_much_part2}", ygopro.constants.COLORS.RED)
......@@ -2722,11 +2716,11 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
else
record_last_game_msg()
# log.info(client.name, client.last_game_msg_title)
else if msg_name != 'RETRY'
else if !(msg_inst instanceof YGOProMsg.YGOProMsgRetry)
record_last_game_msg()
# log.info(client.name, client.last_game_msg_title)
if (msg >= 10 and msg < 30) or msg == 132 or (msg >= 140 and msg <= 144) #SELECT和ANNOUNCE开头的消息
if msg_inst instanceof YGOProMsg.YGOProMsgResponseBase #SELECT和ANNOUNCE开头的消息
if room.recovering
response = room.recover_replay.responses.splice(0, 1)[0]
ygopro.ctos_send(server, 'RESPONSE', Buffer.from(response))
......@@ -2739,8 +2733,8 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
#log.info("#{msg_name}等待#{room.waiting_for_player.name}")
#log.info 'MSG', msg_name
if msg_name == 'START'
playertype = buffer.readUInt8(1)
if msg_inst instanceof YGOProMsg.YGOProMsgStart
playertype = msg_inst.playerType
client.is_first = !(playertype & 0xf)
client.lp = room.hostinfo.start_lp
client.card_count = 0 if room.hostinfo.mode != 2
......@@ -2763,12 +2757,12 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
#ygopro.stoc_send_chat_to_room(room, "LP跟踪调试信息: #{client.name} 初始LP #{client.lp}")
if msg_name == 'HINT'
hint_type = buffer.readUInt8(1)
if msg_inst instanceof YGOProMsg.YGOProMsgHint
hint_type = msg_inst.type
if hint_type == 3
client.last_hint_msg = buffer
if msg_name == 'NEW_TURN'
if msg_inst instanceof YGOProMsg.YGOProMsgNewTurn
if client.pos == 0
room.turn++
if room.recovering and room.recover_from_turn <= room.turn
......@@ -2789,8 +2783,8 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
client.surrend_confirm = false
ygopro.stoc_send_chat(client, "${surrender_canceled}", ygopro.constants.COLORS.BABYBLUE)
if msg_name == 'NEW_PHASE'
phase = buffer.readInt16LE(1)
if msg_inst instanceof YGOProMsg.YGOProMsgNewPhase
phase = msg_inst.phase
oppo_pos = if room.hostinfo.mode == 2 then 2 else 1
if client.pos == 0 and room.death == -2 and not (phase == 0x1 and room.turn < 2)
if room.dueling_players[0].lp != room.dueling_players[oppo_pos].lp
......@@ -2801,14 +2795,14 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
room.death = -1
ygopro.stoc_send_chat_to_room(room, "${death_remain_final}", ygopro.constants.COLORS.BABYBLUE)
if msg_name == 'WIN' and client.pos == 0
if msg_inst instanceof YGOProMsg.YGOProMsgWin and client.pos == 0
if room.recovering
room.finish_recover(true)
return true
pos = buffer.readUInt8(1)
pos = msg_inst.player
pos = 1 - pos unless client.is_first or pos == 2 or room.duel_stage != ygopro.constants.DUEL_STAGE.DUELING
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
reason = buffer.readUInt8(2)
reason = msg_inst.type
#log.info {winner: pos, reason: reason}
#room.duels.push {winner: pos, reason: reason}
room.winner = pos
......@@ -2832,42 +2826,42 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
else
room.death = 5
if msg_name == 'MATCH_KILL' and client.pos == 0
if msg_inst instanceof YGOProMsg.YGOProMsgMatchKill and client.pos == 0
room.match_kill = true
#lp跟踪
if msg_name == 'DAMAGE' and client.pos == 0
pos = buffer.readUInt8(1)
if msg_inst instanceof YGOProMsg.YGOProMsgDamage and client.pos == 0
pos = msg_inst.player
pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2)
val = msg_inst.value
if room.dueling_players[pos]
room.dueling_players[pos].lp -= val
room.dueling_players[pos].lp = 0 if room.dueling_players[pos].lp < 0
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
pos = buffer.readUInt8(1)
if msg_inst instanceof YGOProMsg.YGOProMsgRecover and client.pos == 0
pos = msg_inst.player
pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2)
val = msg_inst.value
if room.dueling_players[pos]
room.dueling_players[pos].lp += val
if msg_name == 'LPUPDATE' and client.pos == 0
pos = buffer.readUInt8(1)
if msg_inst instanceof YGOProMsg.YGOProMsgLpUpdate and client.pos == 0
pos = msg_inst.player
pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2)
val = msg_inst.lp
if room.dueling_players[pos]
room.dueling_players[pos].lp = val
if msg_name == 'PAY_LPCOST' and client.pos == 0
pos = buffer.readUInt8(1)
if msg_inst instanceof YGOProMsg.YGOProMsgPayLpCost and client.pos == 0
pos = msg_inst.player
pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2)
val = msg_inst.cost
if room.dueling_players[pos]
room.dueling_players[pos].lp -= val
room.dueling_players[pos].lp = 0 if room.dueling_players[pos].lp < 0
......@@ -2876,32 +2870,30 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
#track card count
#todo: track card count in tag mode
if msg_name == 'MOVE' and room.hostinfo.mode != 2
pos = buffer.readUInt8(5)
if msg_inst instanceof YGOProMsg.YGOProMsgMove and room.hostinfo.mode != 2
pos = msg_inst.previous.controller
pos = 1 - pos unless client.is_first
loc = buffer.readUInt8(6)
loc = msg_inst.previous.location
client.card_count-- if (loc & 0xe) and pos == 0
pos = buffer.readUInt8(9)
pos = msg_inst.current.controller
pos = 1 - pos unless client.is_first
loc = buffer.readUInt8(10)
loc = msg_inst.current.location
client.card_count++ if (loc & 0xe) and pos == 0
if msg_name == 'DRAW' and room.hostinfo.mode != 2
pos = buffer.readUInt8(1)
if msg_inst instanceof YGOProMsg.YGOProMsgDraw and room.hostinfo.mode != 2
pos = msg_inst.player
pos = 1 - pos unless client.is_first
if pos == 0
count = buffer.readInt8(2)
count = msg_inst.count
client.card_count += count
# check panel confirming cards in heartbeat
if settings.modules.heartbeat_detection.enabled and msg_name == 'CONFIRM_CARDS'
if settings.modules.heartbeat_detection.enabled and msg_inst instanceof YGOProMsg.YGOProMsgConfirmCards
check = false
count = buffer.readInt8(2)
max_loop = 3 + (count - 1) * 7
deck_found = 0
limbo_found = 0 # support custom cards which may be in location 0 in KoishiPro or EdoPro
for i in [3..max_loop] by 7
loc = buffer.readInt8(i + 5)
for card in msg_inst.cards
loc = card.location
if (loc & 0x41) > 0
deck_found++
else if loc == 0
......@@ -2915,8 +2907,8 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
# chain detection
if settings.modules.heartbeat_detection.enabled and client.pos == 0
if msg_name == 'CHAINING'
card = buffer.readUInt32LE(1)
if msg_inst instanceof YGOProMsg.YGOProMsgChaining
card = msg_inst.code
found = false
for id in long_resolve_cards when id == card
found = true
......@@ -2926,46 +2918,46 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
# console.log(0,card)
else
delete room.long_resolve_card
else if msg_name == 'CHAINED' and room.long_resolve_card
chain = buffer.readInt8(1)
else if msg_inst instanceof YGOProMsg.YGOProMsgChained and room.long_resolve_card
chain = msg_inst.chainCount
if !room.long_resolve_chain
room.long_resolve_chain = []
room.long_resolve_chain[chain] = true
# console.log(1,chain)
delete room.long_resolve_card
else if msg_name == 'CHAIN_SOLVING' and room.long_resolve_chain
chain = buffer.readInt8(1)
else if msg_inst instanceof YGOProMsg.YGOProMsgChainSolving and room.long_resolve_chain
chain = msg_inst.chainCount
# console.log(2,chain)
if room.long_resolve_chain[chain]
for player in room.get_playing_player()
player.heartbeat_protected = true
else if (msg_name == 'CHAIN_NEGATED' or msg_name == 'CHAIN_DISABLED') and room.long_resolve_chain
chain = buffer.readInt8(1)
else if (msg_inst instanceof YGOProMsg.YGOProMsgChainNegated or msg_inst instanceof YGOProMsg.YGOProMsgChainDisabled) and room.long_resolve_chain
chain = msg_inst.chainCount
# console.log(3,chain)
delete room.long_resolve_chain[chain]
else if msg_name == 'CHAIN_END'
else if msg_inst instanceof YGOProMsg.YGOProMsgChainEnd
# console.log(4,chain)
delete room.long_resolve_card
delete room.long_resolve_chain
#登场台词
if settings.modules.dialogues.enabled and !room.recovering
if msg_name == 'SUMMONING' or msg_name == 'SPSUMMONING' or msg_name == 'CHAINING'
card = buffer.readUInt32LE(1)
trigger_location = buffer.readUInt8(6)
if msg_inst instanceof YGOProMsg.YGOProMsgSummoning or msg_inst instanceof YGOProMsg.YGOProMsgSpSummoning or msg_inst instanceof YGOProMsg.YGOProMsgChaining
card = msg_inst.code
trigger_location = msg_inst.location
if dialogues.dialogues[card] and (msg_name != 'CHAINING' or (trigger_location & 0x8) and client.ready_trap)
for line in _.lines dialogues.dialogues[card][Math.floor(Math.random() * dialogues.dialogues[card].length)]
ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK)
if msg_name == 'POS_CHANGE'
loc = buffer.readUInt8(6)
ppos = buffer.readUInt8(8)
cpos = buffer.readUInt8(9)
if msg_inst instanceof YGOProMsg.YGOProMsgPosChange
loc = msg_inst.card.location
ppos = msg_inst.previousPosition
cpos = msg_inst.currentPosition
client.ready_trap = !!(loc & 0x8) and !!(ppos & 0xa) and !!(cpos & 0x5)
else if msg_name != 'UPDATE_CARD' and msg_name != 'WAITING'
else if !(msg_inst instanceof YGOProMsg.YGOProMsgUpdateCard) and !(msg_inst instanceof YGOProMsg.YGOProMsgWaiting)
client.ready_trap = false
if room.recovering and client.pos < 4
if msg_name != 'WAITING'
if !(msg_inst instanceof YGOProMsg.YGOProMsgWaiting)
room.recover_buffers[client.pos].push(buffer)
return true
......@@ -3391,8 +3383,6 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
else
ygopro.stoc_send_chat(client, "${get_chat_color_default}", ygopro.constants.COLORS.BABYBLUE)
#when '/test'
# ygopro.stoc_send_hint_card_to_room(room, 2333365)
if (msg.length>100)
log.warn "SPAM WORD", client.name, client.ip, msg
client.abuse_count=client.abuse_count+2 if client.abuse_count
......@@ -3902,10 +3892,7 @@ if true
response.end(addCallback(u.query.callback, '{"rooms":[{"roomid":"0","roomname":"密码错误","needpass":"true"}]}'))
else
roomsjson = [];
_async.each(ROOM_all, (room, done)->
if !(room and room.established)
done()
return
for room in ROOM_all when room and room.established
roomsjson.push({
roomid: room.process_pid.toString(),
roomname: if pass_validated then room.name else room.name.split('$', 2)[0],
......@@ -3924,11 +3911,8 @@ if true
), "pos"),
istart: if room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN then (if settings.modules.http.show_info then ("Duel:" + room.duel_count + " " + (if room.duel_stage == ygopro.constants.DUEL_STAGE.SIDING then "Siding" else "Turn:" + (if room.turn? then room.turn else 0) + (if room.death then "/" + (if room.death > 0 then room.death - 1 else "Death") else ""))) else 'start') else 'wait'
})
done()
, ()->
response.writeHead(200)
response.end(addCallback(u.query.callback, JSON.stringify({rooms: roomsjson})))
)
response.writeHead(200)
response.end(addCallback(u.query.callback, JSON.stringify({rooms: roomsjson})))
else if u.pathname == '/api/duellog' and settings.modules.mysql.enabled
......@@ -4015,9 +3999,8 @@ if true
response.writeHead(200)
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
_async.each ROOM_all, (room)->
if room and room.established
ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW)
for room in ROOM_all when room and room.established
ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW)
response.writeHead(200)
response.end(addCallback(u.query.callback, "['shout ok', '" + u.query.shout + "']"))
......@@ -4115,21 +4098,15 @@ if true
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
death_room_found = false
_async.each(ROOM_all, (room, done)->
if !(room and (u.query.death == "all" or u.query.death == room.process_pid.toString() or u.query.death == room.name))
done()
return
for room in ROOM_all when room
continue unless u.query.death == "all" or u.query.death == room.process_pid.toString() or u.query.death == room.name
if room.start_death()
death_room_found = true
done()
return
, () ->
response.writeHead(200)
if death_room_found
response.end(addCallback(u.query.callback, "['death ok', '" + u.query.death + "']"))
else
response.end(addCallback(u.query.callback, "['room not found', '" + u.query.death + "']"))
)
response.writeHead(200)
if death_room_found
response.end(addCallback(u.query.callback, "['death ok', '" + u.query.death + "']"))
else
response.end(addCallback(u.query.callback, "['room not found', '" + u.query.death + "']"))
else if u.query.deathcancel
if !await auth.auth(u.query.username, u.query.pass, "start_death", "cancel_death")
......@@ -4137,20 +4114,15 @@ if true
response.end(addCallback(u.query.callback, "['密码错误', 0]"))
return
death_room_found = false
_async.each(ROOM_all, (room, done)->
if !(room and (u.query.deathcancel == "all" or u.query.deathcancel == room.process_pid.toString() or u.query.deathcancel == room.name))
done()
return
for room in ROOM_all when room
continue unless u.query.deathcancel == "all" or u.query.deathcancel == room.process_pid.toString() or u.query.deathcancel == room.name
if room.cancel_death()
death_room_found = true
done()
, () ->
response.writeHead(200)
if death_room_found
response.end(addCallback(u.query.callback, "['death cancel ok', '" + u.query.deathcancel + "']"))
else
response.end(addCallback(u.query.callback, "['room not found', '" + u.query.deathcancel + "']"))
)
response.writeHead(200)
if death_room_found
response.end(addCallback(u.query.callback, "['death cancel ok', '" + u.query.deathcancel + "']"))
else
response.end(addCallback(u.query.callback, "['room not found', '" + u.query.deathcancel + "']"))
else if u.query.reboot
if !await auth.auth(u.query.username, u.query.pass, "stop", "reboot")
......
// Generated by CoffeeScript 2.7.0
(function() {
// 标准库
var Aragami, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_kick_reconnect, CLIENT_is_able_to_reconnect, CLIENT_is_banned_by_mc, CLIENT_is_player, CLIENT_kick, CLIENT_kick_reconnect, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, CLIENT_send_replays, CLIENT_send_replays_and_kick, CLIENT_set_ip, PQueue, Q, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_pid, ROOM_find_by_port, ROOM_find_by_title, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_kick, ROOM_player_flee, ROOM_player_get_score, ROOM_player_lose, ROOM_player_win, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, ReplayParser, ResolveData, Room, SERVER_clear_disconnect, SERVER_kick, SOCKET_flush_data, YGOProDeck, YGOProYrp, _, _async, addCallback, aragami, aragami_classes, athleticChecker, auth, axios, badwordR, badwords, ban_user, bunyan, call_match_api, challonge, checkFileExists, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, extra_mode_list, fs, geoip, getDuelLogQueryFromQs, getRealIp, get_memory_usage, http, httpRequestListener, importOldConfig, import_datas, init, ip6addr, isTrustedProxy, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_tips, log, long_resolve_cards, memory_usage, merge, moment, moment_long_ago_string, moment_now, moment_now_string, msg_polyfill, neosRequestListener, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, release_disconnect, report_to_big_brother, request, roomlist, rooms_count, setting_change, setting_get, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, toIpv4, toIpv6, util, utility, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, ygopro, zlib;
var Aragami, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_kick_reconnect, CLIENT_is_able_to_reconnect, CLIENT_is_banned_by_mc, CLIENT_is_player, CLIENT_kick, CLIENT_kick_reconnect, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, CLIENT_send_replays, CLIENT_send_replays_and_kick, CLIENT_set_ip, PQueue, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_pid, ROOM_find_by_port, ROOM_find_by_title, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_kick, ROOM_player_flee, ROOM_player_get_score, ROOM_player_lose, ROOM_player_win, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, ReplayParser, ResolveData, Room, SERVER_clear_disconnect, SERVER_kick, SOCKET_flush_data, YGOProDeck, YGOProMsg, YGOProYrp, _, addCallback, aragami, aragami_classes, athleticChecker, auth, axios, badwordR, badwords, ban_user, bunyan, call_match_api, challonge, checkFileExists, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, extra_mode_list, fs, geoip, getDuelLogQueryFromQs, getRealIp, get_memory_usage, http, httpRequestListener, importOldConfig, import_datas, init, ip6addr, isTrustedProxy, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_tips, log, long_resolve_cards, memory_usage, merge, moment, moment_long_ago_string, moment_now, moment_now_string, msg_polyfill, neosRequestListener, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, release_disconnect, report_to_big_brother, request, roomlist, rooms_count, setting_change, setting_get, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, toIpv4, toIpv6, util, utility, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, ygopro, zlib;
net = require('net');
......@@ -23,8 +23,6 @@
spawnSync = require('child_process').spawnSync;
_async = require('async');
// ts utility
utility = require('./utility.js');
......@@ -81,12 +79,12 @@
util = require("util");
Q = require("q");
YGOProDeck = require('ygopro-deck-encode').default;
YGOProYrp = require('ygopro-yrp-encode').YGOProYrp;
YGOProMsg = require('ygopro-msg-encode');
Aragami = require('aragami').Aragami;
aragami = global.aragami = new Aragami(); // we use memory mode only
......@@ -934,19 +932,20 @@
};
ROOM_kick = function(name, callback) {
var found;
var found, j, len, room;
found = false;
return _async.each(ROOM_all, function(room, done) {
if (!(room && room.established && (name === "all" || name === room.process_pid.toString() || name === room.name))) {
done();
return;
for (j = 0, len = ROOM_all.length; j < len; j++) {
room = ROOM_all[j];
if (!(room && room.established)) {
continue;
}
if (!(name === "all" || name === room.process_pid.toString() || name === room.name)) {
continue;
}
found = true;
room.terminate();
return done();
}, function(err) {
callback(null, found);
});
}
callback(null, found);
};
ROOM_player_win = global.ROOM_player_win = async function(name) {
......@@ -3517,33 +3516,36 @@
};
ygopro.stoc_follow('GAME_MSG', true, async function(buffer, info, client, server, datas) {
var card, chain, check, count, cpos, deck_found, found, hint_type, i, id, j, l, len, len1, len2, len3, limbo_found, line, loc, m, max_loop, msg, msg_name, n, new_buf, o, oppo_pos, phase, player, playertype, pos, ppos, reason, record_last_game_msg, ref, ref1, ref2, ref3, ref4, ref5, response, room, trigger_location, val, win_pos;
var card, chain, check, count, cpos, deck_found, found, hint_type, id, j, l, len, len1, len2, len3, len4, limbo_found, line, loc, m, msg_inst, msg_name, n, new_buf, o, oppo_pos, phase, player, playertype, pos, ppos, reason, record_last_game_msg, ref, ref1, ref2, ref3, ref4, ref5, response, room, trigger_location, val, win_pos;
room = ROOM_all[client.rid];
if (!(room && !client.reconnecting)) {
return;
}
msg = buffer.readInt8(0);
msg_name = ygopro.constants.MSG[msg];
new_buf = (await msg_polyfill.polyfillGameMsg(client.actual_version, msg_name, buffer));
msg_inst = info.msg;
msg_name = msg_inst ? ygopro.constants.MSG[msg_inst.identifier] : null;
new_buf = msg_name ? (await msg_polyfill.polyfillGameMsg(client.actual_version, msg_name, buffer)) : void 0;
if (new_buf) {
buffer = new_buf;
}
if (!msg_inst) {
return new_buf;
}
record_last_game_msg = function() {
client.last_game_msg = buffer;
return client.last_game_msg_title = msg_name;
};
//console.log client.pos, "MSG", msg_name
if (msg_name === 'RETRY' && room.recovering) {
if (msg_inst instanceof YGOProMsg.YGOProMsgRetry && room.recovering) {
room.finish_recover(true);
return true;
}
if (settings.modules.retry_handle.enabled) {
if (msg_name === 'RETRY') {
if (msg_inst instanceof YGOProMsg.YGOProMsgRetry) {
if (client.retry_count == null) {
client.retry_count = 0;
}
client.retry_count++;
log.warn("MSG_RETRY detected", client.name, client.ip, msg, client.retry_count);
log.warn("MSG_RETRY detected", client.name, client.ip, msg_inst.identifier, client.retry_count);
if (settings.modules.retry_handle.max_retry_count && client.retry_count >= settings.modules.retry_handle.max_retry_count) {
ygopro.stoc_send_chat_to_room(room, client.name + "${retry_too_much_room_part1}" + settings.modules.retry_handle.max_retry_count + "${retry_too_much_room_part2}", ygopro.constants.COLORS.BABYBLUE);
ygopro.stoc_send_chat(client, "${retry_too_much_part1}" + settings.modules.retry_handle.max_retry_count + "${retry_too_much_part2}", ygopro.constants.COLORS.RED);
......@@ -3565,12 +3567,11 @@
} else {
record_last_game_msg();
}
// log.info(client.name, client.last_game_msg_title)
} else if (msg_name !== 'RETRY') {
} else if (!(msg_inst instanceof YGOProMsg.YGOProMsgRetry)) {
record_last_game_msg();
}
// log.info(client.name, client.last_game_msg_title)
if ((msg >= 10 && msg < 30) || msg === 132 || (msg >= 140 && msg <= 144)) { //SELECT和ANNOUNCE开头的消息
if (msg_inst instanceof YGOProMsg.YGOProMsgResponseBase) { //SELECT和ANNOUNCE开头的消息
if (room.recovering) {
response = room.recover_replay.responses.splice(0, 1)[0];
ygopro.ctos_send(server, 'RESPONSE', Buffer.from(response));
......@@ -3586,8 +3587,8 @@
//log.info("#{msg_name}等待#{room.waiting_for_player.name}")
//log.info 'MSG', msg_name
if (msg_name === 'START') {
playertype = buffer.readUInt8(1);
if (msg_inst instanceof YGOProMsg.YGOProMsgStart) {
playertype = msg_inst.playerType;
client.is_first = !(playertype & 0xf);
client.lp = room.hostinfo.start_lp;
if (room.hostinfo.mode !== 2) {
......@@ -3617,13 +3618,13 @@
}
}
//ygopro.stoc_send_chat_to_room(room, "LP跟踪调试信息: #{client.name} 初始LP #{client.lp}")
if (msg_name === 'HINT') {
hint_type = buffer.readUInt8(1);
if (msg_inst instanceof YGOProMsg.YGOProMsgHint) {
hint_type = msg_inst.type;
if (hint_type === 3) {
client.last_hint_msg = buffer;
}
}
if (msg_name === 'NEW_TURN') {
if (msg_inst instanceof YGOProMsg.YGOProMsgNewTurn) {
if (client.pos === 0) {
room.turn++;
if (room.recovering && room.recover_from_turn <= room.turn) {
......@@ -3650,8 +3651,8 @@
ygopro.stoc_send_chat(client, "${surrender_canceled}", ygopro.constants.COLORS.BABYBLUE);
}
}
if (msg_name === 'NEW_PHASE') {
phase = buffer.readInt16LE(1);
if (msg_inst instanceof YGOProMsg.YGOProMsgNewPhase) {
phase = msg_inst.phase;
oppo_pos = room.hostinfo.mode === 2 ? 2 : 1;
if (client.pos === 0 && room.death === -2 && !(phase === 0x1 && room.turn < 2)) {
if (room.dueling_players[0].lp !== room.dueling_players[oppo_pos].lp) {
......@@ -3664,19 +3665,19 @@
}
}
}
if (msg_name === 'WIN' && client.pos === 0) {
if (msg_inst instanceof YGOProMsg.YGOProMsgWin && client.pos === 0) {
if (room.recovering) {
room.finish_recover(true);
return true;
}
pos = buffer.readUInt8(1);
pos = msg_inst.player;
if (!(client.is_first || pos === 2 || room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING)) {
pos = 1 - pos;
}
if (pos >= 0 && room.hostinfo.mode === 2) {
pos = pos * 2;
}
reason = buffer.readUInt8(2);
reason = msg_inst.type;
//log.info {winner: pos, reason: reason}
//room.duels.push {winner: pos, reason: reason}
room.winner = pos;
......@@ -3708,19 +3709,19 @@
}
}
}
if (msg_name === 'MATCH_KILL' && client.pos === 0) {
if (msg_inst instanceof YGOProMsg.YGOProMsgMatchKill && client.pos === 0) {
room.match_kill = true;
}
//lp跟踪
if (msg_name === 'DAMAGE' && client.pos === 0) {
pos = buffer.readUInt8(1);
if (msg_inst instanceof YGOProMsg.YGOProMsgDamage && client.pos === 0) {
pos = msg_inst.player;
if (!client.is_first) {
pos = 1 - pos;
}
if (pos >= 0 && room.hostinfo.mode === 2) {
pos = pos * 2;
}
val = buffer.readInt32LE(2);
val = msg_inst.value;
if (room.dueling_players[pos]) {
room.dueling_players[pos].lp -= val;
if (room.dueling_players[pos].lp < 0) {
......@@ -3731,41 +3732,41 @@
}
}
}
if (msg_name === 'RECOVER' && client.pos === 0) {
pos = buffer.readUInt8(1);
if (msg_inst instanceof YGOProMsg.YGOProMsgRecover && client.pos === 0) {
pos = msg_inst.player;
if (!client.is_first) {
pos = 1 - pos;
}
if (pos >= 0 && room.hostinfo.mode === 2) {
pos = pos * 2;
}
val = buffer.readInt32LE(2);
val = msg_inst.value;
if (room.dueling_players[pos]) {
room.dueling_players[pos].lp += val;
}
}
if (msg_name === 'LPUPDATE' && client.pos === 0) {
pos = buffer.readUInt8(1);
if (msg_inst instanceof YGOProMsg.YGOProMsgLpUpdate && client.pos === 0) {
pos = msg_inst.player;
if (!client.is_first) {
pos = 1 - pos;
}
if (pos >= 0 && room.hostinfo.mode === 2) {
pos = pos * 2;
}
val = buffer.readInt32LE(2);
val = msg_inst.lp;
if (room.dueling_players[pos]) {
room.dueling_players[pos].lp = val;
}
}
if (msg_name === 'PAY_LPCOST' && client.pos === 0) {
pos = buffer.readUInt8(1);
if (msg_inst instanceof YGOProMsg.YGOProMsgPayLpCost && client.pos === 0) {
pos = msg_inst.player;
if (!client.is_first) {
pos = 1 - pos;
}
if (pos >= 0 && room.hostinfo.mode === 2) {
pos = pos * 2;
}
val = buffer.readInt32LE(2);
val = msg_inst.cost;
if (room.dueling_players[pos]) {
room.dueling_players[pos].lp -= val;
if (room.dueling_players[pos].lp < 0) {
......@@ -3778,43 +3779,43 @@
}
//track card count
//todo: track card count in tag mode
if (msg_name === 'MOVE' && room.hostinfo.mode !== 2) {
pos = buffer.readUInt8(5);
if (msg_inst instanceof YGOProMsg.YGOProMsgMove && room.hostinfo.mode !== 2) {
pos = msg_inst.previous.controller;
if (!client.is_first) {
pos = 1 - pos;
}
loc = buffer.readUInt8(6);
loc = msg_inst.previous.location;
if ((loc & 0xe) && pos === 0) {
client.card_count--;
}
pos = buffer.readUInt8(9);
pos = msg_inst.current.controller;
if (!client.is_first) {
pos = 1 - pos;
}
loc = buffer.readUInt8(10);
loc = msg_inst.current.location;
if ((loc & 0xe) && pos === 0) {
client.card_count++;
}
}
if (msg_name === 'DRAW' && room.hostinfo.mode !== 2) {
pos = buffer.readUInt8(1);
if (msg_inst instanceof YGOProMsg.YGOProMsgDraw && room.hostinfo.mode !== 2) {
pos = msg_inst.player;
if (!client.is_first) {
pos = 1 - pos;
}
if (pos === 0) {
count = buffer.readInt8(2);
count = msg_inst.count;
client.card_count += count;
}
}
// check panel confirming cards in heartbeat
if (settings.modules.heartbeat_detection.enabled && msg_name === 'CONFIRM_CARDS') {
if (settings.modules.heartbeat_detection.enabled && msg_inst instanceof YGOProMsg.YGOProMsgConfirmCards) {
check = false;
count = buffer.readInt8(2);
max_loop = 3 + (count - 1) * 7;
deck_found = 0;
limbo_found = 0; // support custom cards which may be in location 0 in KoishiPro or EdoPro
for (i = l = 3, ref3 = max_loop; l <= ref3; i = l += 7) {
loc = buffer.readInt8(i + 5);
ref3 = msg_inst.cards;
for (l = 0, len1 = ref3.length; l < len1; l++) {
card = ref3[l];
loc = card.location;
if ((loc & 0x41) > 0) {
deck_found++;
} else if (loc === 0) {
......@@ -3832,10 +3833,10 @@
}
// chain detection
if (settings.modules.heartbeat_detection.enabled && client.pos === 0) {
if (msg_name === 'CHAINING') {
card = buffer.readUInt32LE(1);
if (msg_inst instanceof YGOProMsg.YGOProMsgChaining) {
card = msg_inst.code;
found = false;
for (m = 0, len1 = long_resolve_cards.length; m < len1; m++) {
for (m = 0, len2 = long_resolve_cards.length; m < len2; m++) {
id = long_resolve_cards[m];
if (!(id === card)) {
continue;
......@@ -3849,29 +3850,29 @@
// console.log(0,card)
delete room.long_resolve_card;
}
} else if (msg_name === 'CHAINED' && room.long_resolve_card) {
chain = buffer.readInt8(1);
} else if (msg_inst instanceof YGOProMsg.YGOProMsgChained && room.long_resolve_card) {
chain = msg_inst.chainCount;
if (!room.long_resolve_chain) {
room.long_resolve_chain = [];
}
room.long_resolve_chain[chain] = true;
// console.log(1,chain)
delete room.long_resolve_card;
} else if (msg_name === 'CHAIN_SOLVING' && room.long_resolve_chain) {
chain = buffer.readInt8(1);
} else if (msg_inst instanceof YGOProMsg.YGOProMsgChainSolving && room.long_resolve_chain) {
chain = msg_inst.chainCount;
// console.log(2,chain)
if (room.long_resolve_chain[chain]) {
ref4 = room.get_playing_player();
for (n = 0, len2 = ref4.length; n < len2; n++) {
for (n = 0, len3 = ref4.length; n < len3; n++) {
player = ref4[n];
player.heartbeat_protected = true;
}
}
} else if ((msg_name === 'CHAIN_NEGATED' || msg_name === 'CHAIN_DISABLED') && room.long_resolve_chain) {
chain = buffer.readInt8(1);
} else if ((msg_inst instanceof YGOProMsg.YGOProMsgChainNegated || msg_inst instanceof YGOProMsg.YGOProMsgChainDisabled) && room.long_resolve_chain) {
chain = msg_inst.chainCount;
// console.log(3,chain)
delete room.long_resolve_chain[chain];
} else if (msg_name === 'CHAIN_END') {
} else if (msg_inst instanceof YGOProMsg.YGOProMsgChainEnd) {
// console.log(4,chain)
delete room.long_resolve_card;
delete room.long_resolve_chain;
......@@ -3879,28 +3880,28 @@
}
//登场台词
if (settings.modules.dialogues.enabled && !room.recovering) {
if (msg_name === 'SUMMONING' || msg_name === 'SPSUMMONING' || msg_name === 'CHAINING') {
card = buffer.readUInt32LE(1);
trigger_location = buffer.readUInt8(6);
if (msg_inst instanceof YGOProMsg.YGOProMsgSummoning || msg_inst instanceof YGOProMsg.YGOProMsgSpSummoning || msg_inst instanceof YGOProMsg.YGOProMsgChaining) {
card = msg_inst.code;
trigger_location = msg_inst.location;
if (dialogues.dialogues[card] && (msg_name !== 'CHAINING' || (trigger_location & 0x8) && client.ready_trap)) {
ref5 = _.lines(dialogues.dialogues[card][Math.floor(Math.random() * dialogues.dialogues[card].length)]);
for (o = 0, len3 = ref5.length; o < len3; o++) {
for (o = 0, len4 = ref5.length; o < len4; o++) {
line = ref5[o];
ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK);
}
}
}
if (msg_name === 'POS_CHANGE') {
loc = buffer.readUInt8(6);
ppos = buffer.readUInt8(8);
cpos = buffer.readUInt8(9);
if (msg_inst instanceof YGOProMsg.YGOProMsgPosChange) {
loc = msg_inst.card.location;
ppos = msg_inst.previousPosition;
cpos = msg_inst.currentPosition;
client.ready_trap = !!(loc & 0x8) && !!(ppos & 0xa) && !!(cpos & 0x5);
} else if (msg_name !== 'UPDATE_CARD' && msg_name !== 'WAITING') {
} else if (!(msg_inst instanceof YGOProMsg.YGOProMsgUpdateCard) && !(msg_inst instanceof YGOProMsg.YGOProMsgWaiting)) {
client.ready_trap = false;
}
}
if (room.recovering && client.pos < 4) {
if (msg_name !== 'WAITING') {
if (!(msg_inst instanceof YGOProMsg.YGOProMsgWaiting)) {
room.recover_buffers[client.pos].push(buffer);
}
return true;
......@@ -4538,8 +4539,6 @@
}
}
}
//when '/test'
// ygopro.stoc_send_hint_card_to_room(room, 2333365)
if (msg.length > 100) {
log.warn("SPAM WORD", client.name, client.ip, msg);
if (client.abuse_count) {
......@@ -5197,7 +5196,7 @@
return callback + "( " + text + " );";
};
httpRequestListener = async function(request, response) {
var allowHeaders, archiveStream, base, buffer, death_room_found, duellog, e, err, error, filename, getpath, parseQueryString, pass_validated, requestHeaders, roomsjson, success, u, urlObj;
var allowHeaders, archiveStream, base, buffer, death_room_found, duellog, e, err, error, filename, getpath, j, l, len, len1, len2, len3, m, n, parseQueryString, pass_validated, player, requestHeaders, room, roomsjson, success, u, urlObj;
parseQueryString = true;
base = `http://${request.headers.host || 'localhost'}`;
urlObj = new URL(request.url, base);
......@@ -5232,48 +5231,44 @@
response.end(addCallback(u.query.callback, '{"rooms":[{"roomid":"0","roomname":"密码错误","needpass":"true"}]}'));
} else {
roomsjson = [];
_async.each(ROOM_all, function(room, done) {
var player;
if (!(room && room.established)) {
done();
return;
}
roomsjson.push({
roomid: room.process_pid.toString(),
roomname: pass_validated ? room.name : room.name.split('$', 2)[0],
roommode: room.hostinfo.mode,
needpass: (room.name.indexOf('$') !== -1).toString(),
users: _.sortBy((function() {
var j, len, ref, results;
ref = room.players;
results = [];
for (j = 0, len = ref.length; j < len; j++) {
player = ref[j];
if (player.pos != null) {
results.push({
id: (-1).toString(),
name: player.name,
ip: settings.modules.http.show_ip && pass_validated && !player.is_local ? toIpv4(player.ip) : null,
status: settings.modules.http.show_info && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && player.pos !== 7 ? {
score: room.scores[player.name_vpass],
lp: player.lp != null ? player.lp : room.hostinfo.start_lp,
cards: room.hostinfo.mode !== 2 ? (player.card_count != null ? player.card_count : room.hostinfo.start_hand) : null
} : null,
pos: player.pos
});
for (j = 0, len = ROOM_all.length; j < len; j++) {
room = ROOM_all[j];
if (room && room.established) {
roomsjson.push({
roomid: room.process_pid.toString(),
roomname: pass_validated ? room.name : room.name.split('$', 2)[0],
roommode: room.hostinfo.mode,
needpass: (room.name.indexOf('$') !== -1).toString(),
users: _.sortBy((function() {
var l, len1, ref, results;
ref = room.players;
results = [];
for (l = 0, len1 = ref.length; l < len1; l++) {
player = ref[l];
if (player.pos != null) {
results.push({
id: (-1).toString(),
name: player.name,
ip: settings.modules.http.show_ip && pass_validated && !player.is_local ? toIpv4(player.ip) : null,
status: settings.modules.http.show_info && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && player.pos !== 7 ? {
score: room.scores[player.name_vpass],
lp: player.lp != null ? player.lp : room.hostinfo.start_lp,
cards: room.hostinfo.mode !== 2 ? (player.card_count != null ? player.card_count : room.hostinfo.start_hand) : null
} : null,
pos: player.pos
});
}
}
}
return results;
})(), "pos"),
istart: room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN ? (settings.modules.http.show_info ? "Duel:" + room.duel_count + " " + (room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING ? "Siding" : "Turn:" + (room.turn != null ? room.turn : 0) + (room.death ? "/" + (room.death > 0 ? room.death - 1 : "Death") : "")) : 'start') : 'wait'
});
return done();
}, function() {
response.writeHead(200);
return response.end(addCallback(u.query.callback, JSON.stringify({
rooms: roomsjson
})));
});
return results;
})(), "pos"),
istart: room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN ? (settings.modules.http.show_info ? "Duel:" + room.duel_count + " " + (room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING ? "Siding" : "Turn:" + (room.turn != null ? room.turn : 0) + (room.death ? "/" + (room.death > 0 ? room.death - 1 : "Death") : "")) : 'start') : 'wait'
});
}
}
response.writeHead(200);
response.end(addCallback(u.query.callback, JSON.stringify({
rooms: roomsjson
})));
}
} else if (u.pathname === '/api/duellog' && settings.modules.mysql.enabled) {
if (!(await auth.auth(u.query.username, u.query.pass, "duel_log", "duel_log"))) {
......@@ -5377,11 +5372,12 @@
response.end(addCallback(u.query.callback, "['密码错误', 0]"));
return;
}
_async.each(ROOM_all, function(room) {
for (l = 0, len1 = ROOM_all.length; l < len1; l++) {
room = ROOM_all[l];
if (room && room.established) {
return ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW);
ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW);
}
});
}
response.writeHead(200);
response.end(addCallback(u.query.callback, "['shout ok', '" + u.query.shout + "']"));
} else if (u.query.stop) {
......@@ -5488,23 +5484,24 @@
return;
}
death_room_found = false;
_async.each(ROOM_all, function(room, done) {
if (!(room && (u.query.death === "all" || u.query.death === room.process_pid.toString() || u.query.death === room.name))) {
done();
return;
for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[m];
if (!(room)) {
continue;
}
if (!(u.query.death === "all" || u.query.death === room.process_pid.toString() || u.query.death === room.name)) {
continue;
}
if (room.start_death()) {
death_room_found = true;
}
done();
}, function() {
response.writeHead(200);
if (death_room_found) {
return response.end(addCallback(u.query.callback, "['death ok', '" + u.query.death + "']"));
} else {
return response.end(addCallback(u.query.callback, "['room not found', '" + u.query.death + "']"));
}
});
}
response.writeHead(200);
if (death_room_found) {
response.end(addCallback(u.query.callback, "['death ok', '" + u.query.death + "']"));
} else {
response.end(addCallback(u.query.callback, "['room not found', '" + u.query.death + "']"));
}
} else if (u.query.deathcancel) {
if (!(await auth.auth(u.query.username, u.query.pass, "start_death", "cancel_death"))) {
response.writeHead(200);
......@@ -5512,23 +5509,24 @@
return;
}
death_room_found = false;
_async.each(ROOM_all, function(room, done) {
if (!(room && (u.query.deathcancel === "all" || u.query.deathcancel === room.process_pid.toString() || u.query.deathcancel === room.name))) {
done();
return;
for (n = 0, len3 = ROOM_all.length; n < len3; n++) {
room = ROOM_all[n];
if (!(room)) {
continue;
}
if (!(u.query.deathcancel === "all" || u.query.deathcancel === room.process_pid.toString() || u.query.deathcancel === room.name)) {
continue;
}
if (room.cancel_death()) {
death_room_found = true;
}
return done();
}, function() {
response.writeHead(200);
if (death_room_found) {
return response.end(addCallback(u.query.callback, "['death cancel ok', '" + u.query.deathcancel + "']"));
} else {
return response.end(addCallback(u.query.callback, "['room not found', '" + u.query.deathcancel + "']"));
}
});
}
response.writeHead(200);
if (death_room_found) {
response.end(addCallback(u.query.callback, "['death cancel ok', '" + u.query.deathcancel + "']"));
} else {
response.end(addCallback(u.query.callback, "['room not found', '" + u.query.deathcancel + "']"));
}
} else if (u.query.reboot) {
if (!(await auth.auth(u.query.username, u.query.pass, "stop", "reboot"))) {
response.writeHead(200);
......
......@@ -51,7 +51,6 @@ const axios_1 = __importDefault(require("axios"));
const formidable = __importStar(require("formidable"));
const load_json_file_1 = require("load-json-file");
const challonge_1 = require("./challonge");
const asyncLib = __importStar(require("async"));
const ygopro_deck_encode_1 = __importDefault(require("ygopro-deck-encode"));
const auth = __importStar(require("./ygopro-auth"));
const underscore_1 = __importDefault(require("underscore"));
......@@ -114,27 +113,21 @@ const readDeck = async function (deck_name, deck_full_path) {
return deck;
};
//读取指定文件夹中所有卡组
const getDecks = function (callback) {
const decks = [];
asyncLib.auto({
readDir: (done) => {
fs.readdir(config.deck_path, done);
},
handleDecks: [
"readDir",
(results, done) => {
const decks_list = results.readDir;
asyncLib.each(decks_list, async (deck_name) => {
if (deck_name.endsWith(".ydk")) {
const deck = await readDeck(deck_name, config.deck_path + deck_name);
decks.push(deck);
}
}, done);
},
],
}, (err) => {
callback(err, decks);
});
const getDecks = async function (callback) {
try {
const decks = [];
const decks_list = await fs.promises.readdir(config.deck_path);
for (const deck_name of decks_list) {
if (deck_name.endsWith(".ydk")) {
const deck = await readDeck(deck_name, config.deck_path + deck_name);
decks.push(deck);
}
}
callback(null, decks);
}
catch (err) {
callback(err, []);
}
};
const delDeck = function (deck_name, callback) {
if (deck_name.startsWith("../") || deck_name.match(/\/\.\.\//)) {
......@@ -143,19 +136,19 @@ const delDeck = function (deck_name, callback) {
}
fs.unlink(config.deck_path + deck_name, callback);
};
const clearDecks = function (callback) {
asyncLib.auto({
deckList: (done) => {
fs.readdir(config.deck_path, done);
},
removeAll: [
"deckList",
(results, done) => {
const decks_list = results.deckList;
asyncLib.each(decks_list, delDeck, done);
},
],
}, callback);
const clearDecks = async function (callback) {
try {
const decks_list = await fs.promises.readdir(config.deck_path);
for (const deck_name of decks_list) {
await new Promise((resolve, reject) => {
delDeck(deck_name, (err) => (err ? reject(err) : resolve()));
});
}
callback(null);
}
catch (err) {
callback(err);
}
};
const UploadToChallonge = async function () {
if (!challonge_config.enabled) {
......@@ -194,34 +187,38 @@ const UploadToChallonge = async function () {
}
return true;
};
const receiveDecks = function (files, callback) {
const result = [];
asyncLib.eachSeries(files, async (file) => {
if (file.name.endsWith(".ydk")) {
const deck = await readDeck(file.name, file.path);
if (deck.main.length >= 40) {
fs.createReadStream(file.path).pipe(fs.createWriteStream(config.deck_path + file.name));
result.push({
file: file.name,
status: "OK",
});
const receiveDecks = async function (files, callback) {
try {
const result = [];
for (const file of files) {
if (file.name.endsWith(".ydk")) {
const deck = await readDeck(file.name, file.path);
if (deck.main.length >= 40) {
fs.createReadStream(file.path).pipe(fs.createWriteStream(config.deck_path + file.name));
result.push({
file: file.name,
status: "OK",
});
}
else {
result.push({
file: file.name,
status: "卡组不合格",
});
}
}
else {
result.push({
file: file.name,
status: "卡组不合格",
status: "不是卡组文件",
});
}
}
else {
result.push({
file: file.name,
status: "不是卡组文件",
});
}
}, (err) => {
callback(err, result);
});
callback(null, result);
}
catch (err) {
callback(err, []);
}
};
//建立一个http服务器,接收API操作
async function requestListener(req, res) {
......
......@@ -15,7 +15,6 @@ import * as formidable from "formidable";
import { sync as loadJSON } from "load-json-file";
import defaultConfig from "./data/default_config.json";
import { Challonge } from "./challonge";
import * as asyncLib from "async";
import YGOProDeckEncode from "ygopro-deck-encode";
import * as auth from "./ygopro-auth";
import _ from "underscore";
......@@ -82,34 +81,20 @@ const readDeck = async function (deck_name: string, deck_full_path: string) {
};
//读取指定文件夹中所有卡组
const getDecks = function (callback: (err: Error | null, decks: any[]) => void) {
const decks: any[] = [];
asyncLib.auto(
{
readDir: (done: (err: NodeJS.ErrnoException | null, files?: string[]) => void) => {
fs.readdir(config.deck_path, done);
},
handleDecks: [
"readDir",
(results: any, done: (err?: Error | null) => void) => {
const decks_list = results.readDir as string[];
asyncLib.each(
decks_list,
async (deck_name: string) => {
if (deck_name.endsWith(".ydk")) {
const deck = await readDeck(deck_name, config.deck_path + deck_name);
decks.push(deck);
}
},
done
);
},
],
},
(err: Error | null) => {
callback(err, decks);
const getDecks = async function (callback: (err: Error | null, decks: any[]) => void) {
try {
const decks: any[] = [];
const decks_list = await fs.promises.readdir(config.deck_path);
for (const deck_name of decks_list) {
if (deck_name.endsWith(".ydk")) {
const deck = await readDeck(deck_name, config.deck_path + deck_name);
decks.push(deck);
}
}
);
callback(null, decks);
} catch (err) {
callback(err as Error, []);
}
};
const delDeck = function (deck_name: string, callback: (err?: NodeJS.ErrnoException | null) => void) {
......@@ -120,22 +105,18 @@ const delDeck = function (deck_name: string, callback: (err?: NodeJS.ErrnoExcept
fs.unlink(config.deck_path + deck_name, callback);
};
const clearDecks = function (callback: (err?: Error | null) => void) {
asyncLib.auto(
{
deckList: (done: (err: NodeJS.ErrnoException | null, files?: string[]) => void) => {
fs.readdir(config.deck_path, done);
},
removeAll: [
"deckList",
(results: any, done: (err?: Error | null) => void) => {
const decks_list = results.deckList as string[];
asyncLib.each(decks_list, delDeck as any, done);
},
],
},
callback
);
const clearDecks = async function (callback: (err?: Error | null) => void) {
try {
const decks_list = await fs.promises.readdir(config.deck_path);
for (const deck_name of decks_list) {
await new Promise<void>((resolve, reject) => {
delDeck(deck_name, (err) => (err ? reject(err) : resolve()));
});
}
callback(null);
} catch (err) {
callback(err as Error);
}
};
const UploadToChallonge = async function () {
......@@ -179,14 +160,13 @@ const UploadToChallonge = async function () {
return true;
};
const receiveDecks = function (
const receiveDecks = async function (
files: any,
callback: (err: Error | null, result: Array<{ file: string; status: string }>) => void
) {
const result: Array<{ file: string; status: string }> = [];
asyncLib.eachSeries(
files,
async (file: any) => {
try {
const result: Array<{ file: string; status: string }> = [];
for (const file of files) {
if (file.name.endsWith(".ydk")) {
const deck = await readDeck(file.name, file.path);
if (deck.main.length >= 40) {
......@@ -207,11 +187,11 @@ const receiveDecks = function (
status: "不是卡组文件",
});
}
},
(err: Error | null) => {
callback(err, result);
}
);
callback(null, result);
} catch (err) {
callback(err as Error, []);
}
};
//建立一个http服务器,接收API操作
......
......@@ -21,7 +21,7 @@ var loadJSON = require('load-json-file').sync;
var auth = require('./ygopro-auth.js');
var constants = loadJSON('./data/constants.json');
var constants = require('./load-constants').loadConstants();
var settings = loadJSON('./config/config.json');
config = settings.modules.update_util;
......
......@@ -2,7 +2,6 @@ _ = require 'underscore'
_.str = require 'underscore.string'
_.mixin(_.str.exports())
Struct = require('./struct.js').Struct
loadJSON = require('load-json-file').sync
@i18ns = loadJSON './data/i18n.json'
......@@ -23,9 +22,6 @@ YGOProMessagesHelper = require("./YGOProMessages.js").YGOProMessagesHelper # 为
@helper = new YGOProMessagesHelper(9000)
@structs = @helper.structs
@structs_declaration = @helper.structs_declaration
@typedefs = @helper.typedefs
@proto_structs = @helper.proto_structs
@constants = @helper.constants
translateHandler = (handler) ->
......@@ -91,26 +87,6 @@ translateHandler = (handler) ->
room.recordChatMessage(msg, player)
return
@stoc_send_hint_card_to_room = (room, card)->
if !room
console.log "err stoc_send_hint_card_to_room"
return
for client in room.players
@stoc_send client, 'GAME_MSG', {
curmsg: 2,
type: 10,
player: 0,
data: card
} if client
for client in room.watchers
@stoc_send client, 'GAME_MSG', {
curmsg: 2,
type: 10,
player: 0,
data: card
} if client
return
@stoc_die = (client, msg)->
await @stoc_send_chat(client, msg, @constants.COLORS.RED)
await @stoc_send client, 'ERROR_MSG', {
......
// Generated by CoffeeScript 2.7.0
(function() {
var Struct, YGOProMessagesHelper, _, loadJSON, translateHandler;
var YGOProMessagesHelper, _, loadJSON, translateHandler;
_ = require('underscore');
......@@ -8,8 +8,6 @@
_.mixin(_.str.exports());
Struct = require('./struct.js').Struct;
loadJSON = require('load-json-file').sync;
this.i18ns = loadJSON('./data/i18n.json');
......@@ -47,12 +45,6 @@
this.structs = this.helper.structs;
this.structs_declaration = this.helper.structs_declaration;
this.typedefs = this.helper.typedefs;
this.proto_structs = this.helper.proto_structs;
this.constants = this.helper.constants;
translateHandler = function(handler) {
......@@ -153,38 +145,6 @@
room.recordChatMessage(msg, player);
};
this.stoc_send_hint_card_to_room = function(room, card) {
var client, i, j, len, len1, ref, ref1;
if (!room) {
console.log("err stoc_send_hint_card_to_room");
return;
}
ref = room.players;
for (i = 0, len = ref.length; i < len; i++) {
client = ref[i];
if (client) {
this.stoc_send(client, 'GAME_MSG', {
curmsg: 2,
type: 10,
player: 0,
data: card
});
}
}
ref1 = room.watchers;
for (j = 0, len1 = ref1.length; j < len1; j++) {
client = ref1[j];
if (client) {
this.stoc_send(client, 'GAME_MSG', {
curmsg: 2,
type: 10,
player: 0,
data: card
});
}
}
};
this.stoc_die = async function(client, msg) {
await this.stoc_send_chat(client, msg, this.constants.COLORS.RED);
if (client) {
......
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