Commit e8491dbe authored by nanahira's avatar nanahira

migrate to ygopro-yrp-encode

parent 7ec0ee59
Pipeline #42723 passed with stages
in 8 minutes and 19 seconds
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Replay = exports.ReplayHeader = exports.REPLAY_ID_YRP2 = exports.REPLAY_ID_YRP1 = exports.SEED_COUNT = void 0;
const fs = __importStar(require("fs"));
const lzma = __importStar(require("lzma"));
exports.SEED_COUNT = 8;
exports.REPLAY_ID_YRP1 = 0x31707279;
exports.REPLAY_ID_YRP2 = 0x32707279;
/**
* Metadata stored at the beginning of every replay file.
*/
class ReplayHeader {
constructor() {
this.id = 0;
this.version = 0;
this.flag = 0;
this.seed = 0;
this.dataSizeRaw = [];
this.hash = 0;
this.props = [];
this.seedSequence = [];
this.headerVersion = 0;
this.value1 = 0;
this.value2 = 0;
this.value3 = 0;
}
/** Decompressed size as little‑endian 32‑bit */
get dataSize() {
return Buffer.from(this.dataSizeRaw).readUInt32LE(0);
}
get isTag() {
return (this.flag & ReplayHeader.REPLAY_TAG_FLAG) !== 0;
}
get isCompressed() {
return (this.flag & ReplayHeader.REPLAY_COMPRESSED_FLAG) !== 0;
}
/** Compose a valid 13‑byte LZMA header for this replay */
getLzmaHeader() {
const bytes = [
...this.props.slice(0, 5),
...this.dataSizeRaw,
0,
0,
0,
0,
];
return Buffer.from(bytes);
}
}
exports.ReplayHeader = ReplayHeader;
ReplayHeader.REPLAY_COMPRESSED_FLAG = 0x1;
ReplayHeader.REPLAY_TAG_FLAG = 0x2;
ReplayHeader.REPLAY_DECODED_FLAG = 0x4;
ReplayHeader.REPLAY_SINGLE_MODE = 0x8;
ReplayHeader.REPLAY_UNIFORM = 0x10;
/** Utility for reading little‑endian primitives from a Buffer */
class ReplayReader {
constructor(buffer) {
this.buffer = buffer;
this.pointer = 0;
}
advance(size, read) {
const value = read();
this.pointer += size;
return value;
}
readByte() {
return this.advance(1, () => this.buffer.readUInt8(this.pointer));
}
readByteArray(length) {
const out = [];
for (let i = 0; i < length; i++)
out.push(this.readByte());
return out;
}
readInt8() {
return this.advance(1, () => this.buffer.readInt8(this.pointer));
}
readUInt8() {
return this.advance(1, () => this.buffer.readUInt8(this.pointer));
}
readInt16() {
return this.advance(2, () => this.buffer.readInt16LE(this.pointer));
}
readInt32() {
return this.advance(4, () => this.buffer.readInt32LE(this.pointer));
}
readUInt16() {
return this.advance(2, () => this.buffer.readUInt16LE(this.pointer));
}
readUInt32() {
return this.advance(4, () => this.buffer.readUInt32LE(this.pointer));
}
readAll() {
return this.buffer.slice(this.pointer);
}
readString(length) {
if (this.pointer + length > this.buffer.length)
return null;
const raw = this.buffer
.slice(this.pointer, this.pointer + length)
.toString('utf16le');
this.pointer += length;
return raw.split('\u0000')[0];
}
readRaw(length) {
if (this.pointer + length > this.buffer.length)
return null;
const buf = this.buffer.slice(this.pointer, this.pointer + length);
this.pointer += length;
return buf;
}
}
/** Utility for writing little‑endian primitives into a Buffer */
class ReplayWriter {
constructor(buffer) {
this.buffer = buffer;
this.pointer = 0;
}
advance(action, size) {
action();
this.pointer += size;
}
writeByte(val) {
this.advance(() => this.buffer.writeUInt8(val, this.pointer), 1);
}
writeByteArray(values) {
for (const v of values)
this.writeByte(v);
}
writeInt8(val) {
this.advance(() => this.buffer.writeInt8(val, this.pointer), 1);
}
writeUInt8(val) {
this.advance(() => this.buffer.writeUInt8(val, this.pointer), 1);
}
writeInt16(val) {
this.advance(() => this.buffer.writeInt16LE(val, this.pointer), 2);
}
writeInt32(val) {
this.advance(() => this.buffer.writeInt32LE(val, this.pointer), 4);
}
writeUInt16(val) {
this.advance(() => this.buffer.writeUInt16LE(val, this.pointer), 2);
}
writeUInt32(val) {
this.advance(() => this.buffer.writeUInt32LE(val, this.pointer), 4);
}
writeAll(buf) {
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeString(val, length) {
const raw = Buffer.from(val ?? '', 'utf16le');
const bytes = [...raw];
if (length !== undefined) {
const padding = new Array(Math.max(length - bytes.length, 0)).fill(0);
this.writeByteArray([...bytes, ...padding]);
}
else {
this.writeByteArray(bytes);
}
}
}
class Replay {
constructor() {
this.header = null;
this.hostName = '';
this.clientName = '';
this.startLp = 0;
this.startHand = 0;
this.drawCount = 0;
this.opt = 0;
this.hostDeck = null;
this.clientDeck = null;
this.tagHostName = null;
this.tagClientName = null;
this.tagHostDeck = null;
this.tagClientDeck = null;
this.responses = [];
}
/** All deck objects in play order */
get decks() {
return this.isTag
? [
this.hostDeck,
this.clientDeck,
this.tagHostDeck,
this.tagClientDeck,
]
: [this.hostDeck, this.clientDeck];
}
get isTag() {
return this.header?.isTag ?? false;
}
/* ------------------ Static helpers ------------------ */
static async fromFile(path) {
return Replay.fromBuffer(await fs.promises.readFile(path));
}
static fromBuffer(buffer) {
const headerReader = new ReplayReader(buffer);
const header = Replay.readHeader(headerReader);
const raw = headerReader.readAll();
const body = header.isCompressed
? Replay.decompressBody(header, raw)
: raw;
const bodyReader = new ReplayReader(body);
return Replay.readReplay(header, bodyReader);
}
static decompressBody(header, raw) {
const lzmaBuffer = Buffer.concat([header.getLzmaHeader(), raw]);
// lzma‑native provides synchronous helpers.
return Buffer.from(lzma.decompress(lzmaBuffer));
}
static readHeader(reader) {
const h = new ReplayHeader();
h.id = reader.readUInt32();
h.version = reader.readUInt32();
h.flag = reader.readUInt32();
h.seed = reader.readUInt32();
h.dataSizeRaw = reader.readByteArray(4);
h.hash = reader.readUInt32();
h.props = reader.readByteArray(8);
if (h.id === exports.REPLAY_ID_YRP2) {
for (let i = 0; i < exports.SEED_COUNT; i++) {
h.seedSequence.push(reader.readUInt32());
}
h.headerVersion = reader.readUInt32();
h.value1 = reader.readUInt32();
h.value2 = reader.readUInt32();
h.value3 = reader.readUInt32();
}
return h;
}
static readReplay(header, reader) {
const r = new Replay();
r.header = header;
r.hostName = reader.readString(40) ?? '';
if (header.isTag) {
r.tagHostName = reader.readString(40);
r.tagClientName = reader.readString(40);
}
r.clientName = reader.readString(40) ?? '';
r.startLp = reader.readInt32();
r.startHand = reader.readInt32();
r.drawCount = reader.readInt32();
r.opt = reader.readInt32();
r.hostDeck = Replay.readDeck(reader);
if (header.isTag) {
r.tagHostDeck = Replay.readDeck(reader);
r.tagClientDeck = Replay.readDeck(reader);
}
r.clientDeck = Replay.readDeck(reader);
r.responses = Replay.readResponses(reader);
return r;
}
/* ------------------ Deck helpers ------------------ */
static readDeck(reader) {
return {
main: Replay.readDeckPack(reader),
ex: Replay.readDeckPack(reader),
};
}
static readDeckPack(reader) {
const length = reader.readInt32();
const cards = [];
for (let i = 0; i < length; i++)
cards.push(reader.readInt32());
return cards;
}
/* ------------------ Response helpers ------------------ */
static readResponses(reader) {
const out = [];
while (true) {
try {
let length = reader.readUInt8();
if (length > 64)
length = 64;
const segment = reader.readRaw(length);
if (!segment)
break;
out.push(segment);
}
catch {
break;
}
}
return out;
}
/* ------------------ Writing ------------------ */
toBuffer() {
if (!this.header)
throw new Error('Header not initialised');
const headerWriter = new ReplayWriter(Buffer.alloc(32));
this.writeHeader(headerWriter);
const deckSize = (d) => ((d?.main.length ?? 0) + (d?.ex.length ?? 0)) * 4 + 8;
const responseSize = this.responses.reduce((s, b) => s + b.length + 1, 0);
let contentSize = 96 + deckSize(this.hostDeck) + deckSize(this.clientDeck) + responseSize;
if (this.header.isTag) {
contentSize +=
deckSize(this.tagHostDeck) + deckSize(this.tagClientDeck) + 80;
}
const contentWriter = new ReplayWriter(Buffer.alloc(contentSize));
this.writeContent(contentWriter);
let body = contentWriter.buffer;
if (this.header.isCompressed) {
body = Buffer.from(lzma.compress(body));
body = body.slice(13); // strip header like original implementation
}
return Buffer.concat([headerWriter.buffer, body]);
}
async writeToFile(path) {
await fs.promises.writeFile(path, this.toBuffer());
}
writeHeader(w) {
w.writeUInt32(this.header.id);
w.writeUInt32(this.header.version);
w.writeUInt32(this.header.flag);
w.writeUInt32(this.header.seed);
w.writeByteArray(this.header.dataSizeRaw);
w.writeUInt32(this.header.hash);
w.writeByteArray(this.header.props);
if (this.header.id === exports.REPLAY_ID_YRP2) {
for (let i = 0; i < exports.SEED_COUNT; i++) {
w.writeUInt32(this.header.seedSequence[i]);
}
w.writeUInt32(this.header.headerVersion);
w.writeUInt32(this.header.value1);
w.writeUInt32(this.header.value2);
w.writeUInt32(this.header.value3);
}
}
writeContent(w) {
w.writeString(this.hostName, 40);
if (this.header.isTag) {
w.writeString(this.tagHostName, 40);
w.writeString(this.tagClientName, 40);
}
w.writeString(this.clientName, 40);
w.writeInt32(this.startLp);
w.writeInt32(this.startHand);
w.writeInt32(this.drawCount);
w.writeInt32(this.opt);
Replay.writeDeck(w, this.hostDeck);
if (this.header.isTag) {
Replay.writeDeck(w, this.tagHostDeck);
Replay.writeDeck(w, this.tagClientDeck);
}
Replay.writeDeck(w, this.clientDeck);
Replay.writeResponses(w, this.responses);
}
static writeDeck(w, d) {
if (!d) {
w.writeInt32(0);
w.writeInt32(0);
return;
}
Replay.writeDeckPack(w, d.main);
Replay.writeDeckPack(w, d.ex);
}
static writeDeckPack(w, pack) {
w.writeInt32(pack.length);
for (const card of pack)
w.writeInt32(card);
}
static writeResponses(w, res) {
for (const buf of res) {
w.writeUInt8(buf.length);
w.writeByteArray(buf);
}
}
}
exports.Replay = Replay;
import * as fs from 'fs';
import * as lzma from 'lzma';
/** A minimal deck representation */
export interface DeckObject {
main: number[];
ex: number[];
}
export const SEED_COUNT = 8;
export const REPLAY_ID_YRP1 = 0x31707279;
export const REPLAY_ID_YRP2 = 0x32707279;
/**
* Metadata stored at the beginning of every replay file.
*/
export class ReplayHeader {
static readonly REPLAY_COMPRESSED_FLAG = 0x1;
static readonly REPLAY_TAG_FLAG = 0x2;
static readonly REPLAY_DECODED_FLAG = 0x4;
static readonly REPLAY_SINGLE_MODE = 0x8;
static readonly REPLAY_UNIFORM = 0x10;
id = 0;
version = 0;
flag = 0;
seed = 0;
dataSizeRaw: number[] = [];
hash = 0;
props: number[] = [];
seedSequence: number[] = [];
headerVersion = 0;
value1 = 0;
value2 = 0;
value3 = 0;
/** Decompressed size as little‑endian 32‑bit */
get dataSize(): number {
return Buffer.from(this.dataSizeRaw).readUInt32LE(0);
}
get isTag(): boolean {
return (this.flag & ReplayHeader.REPLAY_TAG_FLAG) !== 0;
}
get isCompressed(): boolean {
return (this.flag & ReplayHeader.REPLAY_COMPRESSED_FLAG) !== 0;
}
/** Compose a valid 13‑byte LZMA header for this replay */
getLzmaHeader(): Buffer {
const bytes = [
...this.props.slice(0, 5),
...this.dataSizeRaw,
0,
0,
0,
0,
];
return Buffer.from(bytes);
}
}
/** Utility for reading little‑endian primitives from a Buffer */
class ReplayReader {
private pointer = 0;
constructor(private readonly buffer: Buffer) {}
private advance<T>(size: number, read: () => T): T {
const value = read();
this.pointer += size;
return value;
}
readByte(): number {
return this.advance(1, () => this.buffer.readUInt8(this.pointer));
}
readByteArray(length: number): number[] {
const out: number[] = [];
for (let i = 0; i < length; i++) out.push(this.readByte());
return out;
}
readInt8(): number {
return this.advance(1, () => this.buffer.readInt8(this.pointer));
}
readUInt8(): number {
return this.advance(1, () => this.buffer.readUInt8(this.pointer));
}
readInt16(): number {
return this.advance(2, () => this.buffer.readInt16LE(this.pointer));
}
readInt32(): number {
return this.advance(4, () => this.buffer.readInt32LE(this.pointer));
}
readUInt16(): number {
return this.advance(2, () => this.buffer.readUInt16LE(this.pointer));
}
readUInt32(): number {
return this.advance(4, () => this.buffer.readUInt32LE(this.pointer));
}
readAll(): Buffer {
return this.buffer.slice(this.pointer);
}
readString(length: number): string | null {
if (this.pointer + length > this.buffer.length) return null;
const raw = this.buffer
.slice(this.pointer, this.pointer + length)
.toString('utf16le');
this.pointer += length;
return raw.split('\u0000')[0];
}
readRaw(length: number): Buffer | null {
if (this.pointer + length > this.buffer.length) return null;
const buf = this.buffer.slice(this.pointer, this.pointer + length);
this.pointer += length;
return buf;
}
}
/** Utility for writing little‑endian primitives into a Buffer */
class ReplayWriter {
private pointer = 0;
constructor(public buffer: Buffer) {}
private advance(action: () => void, size: number): void {
action();
this.pointer += size;
}
writeByte(val: number): void {
this.advance(() => this.buffer.writeUInt8(val, this.pointer), 1);
}
writeByteArray(values: Iterable<number>): void {
for (const v of values) this.writeByte(v);
}
writeInt8(val: number): void {
this.advance(() => this.buffer.writeInt8(val, this.pointer), 1);
}
writeUInt8(val: number): void {
this.advance(() => this.buffer.writeUInt8(val, this.pointer), 1);
}
writeInt16(val: number): void {
this.advance(() => this.buffer.writeInt16LE(val, this.pointer), 2);
}
writeInt32(val: number): void {
this.advance(() => this.buffer.writeInt32LE(val, this.pointer), 4);
}
writeUInt16(val: number): void {
this.advance(() => this.buffer.writeUInt16LE(val, this.pointer), 2);
}
writeUInt32(val: number): void {
this.advance(() => this.buffer.writeUInt32LE(val, this.pointer), 4);
}
writeAll(buf: Buffer): void {
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeString(val: string | null, length?: number): void {
const raw = Buffer.from(val ?? '', 'utf16le');
const bytes = [...raw];
if (length !== undefined) {
const padding = new Array(Math.max(length - bytes.length, 0)).fill(0);
this.writeByteArray([...bytes, ...padding]);
} else {
this.writeByteArray(bytes);
}
}
}
export class Replay {
header: ReplayHeader | null = null;
hostName = '';
clientName = '';
startLp = 0;
startHand = 0;
drawCount = 0;
opt = 0;
hostDeck: DeckObject | null = null;
clientDeck: DeckObject | null = null;
tagHostName: string | null = null;
tagClientName: string | null = null;
tagHostDeck: DeckObject | null = null;
tagClientDeck: DeckObject | null = null;
responses: Buffer[] = [];
/** All deck objects in play order */
get decks(): DeckObject[] {
return this.isTag
? [
this.hostDeck!,
this.clientDeck!,
this.tagHostDeck!,
this.tagClientDeck!,
]
: [this.hostDeck!, this.clientDeck!];
}
get isTag(): boolean {
return this.header?.isTag ?? false;
}
/* ------------------ Static helpers ------------------ */
static async fromFile(path: string): Promise<Replay> {
return Replay.fromBuffer(await fs.promises.readFile(path));
}
static fromBuffer(buffer: Buffer): Replay {
const headerReader = new ReplayReader(buffer);
const header = Replay.readHeader(headerReader);
const raw = headerReader.readAll();
const body = header.isCompressed
? Replay.decompressBody(header, raw)
: raw;
const bodyReader = new ReplayReader(body);
return Replay.readReplay(header, bodyReader);
}
private static decompressBody(header: ReplayHeader, raw: Buffer): Buffer {
const lzmaBuffer = Buffer.concat([header.getLzmaHeader(), raw]);
// lzma‑native provides synchronous helpers.
return Buffer.from(lzma.decompress(lzmaBuffer));
}
private static readHeader(reader: ReplayReader): ReplayHeader {
const h = new ReplayHeader();
h.id = reader.readUInt32();
h.version = reader.readUInt32();
h.flag = reader.readUInt32();
h.seed = reader.readUInt32();
h.dataSizeRaw = reader.readByteArray(4);
h.hash = reader.readUInt32();
h.props = reader.readByteArray(8);
if (h.id === REPLAY_ID_YRP2) {
for(let i = 0; i < SEED_COUNT; i++) {
h.seedSequence.push(reader.readUInt32());
}
h.headerVersion = reader.readUInt32();
h.value1 = reader.readUInt32();
h.value2 = reader.readUInt32();
h.value3 = reader.readUInt32();
}
return h;
}
private static readReplay(header: ReplayHeader, reader: ReplayReader): Replay {
const r = new Replay();
r.header = header;
r.hostName = reader.readString(40) ?? '';
if (header.isTag) {
r.tagHostName = reader.readString(40);
r.tagClientName = reader.readString(40);
}
r.clientName = reader.readString(40) ?? '';
r.startLp = reader.readInt32();
r.startHand = reader.readInt32();
r.drawCount = reader.readInt32();
r.opt = reader.readInt32();
r.hostDeck = Replay.readDeck(reader);
if (header.isTag) {
r.tagHostDeck = Replay.readDeck(reader);
r.tagClientDeck = Replay.readDeck(reader);
}
r.clientDeck = Replay.readDeck(reader);
r.responses = Replay.readResponses(reader);
return r;
}
/* ------------------ Deck helpers ------------------ */
private static readDeck(reader: ReplayReader): DeckObject {
return {
main: Replay.readDeckPack(reader),
ex: Replay.readDeckPack(reader),
};
}
private static readDeckPack(reader: ReplayReader): number[] {
const length = reader.readInt32();
const cards: number[] = [];
for (let i = 0; i < length; i++) cards.push(reader.readInt32());
return cards;
}
/* ------------------ Response helpers ------------------ */
private static readResponses(reader: ReplayReader): Buffer[] {
const out: Buffer[] = [];
while (true) {
try {
let length = reader.readUInt8();
if (length > 64) length = 64;
const segment = reader.readRaw(length);
if (!segment) break;
out.push(segment);
} catch {
break;
}
}
return out;
}
/* ------------------ Writing ------------------ */
toBuffer(): Buffer {
if (!this.header) throw new Error('Header not initialised');
const headerWriter = new ReplayWriter(Buffer.alloc(32));
this.writeHeader(headerWriter);
const deckSize = (d: DeckObject | null) =>
((d?.main.length ?? 0) + (d?.ex.length ?? 0)) * 4 + 8;
const responseSize = this.responses.reduce((s, b) => s + b.length + 1, 0);
let contentSize =
96 + deckSize(this.hostDeck) + deckSize(this.clientDeck) + responseSize;
if (this.header.isTag) {
contentSize +=
deckSize(this.tagHostDeck) + deckSize(this.tagClientDeck) + 80;
}
const contentWriter = new ReplayWriter(Buffer.alloc(contentSize));
this.writeContent(contentWriter);
let body = contentWriter.buffer;
if (this.header.isCompressed) {
body = Buffer.from(lzma.compress(body));
body = body.slice(13); // strip header like original implementation
}
return Buffer.concat([headerWriter.buffer, body]);
}
async writeToFile(path: string): Promise<void> {
await fs.promises.writeFile(path, this.toBuffer());
}
private writeHeader(w: ReplayWriter): void {
w.writeUInt32(this.header!.id);
w.writeUInt32(this.header!.version);
w.writeUInt32(this.header!.flag);
w.writeUInt32(this.header!.seed);
w.writeByteArray(this.header!.dataSizeRaw);
w.writeUInt32(this.header!.hash);
w.writeByteArray(this.header!.props);
if (this.header!.id === REPLAY_ID_YRP2) {
for (let i = 0; i < SEED_COUNT; i++) {
w.writeUInt32(this.header!.seedSequence[i]);
}
w.writeUInt32(this.header!.headerVersion);
w.writeUInt32(this.header!.value1);
w.writeUInt32(this.header!.value2);
w.writeUInt32(this.header!.value3);
}
}
private writeContent(w: ReplayWriter): void {
w.writeString(this.hostName, 40);
if (this.header!.isTag) {
w.writeString(this.tagHostName, 40);
w.writeString(this.tagClientName, 40);
}
w.writeString(this.clientName, 40);
w.writeInt32(this.startLp);
w.writeInt32(this.startHand);
w.writeInt32(this.drawCount);
w.writeInt32(this.opt);
Replay.writeDeck(w, this.hostDeck);
if (this.header!.isTag) {
Replay.writeDeck(w, this.tagHostDeck);
Replay.writeDeck(w, this.tagClientDeck);
}
Replay.writeDeck(w, this.clientDeck);
Replay.writeResponses(w, this.responses);
}
private static writeDeck(w: ReplayWriter, d: DeckObject | null): void {
if (!d) {
w.writeInt32(0);
w.writeInt32(0);
return;
}
Replay.writeDeckPack(w, d.main);
Replay.writeDeckPack(w, d.ex);
}
private static writeDeckPack(w: ReplayWriter, pack: number[]): void {
w.writeInt32(pack.length);
for (const card of pack) w.writeInt32(card);
}
private static writeResponses(w: ReplayWriter, res: Buffer[]): void {
for (const buf of res) {
w.writeUInt8(buf.length);
w.writeByteArray(buf);
}
}
}
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
"ip6addr": "^0.2.5", "ip6addr": "^0.2.5",
"jszip": "^3.5.0", "jszip": "^3.5.0",
"load-json-file": "^6.2.0", "load-json-file": "^6.2.0",
"lzma": "^2.3.2",
"moment": "^2.29.1", "moment": "^2.29.1",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"node-os-utils": "^1.3.2", "node-os-utils": "^1.3.2",
...@@ -34,14 +33,14 @@ ...@@ -34,14 +33,14 @@
"underscore": "^1.11.0", "underscore": "^1.11.0",
"underscore.string": "^3.3.6", "underscore.string": "^3.3.6",
"ws": "^8.9.0", "ws": "^8.9.0",
"ygopro-deck-encode": "^1.0.14" "ygopro-deck-encode": "^1.0.15",
"ygopro-yrp-encode": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/async": "^3.2.25", "@types/async": "^3.2.25",
"@types/bunyan": "^1.8.8", "@types/bunyan": "^1.8.8",
"@types/formidable": "^3.4.6", "@types/formidable": "^3.4.6",
"@types/ip6addr": "^0.2.3", "@types/ip6addr": "^0.2.3",
"@types/lzma": "^2.3.0",
"@types/node": "^16.18.126", "@types/node": "^16.18.126",
"@types/underscore": "^1.13.0", "@types/underscore": "^1.13.0",
"@types/ws": "^8.5.3", "@types/ws": "^8.5.3",
...@@ -78,6 +77,15 @@ ...@@ -78,6 +77,15 @@
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==", "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@nanahira/lzma1": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@nanahira/lzma1/-/lzma1-0.2.1.tgz",
"integrity": "sha512-PDJjw4lhD/Lx3RmwqYVpB3nDfmFr2NjdJzK9aazTVxSTJ/JCNzcKB9nxdYTHOwVugMi5FcEnwoSrL26OZkXhyg==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/purerosefallen"
}
},
"node_modules/@sesamecare-oss/redlock": { "node_modules/@sesamecare-oss/redlock": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/@sesamecare-oss/redlock/-/redlock-1.4.0.tgz", "resolved": "https://registry.npmjs.org/@sesamecare-oss/redlock/-/redlock-1.4.0.tgz",
...@@ -127,16 +135,6 @@ ...@@ -127,16 +135,6 @@
"integrity": "sha512-oe7hzc+P9DU6+gql8+bLKuUf4WL4aakyCSXZMZq2cjhhGK75qYwH1zJ4s94XOlnb4cAhrGKwnbrmMBaqDK8+Ww==", "integrity": "sha512-oe7hzc+P9DU6+gql8+bLKuUf4WL4aakyCSXZMZq2cjhhGK75qYwH1zJ4s94XOlnb4cAhrGKwnbrmMBaqDK8+Ww==",
"dev": true "dev": true
}, },
"node_modules/@types/lzma": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@types/lzma/-/lzma-2.3.0.tgz",
"integrity": "sha512-z7TknP6ts5GPnN7P2bkZC1B/tMpoMJXG3UnPY1XDrwBq1OJQ2EpHtEypFwq5Q0A5iS37+oc+MT/o/B7x5lgl8Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "16.18.126", "version": "16.18.126",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz",
...@@ -1861,14 +1859,6 @@ ...@@ -1861,14 +1859,6 @@
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI="
}, },
"node_modules/lzma": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/lzma/-/lzma-2.3.2.tgz",
"integrity": "sha1-N4OySFi5wOdHoN88vx+1/KqSxEE=",
"bin": {
"lzma.js": "bin/lzma.js"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
...@@ -3708,10 +3698,20 @@ ...@@ -3708,10 +3698,20 @@
} }
}, },
"node_modules/ygopro-deck-encode": { "node_modules/ygopro-deck-encode": {
"version": "1.0.14", "version": "1.0.15",
"resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.14.tgz", "resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.15.tgz",
"integrity": "sha512-Q64f8U+okLBDKHw02eRYsdDMpALhYa55k0BhFqZ5k4ntRpPKFNvM9sNEbBlg2bmyi6LCf3rlEmISmLtlx9uDeA==", "integrity": "sha512-NMvgWuC3SKant50RDu0bHa3QIRlwBhdTR3bNDrMpNthTTQmCCq8i2HZaWFiCmYIBi9fR3W9CkFIgK6hI4d+PzQ==",
"license": "MIT" "license": "MIT"
},
"node_modules/ygopro-yrp-encode": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ygopro-yrp-encode/-/ygopro-yrp-encode-1.0.1.tgz",
"integrity": "sha512-BR36py0crUmhvdtponPmM2s9jNb1ufwpy4+MttUc5gEzxfJgN5ZSGLCLCuPQibMaj6kUtJi11akFHLTvhN79rA==",
"license": "MIT",
"dependencies": {
"@nanahira/lzma1": "^0.2.1",
"ygopro-deck-encode": "^1.0.15"
}
} }
}, },
"dependencies": { "dependencies": {
...@@ -3743,6 +3743,11 @@ ...@@ -3743,6 +3743,11 @@
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
}, },
"@nanahira/lzma1": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@nanahira/lzma1/-/lzma1-0.2.1.tgz",
"integrity": "sha512-PDJjw4lhD/Lx3RmwqYVpB3nDfmFr2NjdJzK9aazTVxSTJ/JCNzcKB9nxdYTHOwVugMi5FcEnwoSrL26OZkXhyg=="
},
"@sesamecare-oss/redlock": { "@sesamecare-oss/redlock": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/@sesamecare-oss/redlock/-/redlock-1.4.0.tgz", "resolved": "https://registry.npmjs.org/@sesamecare-oss/redlock/-/redlock-1.4.0.tgz",
...@@ -3784,15 +3789,6 @@ ...@@ -3784,15 +3789,6 @@
"integrity": "sha512-oe7hzc+P9DU6+gql8+bLKuUf4WL4aakyCSXZMZq2cjhhGK75qYwH1zJ4s94XOlnb4cAhrGKwnbrmMBaqDK8+Ww==", "integrity": "sha512-oe7hzc+P9DU6+gql8+bLKuUf4WL4aakyCSXZMZq2cjhhGK75qYwH1zJ4s94XOlnb4cAhrGKwnbrmMBaqDK8+Ww==",
"dev": true "dev": true
}, },
"@types/lzma": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@types/lzma/-/lzma-2.3.0.tgz",
"integrity": "sha512-z7TknP6ts5GPnN7P2bkZC1B/tMpoMJXG3UnPY1XDrwBq1OJQ2EpHtEypFwq5Q0A5iS37+oc+MT/o/B7x5lgl8Q==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/node": { "@types/node": {
"version": "16.18.126", "version": "16.18.126",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz",
...@@ -5077,11 +5073,6 @@ ...@@ -5077,11 +5073,6 @@
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI="
}, },
"lzma": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/lzma/-/lzma-2.3.2.tgz",
"integrity": "sha1-N4OySFi5wOdHoN88vx+1/KqSxEE="
},
"math-intrinsics": { "math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
...@@ -6483,9 +6474,18 @@ ...@@ -6483,9 +6474,18 @@
} }
}, },
"ygopro-deck-encode": { "ygopro-deck-encode": {
"version": "1.0.14", "version": "1.0.15",
"resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.14.tgz", "resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.15.tgz",
"integrity": "sha512-Q64f8U+okLBDKHw02eRYsdDMpALhYa55k0BhFqZ5k4ntRpPKFNvM9sNEbBlg2bmyi6LCf3rlEmISmLtlx9uDeA==" "integrity": "sha512-NMvgWuC3SKant50RDu0bHa3QIRlwBhdTR3bNDrMpNthTTQmCCq8i2HZaWFiCmYIBi9fR3W9CkFIgK6hI4d+PzQ=="
},
"ygopro-yrp-encode": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ygopro-yrp-encode/-/ygopro-yrp-encode-1.0.1.tgz",
"integrity": "sha512-BR36py0crUmhvdtponPmM2s9jNb1ufwpy4+MttUc5gEzxfJgN5ZSGLCLCuPQibMaj6kUtJi11akFHLTvhN79rA==",
"requires": {
"@nanahira/lzma1": "^0.2.1",
"ygopro-deck-encode": "^1.0.15"
}
} }
} }
} }
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
"ip6addr": "^0.2.5", "ip6addr": "^0.2.5",
"jszip": "^3.5.0", "jszip": "^3.5.0",
"load-json-file": "^6.2.0", "load-json-file": "^6.2.0",
"lzma": "^2.3.2",
"moment": "^2.29.1", "moment": "^2.29.1",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"node-os-utils": "^1.3.2", "node-os-utils": "^1.3.2",
...@@ -36,7 +35,8 @@ ...@@ -36,7 +35,8 @@
"underscore": "^1.11.0", "underscore": "^1.11.0",
"underscore.string": "^3.3.6", "underscore.string": "^3.3.6",
"ws": "^8.9.0", "ws": "^8.9.0",
"ygopro-deck-encode": "^1.0.14" "ygopro-deck-encode": "^1.0.15",
"ygopro-yrp-encode": "^1.0.1"
}, },
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
...@@ -52,7 +52,6 @@ ...@@ -52,7 +52,6 @@
"@types/bunyan": "^1.8.8", "@types/bunyan": "^1.8.8",
"@types/formidable": "^3.4.6", "@types/formidable": "^3.4.6",
"@types/ip6addr": "^0.2.3", "@types/ip6addr": "^0.2.3",
"@types/lzma": "^2.3.0",
"@types/node": "^16.18.126", "@types/node": "^16.18.126",
"@types/underscore": "^1.13.0", "@types/underscore": "^1.13.0",
"@types/ws": "^8.5.3", "@types/ws": "^8.5.3",
......
...@@ -94,6 +94,7 @@ util = require("util") ...@@ -94,6 +94,7 @@ util = require("util")
Q = require("q") Q = require("q")
YGOProDeck = require('ygopro-deck-encode').default YGOProDeck = require('ygopro-deck-encode').default
YGOProYrp = require('ygopro-yrp-encode').YGOProYrp
Aragami = require('aragami').Aragami Aragami = require('aragami').Aragami
...@@ -485,7 +486,10 @@ init = () -> ...@@ -485,7 +486,10 @@ init = () ->
long_resolve_cards = global.long_resolve_cards = await loadJSONAsync('./data/long_resolve_cards.json') long_resolve_cards = global.long_resolve_cards = await loadJSONAsync('./data/long_resolve_cards.json')
if settings.modules.tournament_mode.enable_recover if settings.modules.tournament_mode.enable_recover
ReplayParser = global.ReplayParser = (require "./Replay.js").Replay ReplayParser = global.ReplayParser =
fromFile: (filePath) ->
buffer = await fs.promises.readFile(filePath)
new YGOProYrp().fromYrp(buffer)
if settings.modules.athletic_check.enabled if settings.modules.athletic_check.enabled
AthleticChecker = require("./athletic-check.js").AthleticChecker AthleticChecker = require("./athletic-check.js").AthleticChecker
...@@ -2709,7 +2713,8 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)-> ...@@ -2709,7 +2713,8 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
if (msg >= 10 and msg < 30) or msg == 132 or (msg >= 140 and msg <= 144) #SELECT和ANNOUNCE开头的消息 if (msg >= 10 and msg < 30) or msg == 132 or (msg >= 140 and msg <= 144) #SELECT和ANNOUNCE开头的消息
if room.recovering if room.recovering
ygopro.ctos_send(server, 'RESPONSE', room.recover_replay.responses.splice(0, 1)[0]) response = room.recover_replay.responses.splice(0, 1)[0]
ygopro.ctos_send(server, 'RESPONSE', Buffer.from(response))
if !room.recover_replay.responses.length if !room.recover_replay.responses.length
room.finish_recover() room.finish_recover()
return true return true
......
// Generated by CoffeeScript 2.7.0 // Generated by CoffeeScript 2.7.0
(function() { (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, _, _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, 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;
net = require('net'); net = require('net');
...@@ -85,6 +85,8 @@ ...@@ -85,6 +85,8 @@
YGOProDeck = require('ygopro-deck-encode').default; YGOProDeck = require('ygopro-deck-encode').default;
YGOProYrp = require('ygopro-yrp-encode').YGOProYrp;
Aragami = require('aragami').Aragami; Aragami = require('aragami').Aragami;
aragami = global.aragami = new Aragami(); // we use memory mode only aragami = global.aragami = new Aragami(); // we use memory mode only
...@@ -618,7 +620,13 @@ ...@@ -618,7 +620,13 @@
long_resolve_cards = global.long_resolve_cards = (await loadJSONAsync('./data/long_resolve_cards.json')); long_resolve_cards = global.long_resolve_cards = (await loadJSONAsync('./data/long_resolve_cards.json'));
} }
if (settings.modules.tournament_mode.enable_recover) { if (settings.modules.tournament_mode.enable_recover) {
ReplayParser = global.ReplayParser = (require("./Replay.js")).Replay; ReplayParser = global.ReplayParser = {
fromFile: async function(filePath) {
var buffer;
buffer = (await fs.promises.readFile(filePath));
return new YGOProYrp().fromYrp(buffer);
}
};
} }
if (settings.modules.athletic_check.enabled) { if (settings.modules.athletic_check.enabled) {
AthleticChecker = require("./athletic-check.js").AthleticChecker; AthleticChecker = require("./athletic-check.js").AthleticChecker;
...@@ -3492,7 +3500,7 @@ ...@@ -3492,7 +3500,7 @@
}; };
ygopro.stoc_follow('GAME_MSG', true, async function(buffer, info, client, server, datas) { 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, room, trigger_location, val, win_pos; 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;
room = ROOM_all[client.rid]; room = ROOM_all[client.rid];
if (!(room && !client.reconnecting)) { if (!(room && !client.reconnecting)) {
return; return;
...@@ -3547,7 +3555,8 @@ ...@@ -3547,7 +3555,8 @@
// log.info(client.name, client.last_game_msg_title) // log.info(client.name, client.last_game_msg_title)
if ((msg >= 10 && msg < 30) || msg === 132 || (msg >= 140 && msg <= 144)) { //SELECT和ANNOUNCE开头的消息 if ((msg >= 10 && msg < 30) || msg === 132 || (msg >= 140 && msg <= 144)) { //SELECT和ANNOUNCE开头的消息
if (room.recovering) { if (room.recovering) {
ygopro.ctos_send(server, 'RESPONSE', room.recover_replay.responses.splice(0, 1)[0]); response = room.recover_replay.responses.splice(0, 1)[0];
ygopro.ctos_send(server, 'RESPONSE', Buffer.from(response));
if (!room.recover_replay.responses.length) { if (!room.recover_replay.responses.length) {
room.finish_recover(); room.finish_recover();
} }
......
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