Commit 7963b211 authored by Sophia's avatar Sophia

add source code

parent d78b340d
/* eslint-disable @typescript-eslint/no-var-requires */
import moment from "moment";
import FormData from "form-data";
import fetch from "node-fetch";
interface YGOPro {
stoc_follow_after(msg: string, synchronous: boolean, callback: (buffer: Buffer, info: any, client: any, server: any, datas: any) => Promise<boolean>): void;
stoc_follow(msg: string, synchronous: boolean, callback: (buffer: Buffer, info: any, client: any, server: any, datas: any) => Promise<boolean>): void;
ctos_follow_after(msg: string, synchronous: boolean, callback: (buffer: Buffer, info: any, client: any, server: any, datas: any) => Promise<boolean>): void;
ctos_follow(msg: string, synchronous: boolean, callback: (buffer: Buffer, info: any, client: any, server: any, datas: any) => Promise<boolean>): void;
stoc_send(client: any, message: "REPLAY" | "__N__", buffer: Buffer): any;
}
interface PlayerInformation {
ip: string; // IP 주소
name: string; // 플레이어 이름
lang: string; // 언어
pass: string; // 접속 방 제목
joinTime: string; // 접속 시간
pos: number; // 방 슬롯 정보
// 사이딩 된 덱 레시피 정보
sidedDeck: Array<{
main: number[];
side: number[];
}>;
}
interface ExportData {
roomSettings: Omit<typeof ROOM_all[0]["hostinfo"], "lflist"> & {
lflist: Omit<typeof lflists[0], "date"> & { date: string };
};
players: PlayerInformation[];
startedAt: number[];
finishedAt: number[];
type: "athletic" | "entertain" | "normal";
isRandomMatch: boolean;
}
declare const lflists: Array<{ date: moment.Moment; tcg: boolean }>;
declare const ygopro: YGOPro;
declare const ROOM_all: Array<{
name: string; // 방 제목
// 방 설정
hostinfo: {
rule: number; // ???
mode: number; // 0 => 싱글, 1 => 매치, 2 => 태그
duel_rule: number; // 마스터 룰 버전
no_check_deck: boolean; // 덱 확인 여부
no_shuffle_deck: boolean; // 덱 셔플 없는지 여부
start_lp: number; // 시작 라이프 포인트
start_hand: number; // 시작 드로우 수
draw_count: number; // 매 턴 드로우 수
lflist: number; // 금제 index
time_limit: number; // 턴당 시간
};
dueling_players: Array<{
ip: string; // IP 주소
name: string; // 플레이어 이름
lang: string; // 언어
pass: string; // 접속 방 제목
join_time: import("moment").Moment; // 접속 시간
pos: number; // 방 슬롯 정보
main: number[]; // 메인 + 엑스트라 덱 카드 ID 배열
side: number[]; // 사이드 덱 카드 ID 배열
}>;
replays: Array<Buffer>;
arena?: "athletic" | "entertain";
random_type?: string;
windbot?: boolean;
replaySaved?: boolean;
customPlayerInformation?: PlayerInformation[];
startedAt?: moment.Moment[];
finishedAt?: moment.Moment[];
exportData?: ExportData;
}>;
declare const log: { warn(message: string): void };
function formatTime(t: moment.Moment) {
return t.unix();
}
function compressData(jsonData: string, replays: Array<Buffer>) {
const headerLengthBuffer = Buffer.alloc(4);
const headerContentBuffer = Buffer.from(jsonData, "utf8");
headerLengthBuffer.writeUInt32BE(headerContentBuffer.length);
let replayBuffer: Buffer | null = null;
replays.forEach(replayData => {
const replayDataLengthBuffer = Buffer.alloc(4);
replayDataLengthBuffer.writeUInt32BE(replayData.length, 0);
if (!replayBuffer) {
replayBuffer = Buffer.concat([replayDataLengthBuffer, replayData]);
} else {
replayBuffer = Buffer.concat([replayBuffer, replayDataLengthBuffer, replayData]);
}
});
return Buffer.concat([headerLengthBuffer, headerContentBuffer, replayBuffer]);
}
function uploadResult(room: typeof ROOM_all[0]) {
try {
if (!room.finishedAt) {
room.finishedAt = [];
}
room.finishedAt.push(moment());
const data: ExportData = {
roomSettings: {
...room.hostinfo,
lflist: {
...lflists[room.hostinfo.lflist],
date: lflists[room.hostinfo.lflist].date.add(1, "day").format("YYYY.MM"),
},
},
players: room.customPlayerInformation,
startedAt: room.startedAt.map(formatTime),
finishedAt: room.finishedAt.map(formatTime),
type: room.arena || "normal",
isRandomMatch: Boolean(room.random_type),
};
room.replaySaved = true;
const compressedData = compressData(JSON.stringify(data), room.replays);
const formData = new FormData();
formData.append("data", compressedData, {
filename: "data.bin",
});
(async () => {
const response = await fetch("http://10.198.1.45:3619/replay/upload", {
method: "POST",
body: formData,
headers: formData.getHeaders(),
});
if (!response.ok || response.status === 500) {
throw new Error("Status Code " + response.status);
}
const data: { status: number; message: string } = (await response.json()) as any;
if (data.status === 500) {
throw new Error(data.message);
}
})().catch(e => {
log.warn(`YGOReplay data collecting plugin error: ${e.message}`);
});
} catch (e) {
log.warn(`YGOReplay: an error occurred during uploading match result: ${e.message}`);
}
}
ygopro.stoc_follow("DUEL_START", false, async (buffer, info, client) => {
try {
if (client.pos !== 0) {
return true;
}
const room = ROOM_all[client.rid];
if (room.hostinfo.mode === 2 || Boolean(room.windbot)) {
return true;
}
if (!room.startedAt) {
room.startedAt = [];
}
room.startedAt.push(moment());
if (!room.customPlayerInformation) {
room.customPlayerInformation = room.dueling_players.map(player => {
return {
ip: player.ip,
name: player.name,
joinTime: player.join_time.format("YYYY-MM-DD HH:mm:ss"),
pos: player.pos,
lang: player.lang,
pass: player.pass,
sidedDeck: [
{
main: player.main,
side: player.side,
},
],
};
});
}
} catch (e) {
log.warn(`YGOReplay: an error occurred during processing DUEL_START message: ${e.message}`);
}
return true;
});
ygopro.stoc_follow_after("CHANGE_SIDE", false, async (buffer, info, client) => {
try {
client.needToChangeSide = true;
if (client.pos === 0) {
return false;
}
const room = ROOM_all[client.rid];
if (!room || Boolean(room.windbot)) {
return false;
}
if (!room.finishedAt) {
room.finishedAt = [];
}
room.finishedAt.push(moment());
} catch (e) {
log.warn(`YGOReplay: an error occurred during processing CHANGE_SIDE message: ${e.message}`);
}
return false;
});
ygopro.stoc_follow_after("REPLAY", false, async (buffer, info, client) => {
try {
const room = ROOM_all[client.rid];
if (Boolean(room.windbot)) {
return true;
}
if (client.pos === 0) {
uploadResult(room);
}
} catch (e) {
log.warn(`YGOReplay: an error occurred during processing REPLAY message: ${e.message}`);
}
return false;
});
ygopro.ctos_follow_after("UPDATE_DECK", false, async (buffer, info, client) => {
try {
const room = ROOM_all[client.rid];
if (!room || Boolean(room.windbot)) {
return false;
}
if (!room.customPlayerInformation) {
return false;
}
const customPlayerInformation = room.customPlayerInformation.find(player => player.pos === client.pos);
if (!customPlayerInformation) {
return false;
}
const player = room.dueling_players.find(p => p.pos === client.pos);
if (!player) {
return false;
}
if (client.needToChangeSide) {
customPlayerInformation.sidedDeck.push({
main: player.main,
side: player.side,
});
client.needToChangeSide = false;
}
} catch (e) {
log.warn(`YGOReplay: an error occurred during processing UPDATE_DECK message: ${e.message}`);
}
return false;
});
(() => {
const oldSTOCSend = ygopro.stoc_send.bind(ygopro);
ygopro.stoc_send = (client, message, buffer) => {
try {
if (message !== "REPLAY") {
return oldSTOCSend(client, message, buffer);
}
const room = ROOM_all[client.rid];
if (room && client.pos === 0 && !room.replaySaved && room.customPlayerInformation && !room.windbot) {
uploadResult(room);
}
} catch (e) {
log.warn(`YGOReplay: an error occurred during processing UPDATE_DECK message: ${e.message}`);
}
return oldSTOCSend(client, message, buffer);
};
})();
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