Commit e6edd444 authored by nanahira's avatar nanahira

Merge branch 'master' into ai-play

parents 92c9fa5f 55f93dc3
Pipeline #5514 passed with stages
in 41 minutes and 42 seconds
......@@ -32,6 +32,7 @@ test*
*.tmp
*.bak
*.log
log.*
*.map
......
stages:
- build
- build2
- combine
- deploy
variables:
GIT_DEPTH: "1"
CONTAINER_TEST_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
CONTAINER_TEST_IMAGE_FULL: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-full
CONTAINER_TEST_IMAGE_LITE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-lite
CONTAINER_TEST_IMAGE_X86_FULL: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-x86-full
CONTAINER_TEST_IMAGE_X86_LITE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-x86-lite
CONTAINER_TEST_IMAGE_ARM_FULL: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-arm-full
CONTAINER_TEST_IMAGE_ARM_LITE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG-arm-lite
CONTAINER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:latest
CONTAINER_RELEASE_IMAGE_FULL: $CI_REGISTRY_IMAGE:full
CONTAINER_RELEASE_IMAGE_LITE: $CI_REGISTRY_IMAGE:lite
build:
build_lite_x86:
stage: build
tags:
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_X86_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull --no-cache -t $CONTAINER_TEST_IMAGE .
- docker push $CONTAINER_TEST_IMAGE
build_lite:
- docker build --pull --no-cache -f ./Dockerfile.lite -t $TARGET_IMAGE .
- docker push $TARGET_IMAGE
build_lite_arm:
stage: build
tags:
tags:
- docker-arm
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_ARM_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull --no-cache -f ./Dockerfile.lite -t $TARGET_IMAGE .
- docker push $TARGET_IMAGE
build_full_x86:
stage: build2
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_X86_FULL
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_X86_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --build-arg BASE_IMAGE=$SOURCE_IMAGE --pull --no-cache -t
$TARGET_IMAGE .
- docker push $TARGET_IMAGE
build_full_arm:
stage: build2
tags:
- docker-arm
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_ARM_FULL
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_ARM_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --build-arg BASE_IMAGE=$SOURCE_IMAGE --pull --no-cache -t
$TARGET_IMAGE .
- docker push $TARGET_IMAGE
combine_lite:
stage: build2
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_LITE
- SOURCE_IMAGE_2=$CONTAINER_TEST_IMAGE_ARM_LITE
- SOURCE_IMAGE_1=$CONTAINER_TEST_IMAGE_X86_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $SOURCE_IMAGE_1
- docker pull $SOURCE_IMAGE_2
- docker manifest create $TARGET_IMAGE --amend $SOURCE_IMAGE_1 --amend
$SOURCE_IMAGE_2
- docker manifest push $TARGET_IMAGE
combine_full:
stage: combine
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_TEST_IMAGE_FULL
- SOURCE_IMAGE_2=$CONTAINER_TEST_IMAGE_ARM_FULL
- SOURCE_IMAGE_1=$CONTAINER_TEST_IMAGE_X86_FULL
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull --no-cache -f ./Dockerfile.lite -t $CONTAINER_TEST_IMAGE_LITE .
- docker push $CONTAINER_TEST_IMAGE_LITE
- docker pull $SOURCE_IMAGE_1
- docker pull $SOURCE_IMAGE_2
- docker manifest create $TARGET_IMAGE --amend $SOURCE_IMAGE_1 --amend
$SOURCE_IMAGE_2
- docker manifest push $TARGET_IMAGE
#upload_stuff_to_minio:
# stage: deploy
# tags:
# - linux
# image: $CONTAINER_TEST_IMAGE
# image: $CONTAINER_TEST_IMAGE_FULL
# script:
# - apt update ; apt -y install python3-pip
# - pip3 install -U -i https://mirrors.aliyun.com/pypi/simple/ awscli
......@@ -42,35 +102,61 @@ build_lite:
# only:
# - master
deploy_latest:
deploy_latest_full:
stage: deploy
tags:
tags:
- docker
script:
- TARGET_IMAGE_2=$CONTAINER_RELEASE_IMAGE
- TARGET_IMAGE=$CONTAINER_RELEASE_IMAGE_FULL
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_FULL
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $CONTAINER_TEST_IMAGE
- docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
- docker push $CONTAINER_RELEASE_IMAGE
- docker pull $CONTAINER_TEST_IMAGE_LITE
- docker tag $CONTAINER_TEST_IMAGE_LITE $CONTAINER_RELEASE_IMAGE_LITE
- docker push $CONTAINER_RELEASE_IMAGE_LITE
- docker pull $SOURCE_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE
- docker push $TARGET_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE_2
- docker push $TARGET_IMAGE_2
only:
- master
deploy_tag:
deploy_latest_lite:
stage: deploy
tags:
- docker
script:
- TARGET_IMAGE=$CONTAINER_RELEASE_IMAGE_LITE
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $SOURCE_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE
- docker push $TARGET_IMAGE
only:
- master
deploy_tag_full:
stage: deploy
tags:
- docker
script:
- TARGET_IMAGE_2=$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
- TARGET_IMAGE=$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG-full
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_FULL
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $SOURCE_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE
- docker push $TARGET_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE_2
- docker push $TARGET_IMAGE_2
only:
- tags
deploy_tag_lite:
stage: deploy
tags:
tags:
- docker
variables:
CONTAINER_TAG_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
CONTAINER_TAG_IMAGE_LITE: $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG-lite
script:
- TARGET_IMAGE=$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG-lite
- SOURCE_IMAGE=$CONTAINER_TEST_IMAGE_LITE
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $CONTAINER_TEST_IMAGE
- docker tag $CONTAINER_TEST_IMAGE $CONTAINER_TAG_IMAGE
- docker push $CONTAINER_TAG_IMAGE
- docker pull $CONTAINER_TEST_IMAGE_LITE
- docker tag $CONTAINER_TEST_IMAGE_LITE $CONTAINER_RELEASE_IMAGE_LITE
- docker push $CONTAINER_RELEASE_IMAGE_LITE
- docker pull $SOURCE_IMAGE
- docker tag $SOURCE_IMAGE $TARGET_IMAGE
- docker push $TARGET_IMAGE
only:
- tags
# Dockerfile for SRVPro
FROM node:14-buster-slim
ARG BASE_IMAGE=git-registry.mycard.moe/mycard/srvpro:lite
FROM $BASE_IMAGE
LABEL Author="Nanahira <nanahira@momobako.com>"
RUN npm install -g pm2
# apt
RUN apt update && \
env DEBIAN_FRONTEND=noninteractive apt install -y wget git build-essential libevent-dev libsqlite3-dev mono-complete p7zip-full python3 liblua5.3-dev && \
rm -rf /var/lib/apt/lists/*
# srvpro
COPY . /ygopro-server
WORKDIR /ygopro-server
RUN npm ci && \
mkdir config decks replays logs /redis
# ygopro
RUN git clone --branch=server --recursive --depth=1 https://github.com/purerosefallen/ygopro && \
cd ygopro && \
git submodule foreach git checkout master && \
wget -O - https://github.com/premake/premake-core/releases/download/v5.0.0-alpha14/premake-5.0.0-alpha14-linux.tar.gz | tar zfx - && \
./premake5 gmake && \
cd build && \
make config=release -j$(nproc) && \
cd .. && \
mv ./bin/release/ygopro . && \
strip ygopro && \
mkdir replay expansions && \
rm -rf .git* bin obj build ocgcore cmake lua premake* sound textures .travis.yml *.txt appveyor.yml LICENSE README.md *.lua strings.conf system.conf && \
ls gframe | sed '/game.cpp/d' | xargs -I {} rm -rf gframe/{}
apt -y install mono-complete && \
npm install -g pm2 && \
rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/*
# windbot
RUN git clone --depth=1 https://github.com/purerosefallen/windbot /tmp/windbot && \
RUN git clone --depth=1 https://code.mycard.moe/nanahira/windbot /tmp/windbot && \
cd /tmp/windbot && \
xbuild /property:Configuration=Release /property:TargetFrameworkVersion="v4.5" && \
mv /tmp/windbot/bin/Release /ygopro-server/windbot && \
cp -rf /ygopro-server/ygopro/cards.cdb /ygopro-server/windbot/ && \
rm -rf /tmp/windbot
# infos
WORKDIR /ygopro-server
EXPOSE 7911 7922 7933
# VOLUME [ /ygopro-server/config, /ygopro-server/decks, /ygopro-server/replays, /redis ]
CMD [ "pm2-docker", "start", "/ygopro-server/data/pm2-docker.json" ]
# Dockerfile for SRVPro Lite
FROM node:14-buster-slim
FROM debian:bullseye as premake-builder
RUN apt update && \
env DEBIAN_FRONTEND=noninteractive apt install -y wget build-essential p7zip-full && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
WORKDIR /usr/src
RUN wget -O premake.zip https://github.com/premake/premake-core/releases/download/v5.0.0-alpha14/premake-5.0.0-alpha14-src.zip && \
7z x -y premake.zip && \
mv premake-5.0.0-alpha14 premake && \
cd premake/build/gmake.unix && \
make -j$(nproc)
FROM node:16-bullseye-slim
LABEL Author="Nanahira <nanahira@momobako.com>"
# apt
RUN apt update && \
env DEBIAN_FRONTEND=noninteractive apt install -y wget git build-essential libsqlite3-dev libevent-dev p7zip-full python3 liblua5.3-dev && \
rm -rf /var/lib/apt/lists/*
env DEBIAN_FRONTEND=noninteractive apt install -y wget git build-essential libevent-dev libsqlite3-dev p7zip-full python3 python-is-python3 liblua5.3-dev && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# srvpro
COPY . /ygopro-server
......@@ -12,11 +26,12 @@ WORKDIR /ygopro-server
RUN npm ci && \
mkdir config decks replays logs
RUN git clone --branch=server --recursive --depth=1 https://github.com/purerosefallen/ygopro && \
COPY --from=premake-builder /usr/src/premake/bin/release/premake5 /usr/bin/premake5
RUN git clone --branch=server --recursive --depth=1 https://code.mycard.moe/nanahira/ygopro && \
cd ygopro && \
git submodule foreach git checkout master && \
wget -O - https://github.com/premake/premake-core/releases/download/v5.0.0-alpha13/premake-5.0.0-alpha13-linux.tar.gz | tar zfx - && \
./premake5 gmake && \
premake5 gmake && \
cd build && \
make config=release -j$(nproc) && \
cd .. && \
......@@ -31,4 +46,4 @@ WORKDIR /ygopro-server
EXPOSE 7911 7922 7933
# VOLUME [ /ygopro-server/config, /ygopro-server/decks, /ygopro-server/replays ]
CMD [ "node", "ygopro-server.js" ]
CMD [ "npm", "start" ]
......@@ -122,9 +122,10 @@ class Replay
@fromBuffer: (buffer) ->
reader = new ReplayReader buffer
header = Replay.readHeader reader
lzmaBuffer = Buffer.concat [header.getLzmaHeader(), reader.readAll()]
restBuffer = reader.readAll()
lzmaBuffer = Buffer.concat [header.getLzmaHeader(), restBuffer]
if header.isCompressed
decompressed = lzmaBuffer
decompressed = restBuffer
else
decompressed = Buffer.from lzma.decompress lzmaBuffer
reader = new ReplayReader decompressed
......
......@@ -180,12 +180,13 @@
}
static fromBuffer(buffer) {
var decompressed, header, lzmaBuffer, reader, replay;
var decompressed, header, lzmaBuffer, reader, replay, restBuffer;
reader = new ReplayReader(buffer);
header = Replay.readHeader(reader);
lzmaBuffer = Buffer.concat([header.getLzmaHeader(), reader.readAll()]);
restBuffer = reader.readAll();
lzmaBuffer = Buffer.concat([header.getLzmaHeader(), restBuffer]);
if (header.isCompressed) {
decompressed = lzmaBuffer;
decompressed = restBuffer;
} else {
decompressed = Buffer.from(lzma.decompress(lzmaBuffer));
}
......
......@@ -8,7 +8,7 @@ import net from "net";
class Handler {
handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean>;
private handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean>;
synchronous: boolean;
constructor(handler: (buffer: Buffer, info: any, datas: Buffer[], params: any) => Promise<boolean>, synchronous: boolean) {
this.handler = handler;
......@@ -46,14 +46,32 @@ export interface HandleResult {
feedback: Feedback;
}
export interface Constants {
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>;
}
export class YGOProMessagesHelper {
handlers: HandlerList;
structs: Map<string, Struct>;
structs_declaration: any;
typedefs: any;
proto_structs: any;
constants: any;
structs_declaration: Record<string, Struct>;
typedefs: Record<string, string>;
proto_structs: Record<'CTOS' | 'STOC', Record<string, string>>;
constants: Constants;
singleHandleLimit: number;
constructor(singleHandleLimit?: number) {
......
......@@ -268,8 +268,8 @@ class DataManager {
const queryBuilder = repo.createQueryBuilder("duelLog")
.where("1");
if (roomName != null && roomName.length) {
const escapedRoomName = this.getEscapedString(roomName);
queryBuilder.andWhere("duelLog.name like :escapedRoomName", { escapedRoomName });
//const escapedRoomName = this.getEscapedString(roomName);
queryBuilder.andWhere("duelLog.name = :roomName", { roomName });
}
if (duelCount != null && !isNaN(duelCount)) {
queryBuilder.andWhere("duelLog.duelCount = :duelCount", { duelCount });
......@@ -278,9 +278,9 @@ class DataManager {
let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id";
const innerQueryParams = {};
if (playerName != null && playerName.length) {
const escapedPlayerName = this.getEscapedString(playerName);
innerQuery += " and duel_log_player.realName like :escapedPlayerName";
innerQueryParams.escapedPlayerName = escapedPlayerName;
//const escapedPlayerName = this.getEscapedString(playerName);
innerQuery += " and duel_log_player.realName = :playerName";
innerQueryParams.playerName = playerName;
}
if (playerScore != null && !isNaN(playerScore)) {
innerQuery += " and duel_log_player.score = :playerScore";
......@@ -710,16 +710,25 @@ class DataManager {
}
async randomDuelPlayerWin(name) {
const score = await this.getOrCreateRandomDuelScore(name);
if (!score) {
return;
}
score.win();
await this.saveRandomDuelScore(score);
}
async randomDuelPlayerLose(name) {
const score = await this.getOrCreateRandomDuelScore(name);
if (!score) {
return;
}
score.lose();
await this.saveRandomDuelScore(score);
}
async randomDuelPlayerFlee(name) {
const score = await this.getOrCreateRandomDuelScore(name);
if (!score) {
return;
}
score.flee();
await this.saveRandomDuelScore(score);
}
......
......@@ -276,8 +276,8 @@ export class DataManager {
const queryBuilder = repo.createQueryBuilder("duelLog")
.where("1");
if(roomName != null && roomName.length) {
const escapedRoomName = this.getEscapedString(roomName);
queryBuilder.andWhere("duelLog.name like :escapedRoomName", { escapedRoomName });
//const escapedRoomName = this.getEscapedString(roomName);
queryBuilder.andWhere("duelLog.name = :roomName", { roomName });
}
if(duelCount != null && !isNaN(duelCount)) {
queryBuilder.andWhere("duelLog.duelCount = :duelCount", { duelCount });
......@@ -286,9 +286,9 @@ export class DataManager {
let innerQuery = "select id from duel_log_player where duel_log_player.duelLogId = duelLog.id";
const innerQueryParams: any = {};
if(playerName != null && playerName.length) {
const escapedPlayerName = this.getEscapedString(playerName);
innerQuery += " and duel_log_player.realName like :escapedPlayerName";
innerQueryParams.escapedPlayerName = escapedPlayerName;
//const escapedPlayerName = this.getEscapedString(playerName);
innerQuery += " and duel_log_player.realName = :playerName";
innerQueryParams.playerName = playerName;
}
if(playerScore != null && !isNaN(playerScore)) {
innerQuery += " and duel_log_player.score = :playerScore";
......@@ -714,16 +714,25 @@ export class DataManager {
}
async randomDuelPlayerWin(name: string) {
const score = await this.getOrCreateRandomDuelScore(name);
if (!score) {
return;
}
score.win();
await this.saveRandomDuelScore(score);
}
async randomDuelPlayerLose(name: string) {
const score = await this.getOrCreateRandomDuelScore(name);
if (!score) {
return;
}
score.lose();
await this.saveRandomDuelScore(score);
}
async randomDuelPlayerFlee(name: string) {
const score = await this.getOrCreateRandomDuelScore(name);
if (!score) {
return;
}
score.flee();
await this.saveRandomDuelScore(score);
}
......
......@@ -7,7 +7,7 @@
"lflist": 0,
"rule": 0,
"mode": 0,
"comment": "rule: 0=OCGONLY, 1=TCGONLY, 2=OT; mode: 0=SINGLE, 1=MATCH, 2=TAG",
"comment": "rule: 0=OCG-ONLY, 1=TCG-ONLY, 2=SC-ONLY, 3=CUSTOM-ONLY, 4=NO-UNIQUE, 5=ALL; mode: 0=SINGLE, 1=MATCH, 2=TAG",
"duel_rule": 5,
"no_check_deck": false,
"no_shuffle_deck": false,
......@@ -20,8 +20,11 @@
},
"modules": {
"welcome": "MyCard YGOPro Server",
"update": "请更新游戏版本",
"update": "请更新你的客户端版本",
"wait_update": "你的客户端版本高于服务器版本,请等待服务器更新",
"stop": false,
"full": "服务器已爆满",
"max_rooms_count": 0,
"side_timeout": false,
"tag_duel_surrender": true,
"replay_delay": true,
......@@ -89,7 +92,17 @@
"blank_pass_modes": {
"S": true,
"M": true,
"T": false
"T": false,
"OOR": true,
"TOR": false,
"OR": true,
"TR": true,
"CR": false,
"OOMR": true,
"TOMR": false,
"OMR": true,
"CMR": false,
"TMR": true
},
"ready_time": 20,
"hang_timeout": 90
......@@ -137,9 +150,9 @@
},
"mycard": {
"enabled": false,
"auth_base_url": "https://ygobbs.com",
"auth_base_url": "https://sapi.moecube.com:444/accounts",
"auth_database": "postgres://233@233.mycard.moe/233",
"ban_get": "https://api.mycard.moe/ygopro/big-brother/ban",
"ban_get": "https://sapi.moecube.com:444/ygopro/big-brother/ban",
"auth_key": "233333"
},
"challonge": {
......@@ -147,6 +160,7 @@
"post_detailed_score": true,
"post_score_midduel": true,
"cache_ttl": 60000,
"no_match_mode": false,
"options": {
"apiKey": "123"
},
......@@ -157,13 +171,13 @@
"enabled": false,
"accesskey": "233",
"local": "./deck_log/",
"post": "https://api.mycard.moe/ygopro/analytics/deck/text",
"post": "https://sapi.moecube.com:444/ygopro/analytics/deck/text",
"arena": "233"
},
"big_brother": {
"enabled": false,
"accesskey": "233",
"post": "https://api.mycard.moe/ygopro/big-brother"
"post": "https://sapi.moecube.com:444/ygopro/big-brother"
},
"arena_mode": {
"enabled": false,
......@@ -171,13 +185,13 @@
"comment": "mode: athletic / entertain",
"accesskey": "233",
"ready_time": 30,
"check_permit": "https://api.mycard.moe/ygopro/match/permit",
"check_permit": "https://sapi.moecube.com:444/ygopro/match/permit",
"post_score": false,
"get_score": false,
"punish_quit_before_match": false,
"init_post": {
"enabled": false,
"url": "https://api.mycard.moe/ygopro/match/clear",
"url": "https://sapi.moecube.com:444/ygopro/match/clear",
"accesskey": "momobako"
}
},
......@@ -197,8 +211,8 @@
},
"athletic_check": {
"enabled": false,
"rankURL": "https://api.mycard.moe/ygopro/analytics/deck/type",
"identifierURL": "https://api.mycard.moe/ygopro/identifier/production",
"rankURL": "https://sapi.moecube.com:444/ygopro/analytics/deck/type",
"identifierURL": "https://sapi.moecube.com:444/ygopro/identifier/production",
"athleticFetchParams": {
"type": "week",
"source": "mycard-athletic"
......
......@@ -6,10 +6,10 @@ server = null
room_data = (room)->
id: room.name,
title: room.title,
title: room.title || room.name,
user: {username: room.username}
users: ({username: client.name, position: client.pos} for client in room.players),
options: room.get_old_hostinfo(), # Should be updated when MyCard client updates
options: room.get_roomlist_hostinfo(), # Should be updated when MyCard client updates
arena: settings.modules.arena_mode.enabled && room.arena && settings.modules.arena_mode.mode
init = (http_server, ROOM_all)->
......
......@@ -14,7 +14,7 @@
var client;
return {
id: room.name,
title: room.title,
title: room.title || room.name,
user: {
username: room.username
},
......@@ -31,7 +31,7 @@
}
return results;
})(),
options: room.get_old_hostinfo(), // Should be updated when MyCard client updates
options: room.get_roomlist_hostinfo(), // Should be updated when MyCard client updates
arena: settings.modules.arena_mode.enabled && room.arena && settings.modules.arena_mode.mode
};
};
......
......@@ -228,6 +228,7 @@ tips = null
words = null
dialogues = null
badwords = null
badwordR = null
lflists = global.lflists = []
real_windbot_server_ip = null
long_resolve_cards = []
......@@ -239,6 +240,12 @@ dataManager = null
windbots = []
disconnect_list = {} # {old_client, old_server, room_id, timeout, deckbuf}
moment_now = global.moment_now = null
moment_now_string = global.moment_now_string = null
moment_long_ago_string = global.moment_long_ago_string = null
rooms_count = 0
challonge = null
challonge_cache = {
participants: null
......@@ -278,6 +285,7 @@ loadLFList = (path) ->
catch
init = () ->
log.info('Reading config.')
await createDirectoryIfNotExists("./config")
await importOldConfig()
defaultConfig = await loadJSONAsync('./data/default_config.json')
......@@ -296,8 +304,12 @@ init = () ->
if settings.modules.http.quick_death_rule == true
settings.modules.http.quick_death_rule = 1
imported = true
else if settings.modules.http.quick_death_rule == false
settings.modules.http.quick_death_rule = 2
imported = true
#import the old passwords to new admin user system
if settings.modules.http.password
log.info('Migrating http user.')
await auth.add_user("olduser", settings.modules.http.password, true, {
"get_rooms": true,
"shout": true,
......@@ -310,6 +322,7 @@ init = () ->
delete settings.modules.http.password
imported = true
if settings.modules.tournament_mode.password
log.info('Migrating tournament user.')
await auth.add_user("tournament", settings.modules.tournament_mode.password, true, {
"duel_log": true,
"download_replay": true,
......@@ -320,12 +333,14 @@ init = () ->
delete settings.modules.tournament_mode.password
imported = true
if settings.modules.pre_util.password
log.info('Migrating pre-dash user.')
await auth.add_user("pre", settings.modules.pre_util.password, true, {
"pre_dashboard": true
})
delete settings.modules.pre_util.password
imported = true
if settings.modules.update_util.password
log.info('Migrating update-dash user.')
await auth.add_user("update", settings.modules.update_util.password, true, {
"update_dashboard": true
})
......@@ -349,16 +364,51 @@ init = () ->
settings.modules.random_duel.blank_pass_modes = {"S":true,"M":true,"T":false}
delete settings.modules.random_duel.blank_pass_match
imported = true
#import the old random_duel.blank_pass_match option
if settings.modules.random_duel.blank_pass_match == true
settings.modules.random_duel.blank_pass_modes = {
"S": true,
"M": true,
"T": false,
"OOR": true,
"TOR": true,
"OR": true,
"TR": true,
"CR": true,
"OOMR": true,
"TOMR": true,
"OMR": true,
"TMR": true,
"CMR": true
}
delete settings.modules.random_duel.blank_pass_match
imported = true
if settings.modules.random_duel.blank_pass_match == false
settings.modules.random_duel.blank_pass_modes = {"S":true,"M":false,"T":false}
settings.modules.random_duel.blank_pass_modes = {
"S": true,
"M": true,
"T": false,
"OOR": true,
"TOR": true,
"OR": true,
"TR": true,
"CR": true,
"OOMR": false,
"TOMR": false,
"OMR": false,
"TMR": false,
"CMR": false
}
delete settings.modules.random_duel.blank_pass_match
imported = true
#finish
if imported
log.info('Saving migrated settings.')
await setting_save(settings)
if settings.modules.mysql.enabled
DataManager = require('./data-manager/DataManager.js').DataManager
dataManager = global.dataManager = new DataManager(settings.modules.mysql.db, log)
log.info('Connecting to database.')
await dataManager.init()
else
log.warn("Some functions may be limited without MySQL .")
......@@ -384,6 +434,7 @@ init = () ->
log.warn("Cannot record random match scores because no MySQL.")
# 读取数据
log.info('Loading data.')
default_data = await loadJSONAsync('./data/default_data.json')
try
tips = global.tips = await loadJSONAsync('./config/tips.json')
......@@ -417,11 +468,13 @@ init = () ->
try
chat_color = await loadJSONAsync('./config/chat_color.json')
if chat_color
log.info("Migrating chat color.")
await dataManager.migrateChatColors(chat_color.save_list);
await fs.promises.rename('./config/chat_color.json', './config/chat_color.json.bak')
log.info("Chat color migrated.")
catch
try
log.info("Reading YGOPro version.")
cppversion = parseInt((await fs.promises.readFile('ygopro/gframe/game.cpp', 'utf8')).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16')
await setting_change(settings, "version", cppversion)
log.info "ygopro version 0x"+settings.version.toString(16), "(from source code)"
......@@ -429,10 +482,37 @@ init = () ->
#settings.version = settings.version_default
log.info "ygopro version 0x"+settings.version.toString(16), "(from config)"
# load the lflist of current date
log.info("Reading banlists.")
await loadLFList('ygopro/expansions/lflist.conf')
await loadLFList('ygopro/lflist.conf')
badwordR = global.badwordR = {}
badwordR.level0=new RegExp('(?:'+badwords.level0.join(')|(?:')+')','i');
badwordR.level1=new RegExp('(?:'+badwords.level1.join(')|(?:')+')','i');
badwordR.level1g=new RegExp('(?:'+badwords.level1.join(')|(?:')+')','ig');
badwordR.level2=new RegExp('(?:'+badwords.level2.join(')|(?:')+')','i');
badwordR.level3=new RegExp('(?:'+badwords.level3.join(')|(?:')+')','i');
setInterval ()->
moment_now = global.moment_now = moment()
moment_now_string = global.moment_now_string = moment_now.format()
moment_long_ago_string = global.moment_long_ago_string = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's').format()
return
, 500
if settings.modules.max_rooms_count
rooms_count=0
get_rooms_count = ()->
_rooms_count=0
for room in ROOM_all when room and room.established
_rooms_count++
rooms_count=_rooms_count
setTimeout get_rooms_count, 1000
return
setTimeout get_rooms_count, 1000
if settings.modules.windbot.enabled
log.info("Reading bot list.")
windbots = global.windbots = (await loadJSONAsync(settings.modules.windbot.botlist)).windbots
real_windbot_server_ip = global.real_windbot_server_ip = settings.modules.windbot.server_ip
if !settings.modules.windbot.server_ip.includes("127.0.0.1")
......@@ -479,6 +559,7 @@ init = () ->
arena: settings.modules.arena_mode.mode
})
try
log.info("Sending arena init post.")
await axios.post(settings.modules.arena_mode.init_post.url + "?" + postData)
catch e
log.warn 'ARENA INIT POST ERROR', e
......@@ -516,11 +597,11 @@ init = () ->
resolve_data = new ResolveData(_data.callback)
if settings.modules.challonge.cache_ttl and !_data.no_cache and challonge_cache[challonge_type]
resolve_data.resolve(null, challonge_cache[challonge_type])
else if is_challonge_requesting[challonge_type] and moment() - is_challonge_requesting[challonge_type] <= 5000
else if is_challonge_requesting[challonge_type] and moment_now.diff(is_challonge_requesting[challonge_type]) <= 5000
challonge_queue_callbacks[challonge_type].push(resolve_data)
else
_data.callback = get_callback(challonge_type, resolve_data)
is_challonge_requesting[challonge_type] = moment()
is_challonge_requesting[challonge_type] = moment_now_string
try
challonge[challonge_type].index(_data)
catch err
......@@ -580,10 +661,10 @@ init = () ->
if settings.modules.random_duel.enabled
setInterval ()->
for room in ROOM_all when room and room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN and room.random_type and room.last_active_time and room.waiting_for_player and room.get_disconnected_count() == 0 and (!settings.modules.side_timeout or room.duel_stage != ygopro.constants.DUEL_STAGE.SIDING) and !room.recovered
time_passed = Math.floor((moment() - room.last_active_time) / 1000)
#log.info time_passed
time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000)
#log.info time_passed, moment_now_string
if time_passed >= settings.modules.random_duel.hang_timeout
room.last_active_time = moment()
room.refreshLastActiveTime()
await ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}")
room.scores[room.waiting_for_player.name_vpass] = -9
#log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
......@@ -599,10 +680,10 @@ init = () ->
if settings.modules.mycard.enabled
setInterval ()->
for room in ROOM_all when room and room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN and room.arena and room.last_active_time and room.waiting_for_player and room.get_disconnected_count() == 0 and (!settings.modules.side_timeout or room.duel_stage != ygopro.constants.DUEL_STAGE.SIDING) and !room.recovered
time_passed = Math.floor((moment() - room.last_active_time) / 1000)
time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000)
#log.info time_passed
if time_passed >= settings.modules.random_duel.hang_timeout
room.last_active_time = moment()
room.refreshLastActiveTime()
ygopro.stoc_send_chat_to_room(room, "#{room.waiting_for_player.name} ${kicked_by_system}", ygopro.constants.COLORS.RED)
room.scores[room.waiting_for_player.name_vpass] = -9
#log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
......@@ -615,7 +696,7 @@ init = () ->
for room in ROOM_all when room and room.arena and room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and room.get_playing_player().length < 2
player = room.get_playing_player()[0]
if player and player.join_time and !player.arena_quit_free
waited_time = moment() - player.join_time
waited_time = moment_now.diff(player.join_time)
if waited_time >= 30000
ygopro.stoc_send_chat(player, "${arena_wait_timeout}", ygopro.constants.COLORS.BABYBLUE)
player.arena_quit_free = true
......@@ -636,13 +717,13 @@ init = () ->
spawn_windbot()
setInterval ()->
current_time = moment()
for room in ROOM_all when room and room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN and room.hostinfo.auto_death and !room.auto_death_triggered and current_time - moment(room.start_time) > 60000 * room.hostinfo.auto_death
for room in ROOM_all when room and room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN and room.hostinfo.auto_death and !room.auto_death_triggered and moment_now.diff(room.start_time) > 60000 * room.hostinfo.auto_death
room.auto_death_triggered = true
room.start_death()
, 1000
log.info("Starting server.")
net.createServer(netRequestHandler).listen settings.port, ->
log.info "server started", settings.port
return
......@@ -763,11 +844,11 @@ ROOM_find_or_create_by_name = global.ROOM_find_or_create_by_name = (name, player
uname=name.toUpperCase()
if settings.modules.windbot.enabled and (uname[0...2] == 'AI' or (!settings.modules.random_duel.enabled and uname == ''))
return ROOM_find_or_create_ai(name)
if settings.modules.random_duel.enabled and (uname == '' or uname == 'S' or uname == 'M' or uname == 'T')
if settings.modules.random_duel.enabled and (uname == '' or uname == 'S' or uname == 'M' or uname == 'T' or uname == 'TOR' or uname == 'TR' or uname == 'OOR' or uname == 'OR' or uname == 'TOMR' or uname == 'TMR' or uname == 'OOMR' or uname == 'OMR' or uname == 'CR' or uname == 'CMR')
return await ROOM_find_or_create_random(uname, player_ip)
if room = ROOM_find_by_name(name)
return room
else if memory_usage >= 90
else if memory_usage >= 90 or (settings.modules.max_rooms_count and rooms_count >= settings.modules.max_rooms_count)
return null
else
room = new Room(name)
......@@ -781,9 +862,9 @@ ROOM_find_or_create_random = global.ROOM_find_or_create_random = (type, player_i
if settings.modules.mysql.enabled
randomDuelBanRecord = await dataManager.getRandomDuelBan(player_ip)
if randomDuelBanRecord
if randomDuelBanRecord.count > 6 and moment().isBefore(randomDuelBanRecord.time)
if randomDuelBanRecord.count > 6 and moment_now.isBefore(randomDuelBanRecord.time)
return {"error": "${random_banned_part1}#{randomDuelBanRecord.reasons.join('${random_ban_reason_separator}')}${random_banned_part2}#{moment(randomDuelBanRecord.time).fromNow(true)}${random_banned_part3}"}
if randomDuelBanRecord.count > 3 and moment().isBefore(randomDuelBanRecord.time) and randomDuelBanRecord.getNeedTip() and type != 'T'
if randomDuelBanRecord.count > 3 and moment_now.isBefore(randomDuelBanRecord.time) and randomDuelBanRecord.getNeedTip() and type != 'T'
randomDuelBanRecord.setNeedTip(false)
await dataManager.updateRandomDuelBan(randomDuelBanRecord)
return {"error": "${random_deprecated_part1}#{randomDuelBanRecord.reasons.join('${random_ban_reason_separator}')}${random_deprecated_part2}#{moment(randomDuelBanRecord.time).fromNow(true)}${random_deprecated_part3}"}
......@@ -795,7 +876,7 @@ ROOM_find_or_create_random = global.ROOM_find_or_create_random = (type, player_i
randomDuelBanRecord.setNeedTip(true)
await dataManager.updateRandomDuelBan(randomDuelBanRecord)
max_player = if type == 'T' then 4 else 2
playerbanned = (randomDuelBanRecord and randomDuelBanRecord.count > 3 and moment() < randomDuelBanRecord.time)
playerbanned = (randomDuelBanRecord and randomDuelBanRecord.count > 3 and moment_now < randomDuelBanRecord.time)
result = _.find ROOM_all, (room)->
return room and room.random_type != '' and room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and !room.windbot and
((type == '' and
......@@ -809,7 +890,7 @@ ROOM_find_or_create_random = global.ROOM_find_or_create_random = (type, player_i
if result
result.welcome = '${random_duel_enter_room_waiting}'
#log.info 'found room', player_name
else if memory_usage < 90
else if memory_usage < 90 and not (settings.modules.max_rooms_count and rooms_count >= settings.modules.max_rooms_count)
type = if type then type else settings.modules.random_duel.default_type
name = type + ',RANDOM#' + Math.floor(Math.random() * 100000)
result = new Room(name)
......@@ -1125,7 +1206,7 @@ CLIENT_reconnect = global.CLIENT_reconnect = (client) ->
client.established = true
client.pre_establish_buffers = []
if room.random_type or room.arena
room.last_active_time = moment()
room.refreshLastActiveTime()
CLIENT_import_data(client, dinfo.old_client, room)
CLIENT_send_reconnect_info(client, client.server, room)
#console.log("#{client.name} ${reconnect_to_game}")
......@@ -1154,7 +1235,7 @@ CLIENT_kick_reconnect = global.CLIENT_kick_reconnect = (client, deckbuf) ->
client.established = true
client.pre_establish_buffers = []
if room.random_type or room.arena
room.last_active_time = moment()
room.refreshLastActiveTime()
CLIENT_import_data(client, player, room)
CLIENT_send_reconnect_info(client, client.server, room)
#console.log("#{client.name} ${reconnect_to_game}")
......@@ -1194,7 +1275,7 @@ CLIENT_heartbeat_register = global.CLIENT_heartbeat_register = (client, send) ->
return true
CLIENT_is_banned_by_mc = global.CLIENT_is_banned_by_mc = (client) ->
return client.ban_mc and client.ban_mc.banned and moment().isBefore(client.ban_mc.until)
return client.ban_mc and client.ban_mc.banned and moment_now.isBefore(client.ban_mc.until)
CLIENT_get_absolute_pos = global.CLIENT_get_absolute_pos = (client) ->
room = ROOM_all[client.rid]
......@@ -1291,7 +1372,7 @@ class Room
@hostinfo.mode = 2
@hostinfo.start_lp = 16000
else if name[0...3] == 'AI#'
@hostinfo.rule = 2
@hostinfo.rule = 5
@hostinfo.lflist = -1
@hostinfo.time_limit = 0
@hostinfo.no_check_deck = true
......@@ -1316,6 +1397,51 @@ class Room
@hostinfo.mode = 2
@hostinfo.start_lp = 16000
if (rule.match /(^|,|,)(OOR|OCGONLYRANDOM)(,|,|$)/)
@hostinfo.rule = 0
@hostinfo.lflist = 0
if (rule.match /(^|,|,)(OR|OCGRANDOM)(,|,|$)/)
@hostinfo.rule = 5
@hostinfo.lflist = 0
if (rule.match /(^|,|,)(CR|CCGRANDOM)(,|,|$)/)
@hostinfo.rule = 2
@hostinfo.lflist = -1
if (rule.match /(^|,|,)(TOR|TCGONLYRANDOM)(,|,|$)/)
@hostinfo.rule = 1
@hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg
if (rule.match /(^|,|,)(TR|TCGRANDOM)(,|,|$)/)
@hostinfo.rule = 5
@hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg
if (rule.match /(^|,|,)(OOMR|OCGONLYMATCHRANDOM)(,|,|$)/)
@hostinfo.rule = 0
@hostinfo.lflist = 0
@hostinfo.mode = 1
if (rule.match /(^|,|,)(OMR|OCGMATCHRANDOM)(,|,|$)/)
@hostinfo.rule = 5
@hostinfo.lflist = 0
@hostinfo.mode = 1
if (rule.match /(^|,|,)(CMR|CCGMATCHRANDOM)(,|,|$)/)
@hostinfo.rule = 2
@hostinfo.lflist = -1
@hostinfo.mode = 1
if (rule.match /(^|,|,)(TOMR|TCGONLYMATCHRANDOM)(,|,|$)/)
@hostinfo.rule = 1
@hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg
@hostinfo.mode = 1
if (rule.match /(^|,|,)(TMR|TCGMATCHRANDOM)(,|,|$)/)
@hostinfo.rule = 5
@hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg
@hostinfo.mode = 1
if (rule.match /(^|,|,)(TCGONLY|TO)(,|,|$)/)
@hostinfo.rule = 1
@hostinfo.lflist = _.findIndex lflists, (list)-> list.tcg
......@@ -1325,7 +1451,11 @@ class Room
@hostinfo.lflist = 0
if (rule.match /(^|,|,)(OT|TCG)(,|,|$)/)
@hostinfo.rule = 5
if (rule.match /(^|,|,)(SC|CN|CCG|CHINESE)(,|,|$)/)
@hostinfo.rule = 2
@hostinfo.lflist = -1
if (param = rule.match /(^|,|,)LP(\d+)(,|,|$)/)
start_lp = parseInt(param[2])
......@@ -1359,6 +1489,9 @@ class Room
@hostinfo.lflist = -1
if (rule.match /(^|,|,)(NOUNIQUE|NU)(,|,|$)/)
@hostinfo.rule = 4
if (rule.match /(^|,|,)(CUSTOM|DIY)(,|,|$)/)
@hostinfo.rule = 3
if (rule.match /(^|,|,)(NOCHECK|NC)(,|,|$)/)
......@@ -1484,7 +1617,7 @@ class Room
ROOM_player_lose(score_array[0].name_vpass)
if settings.modules.arena_mode.enabled and @arena
#log.info 'SCORE', score_array, @start_time
end_time = moment().format()
end_time = moment_now_string
if !@start_time
@start_time = end_time
if score_array.length != 2
......@@ -1514,7 +1647,7 @@ class Room
if error
log.warn 'SCORE POST ERROR', error
else
if response.statusCode != 204 and response.statusCode != 200
if response.statusCode >= 300
log.warn 'SCORE POST FAIL', response.statusCode, response.statusMessage, @name, body
#else
# log.info 'SCORE POST OK', response.statusCode, response.statusMessage, @name, body
......@@ -1626,10 +1759,11 @@ class Room
challonge_duel_log.scoresCsv = "0-0"
return challonge_duel_log
get_old_hostinfo: () -> # Just for supporting websocket roomlist in old MyCard client....
ret = _.clone(@hostinfo)
ret.enable_priority = (@hostinfo.duel_rule != 5)
return ret
get_roomlist_hostinfo: () -> # Just for supporting websocket roomlist in old MyCard client....
#ret = _.clone(@hostinfo)
#ret.enable_priority = (@hostinfo.duel_rule != 5)
#return ret
return @hostinfo
send_replays: () ->
return false unless settings.modules.replay_delay and @replays.length and @hostinfo.mode == 1
......@@ -1673,7 +1807,7 @@ class Room
connect: (client)->
@players.push client
client.join_time = moment()
client.join_time = moment_now_string
if @random_type
client.abuse_count = 0
host_player = @get_host()
......@@ -1722,7 +1856,7 @@ class Room
@finished = true
if !@finished_by_death
@scores[client.name_vpass] = -9
if @random_type and not client.flee_free and (!settings.modules.reconnect.enabled or @get_disconnected_count() == 0)
if @random_type and not client.flee_free and (!settings.modules.reconnect.enabled or @get_disconnected_count() == 0) and not client.kicked_by_system and not client.kicked_by_player
ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}")
if settings.modules.random_duel.record_match_scores and @random_type == 'M'
ROOM_player_flee(client.name_vpass)
......@@ -1872,6 +2006,12 @@ class Room
for line in _.lines lines
ygopro.stoc_send_chat_to_room(this, line, ygopro.constants.COLORS.PINK)
refreshLastActiveTime: (longAgo) ->
if longAgo
@last_active_time = moment_long_ago_string
else
@last_active_time = moment_now_string
# 网络连接
netRequestHandler = (client) ->
client.ip = client.remoteAddress
......@@ -2084,18 +2224,6 @@ ygopro.ctos_follow 'PLAYER_INFO', true, (buffer, info, client, server, datas)->
return false
, name))
client.rag = true
if settings.modules.mycard.enabled and settings.modules.mycard.ban_get and !client.is_local
try
banMCRequest = await axios.get settings.modules.mycard.ban_get,
paramsSerializer: qs.stringify
params:
user: name
if typeof(banMCRequest.data) == "object"
client.ban_mc = banMCRequest.data
else
log.warn "ban get bad json", banMCRequest.data
catch e
log.warn 'ban get error', e.toString()
struct = ygopro.structs.get("CTOS_PlayerInfo")
struct._setBuff(buffer)
struct.set("name", name)
......@@ -2164,7 +2292,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
await client.open_cloud_replay(replay)
else if info.version != settings.version and !settings.alternative_versions.includes(info.version)
ygopro.stoc_send_chat(client, settings.modules.update, ygopro.constants.COLORS.RED)
ygopro.stoc_send_chat(client, (if info.version < settings.version then settings.modules.update else settings.modules.wait_update), ygopro.constants.COLORS.RED)
ygopro.stoc_send client, 'ERROR_MSG', {
msg: 4
code: settings.version
......@@ -2205,6 +2333,19 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
if buffer.length != 6
ygopro.stoc_die(client, '${invalid_password_payload}')
return
if settings.modules.mycard.enabled and settings.modules.mycard.ban_get and !client.is_local
try
banMCRequest = await axios.get settings.modules.mycard.ban_get,
paramsSerializer: qs.stringify
params:
user: name
if typeof(banMCRequest.data) == "object"
client.ban_mc = banMCRequest.data
else
log.warn "ban get bad json", banMCRequest.data
catch e
log.warn 'ban get error', e.toString()
check_buffer_indentity = (buf)->
checksum = 0
......@@ -2215,7 +2356,9 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
create_room_with_action = (buffer, decrypted_buffer, match_permit)->
if client.closed
return
action = buffer.readUInt8(1) >> 4
firstByte = buffer.readUInt8(1)
action = firstByte >> 4
opt0 = firstByte & 0xf
if buffer != decrypted_buffer and action in [1, 2, 4]
ygopro.stoc_die(client, '${invalid_password_unauthorized}')
return
......@@ -2238,37 +2381,32 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
options = {
lflist: settings.hostinfo.lflist
time_limit: settings.hostinfo.time_limit
rule: (opt1 >> 5) & 3
mode: (opt1 >> 3) & 3
duel_rule: (if !!((opt1 >> 2) & 1) then 4 else 5)
rule: (opt1 >> 5) & 0x7 # 0 1 2 3 4 5
mode: (opt1 >> 3) & 0x3 # 0 1 2
duel_rule: (opt0 >> 1) || 5 # 1 2 3 4 5
no_check_deck: !!((opt1 >> 1) & 1)
no_shuffle_deck: !!(opt1 & 1)
start_lp: opt2
start_hand: opt3 >> 4
draw_count: opt3 & 0xF
no_watch: settings.hostinfo.no_watch
auto_death: settings.hostinfo.auto_death
auto_death: !!(opt0 & 0x1) ? 40 : false
}
options.lflist = _.findIndex lflists, (list)-> ((options.rule == 1) == list.tcg) and list.date.isBefore()
#console.log(options)
if(options.rule == 3)
options.lflist = -1
else
options.lflist = _.findIndex lflists, (list)-> ((options.rule == 1) == list.tcg) and list.date.isBefore()
room_title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ')
if _.any(badwords.level3, (badword) ->
regexp = new RegExp(badword, 'i')
return room_title.match(regexp)
, room_title)
if badwordR.level3.test(room_title)
log.warn("BAD ROOM NAME LEVEL 3", room_title, client.name, client.ip)
ygopro.stoc_die(client, "${bad_roomname_level3}")
return
else if _.any(badwords.level2, (badword) ->
regexp = new RegExp(badword, 'i')
return room_title.match(regexp)
, room_title)
else if badwordR.level2.test(room_title)
log.warn("BAD ROOM NAME LEVEL 2", room_title, client.name, client.ip)
ygopro.stoc_die(client, "${bad_roomname_level2}")
return
else if _.any(badwords.level1, (badword) ->
regexp = new RegExp(badword, 'i')
return room_title.match(regexp)
, room_title)
else if badwordR.level1.test(room_title)
log.warn("BAD ROOM NAME LEVEL 1", room_title, client.name, client.ip)
ygopro.stoc_die(client, "${bad_roomname_level1}")
return
......@@ -2307,7 +2445,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
return
if !room
ygopro.stoc_die(client, "${server_full}")
ygopro.stoc_die(client, settings.modules.full)
else if room.error
ygopro.stoc_die(client, room.error)
else
......@@ -2459,16 +2597,20 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
#if found.winnerId
# ygopro.stoc_die(client, '${challonge_match_already_finished}')
# return
create_room_name = 'M#' + found.id
if recover_match
create_room_name = recover_match[0] + ',' + create_room_name
create_room_name = found.id.toString()
if !settings.modules.challonge.no_match_mode
create_room_name = 'M#' + create_room_name
if recover_match
create_room_name = recover_match[0] + ',' + create_room_name
else if recover_match
create_room_name = recover_match[0] + '#' + create_room_name
room = await ROOM_find_or_create_by_name(create_room_name)
if room
room.challonge_info = found
# room.max_player = 2
room.welcome = "${challonge_match_created}"
if !room
ygopro.stoc_die(client, "${server_full}")
ygopro.stoc_die(client, settings.modules.full)
else if room.error
ygopro.stoc_die(client, room.error)
else
......@@ -2483,24 +2625,15 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
log.warn("MULTI LOGIN", client.name, client.ip)
ygopro.stoc_die(client, "${too_much_connection}" + client.ip)
else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and _.any(badwords.level3, (badword) ->
regexp = new RegExp(badword, 'i')
return name.match(regexp)
, name = client.name)
else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and badwordR.level3.test(client.name)
log.warn("BAD NAME LEVEL 3", client.name, client.ip)
ygopro.stoc_die(client, "${bad_name_level3}")
else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and _.any(badwords.level2, (badword) ->
regexp = new RegExp(badword, 'i')
return name.match(regexp)
, name = client.name)
else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and badwordR.level2.test(client.name)
log.warn("BAD NAME LEVEL 2", client.name, client.ip)
ygopro.stoc_die(client, "${bad_name_level2}")
else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and _.any(badwords.level1, (badword) ->
regexp = new RegExp(badword, 'i')
return name.match(regexp)
, name = client.name)
else if !settings.modules.tournament_mode.enabled and !settings.modules.challonge.enabled and badwordR.level1.test(client.name)
log.warn("BAD NAME LEVEL 1", client.name, client.ip)
ygopro.stoc_die(client, "${bad_name_level1}")
......@@ -2518,7 +2651,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
#log.info 'join_game',info.pass, client.name
room = await ROOM_find_or_create_by_name(info.pass, client.ip)
if !room
ygopro.stoc_die(client, "${server_full}")
ygopro.stoc_die(client, settings.modules.full)
else if room.error
ygopro.stoc_die(client, room.error)
else
......@@ -2620,12 +2753,13 @@ 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)
#console.log client.pos, "MSG", ygopro.constants.MSG[msg]
if ygopro.constants.MSG[msg] == 'RETRY' and room.recovering
msg_name = ygopro.constants.MSG[msg]
#console.log client.pos, "MSG", msg_name
if msg_name == 'RETRY' and room.recovering
room.finish_recover(true)
return true
if settings.modules.retry_handle.enabled
if ygopro.constants.MSG[msg] == 'RETRY'
if msg_name == 'RETRY'
if !client.retry_count?
client.retry_count = 0
client.retry_count++
......@@ -2647,11 +2781,11 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
return true
else
client.last_game_msg = buffer
client.last_game_msg_title = ygopro.constants.MSG[msg]
client.last_game_msg_title = msg_name
# log.info(client.name, client.last_game_msg_title)
else if ygopro.constants.MSG[msg] != 'RETRY'
else if msg_name != 'RETRY'
client.last_game_msg = buffer
client.last_game_msg_title = ygopro.constants.MSG[msg]
client.last_game_msg_title = msg_name
# 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开头的消息
......@@ -2662,11 +2796,11 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
return true
else
room.waiting_for_player = client
room.last_active_time = moment()
#log.info("#{ygopro.constants.MSG[msg]}等待#{room.waiting_for_player.name}")
room.refreshLastActiveTime()
#log.info("#{msg_name}等待#{room.waiting_for_player.name}")
#log.info 'MSG', ygopro.constants.MSG[msg]
if ygopro.constants.MSG[msg] == 'START'
#log.info 'MSG', msg_name
if msg_name == 'START'
playertype = buffer.readUInt8(1)
client.is_first = !(playertype & 0xf)
client.lp = room.hostinfo.start_lp
......@@ -2692,12 +2826,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 ygopro.constants.MSG[msg] == 'HINT'
if msg_name == 'HINT'
hint_type = buffer.readUInt8(1)
if hint_type == 3
client.last_hint_msg = buffer
if ygopro.constants.MSG[msg] == 'NEW_TURN'
if msg_name == 'NEW_TURN'
r_player = buffer.readUInt8(1)
if client.pos == 0 and (r_player & 0x2) == 0
room.turn++
......@@ -2719,7 +2853,7 @@ 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 ygopro.constants.MSG[msg] == 'NEW_PHASE'
if msg_name == 'NEW_PHASE'
phase = buffer.readInt16LE(1)
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)
......@@ -2731,7 +2865,7 @@ 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 ygopro.constants.MSG[msg] == 'WIN' and client.pos == 0
if msg_name == 'WIN' and client.pos == 0
if room.recovering
room.finish_recover(true)
return true
......@@ -2769,11 +2903,11 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
else
room.death = 5
if ygopro.constants.MSG[msg] == 'MATCH_KILL' and client.pos == 0
if msg_name == 'MATCH_KILL' and client.pos == 0
room.match_kill = true
#lp跟踪
if ygopro.constants.MSG[msg] == 'DAMAGE' and client.pos == 0
if msg_name == 'DAMAGE' and client.pos == 0
pos = buffer.readUInt8(1)
pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
......@@ -2783,21 +2917,21 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
if 0 < room.dueling_players[pos].lp <= 100
ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK)
if ygopro.constants.MSG[msg] == 'RECOVER' and client.pos == 0
if msg_name == 'RECOVER' and client.pos == 0
pos = buffer.readUInt8(1)
pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2)
room.dueling_players[pos].lp += val
if ygopro.constants.MSG[msg] == 'LPUPDATE' and client.pos == 0
if msg_name == 'LPUPDATE' and client.pos == 0
pos = buffer.readUInt8(1)
pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
val = buffer.readInt32LE(2)
room.dueling_players[pos].lp = val
if ygopro.constants.MSG[msg] == 'PAY_LPCOST' and client.pos == 0
if msg_name == 'PAY_LPCOST' and client.pos == 0
pos = buffer.readUInt8(1)
pos = 1 - pos unless client.is_first
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
......@@ -2809,7 +2943,7 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
#track card count
#todo: track card count in tag mode
if ygopro.constants.MSG[msg] == 'MOVE' and room.hostinfo.mode != 2
if msg_name == 'MOVE' and room.hostinfo.mode != 2
pos = buffer.readUInt8(5)
pos = 1 - pos unless client.is_first
loc = buffer.readUInt8(6)
......@@ -2819,7 +2953,7 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
loc = buffer.readUInt8(10)
client.card_count++ if (loc & 0xe) and pos == 0
if ygopro.constants.MSG[msg] == 'DRAW' and room.hostinfo.mode != 2
if msg_name == 'DRAW' and room.hostinfo.mode != 2
pos = buffer.readUInt8(1)
pos = 1 - pos unless client.is_first
if pos == 0
......@@ -2827,7 +2961,7 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
client.card_count += count
# check panel confirming cards in heartbeat
if settings.modules.heartbeat_detection.enabled and ygopro.constants.MSG[msg] == 'CONFIRM_CARDS'
if settings.modules.heartbeat_detection.enabled and msg_name == 'CONFIRM_CARDS'
check = false
count = buffer.readInt8(2)
max_loop = 3 + (count - 1) * 7
......@@ -2848,7 +2982,7 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
# chain detection
if settings.modules.heartbeat_detection.enabled and client.pos == 0
if ygopro.constants.MSG[msg] == 'CHAINING'
if msg_name == 'CHAINING'
card = buffer.readUInt32LE(1)
found = false
for id in long_resolve_cards when id == card
......@@ -2859,39 +2993,39 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
# console.log(0,card)
else
delete room.long_resolve_card
else if ygopro.constants.MSG[msg] == 'CHAINED' and room.long_resolve_card
else if msg_name == 'CHAINED' and room.long_resolve_card
chain = buffer.readInt8(1)
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 ygopro.constants.MSG[msg] == 'CHAIN_SOLVING' and room.long_resolve_chain
else if msg_name == 'CHAIN_SOLVING' and room.long_resolve_chain
chain = buffer.readInt8(1)
# console.log(2,chain)
if room.long_resolve_chain[chain]
for player in room.get_playing_player()
player.heartbeat_protected = true
else if (ygopro.constants.MSG[msg] == 'CHAIN_NEGATED' or ygopro.constants.MSG[msg] == 'CHAIN_DISABLED') and room.long_resolve_chain
else if (msg_name == 'CHAIN_NEGATED' or msg_name == 'CHAIN_DISABLED') and room.long_resolve_chain
chain = buffer.readInt8(1)
# console.log(3,chain)
delete room.long_resolve_chain[chain]
else if ygopro.constants.MSG[msg] == 'CHAIN_END'
else if msg_name == 'CHAIN_END'
# console.log(4,chain)
delete room.long_resolve_card
delete room.long_resolve_chain
#登场台词
if (settings.modules.dialogues.enabled or settings.modules.vip.enabled) and !room.recovering
if ygopro.constants.MSG[msg] == 'SUMMONING' or ygopro.constants.MSG[msg] == 'SPSUMMONING' or ygopro.constants.MSG[msg] == 'CHAINING'
if msg_name == 'SUMMONING' or msg_name == 'SPSUMMONING' or msg_name == 'CHAINING'
card = buffer.readUInt32LE(1)
trigger_location = buffer.readUInt8(6)
act_pos = buffer.readUInt8(if ygopro.constants.MSG[msg] == 'CHAINING' then 9 else 5)
act_pos = buffer.readUInt8(if msg_name == 'CHAINING' then 9 else 5)
if !room.dueling_players[0].is_first
act_pos = 1 - act_pos
if room.hostinfo.mode == 2
act_pos = act_pos * 2
if ygopro.constants.MSG[msg] != 'CHAINING' or (trigger_location & 0x8) and client.ready_trap
if msg_name != 'CHAINING' or (trigger_location & 0x8) and client.ready_trap
if settings.modules.vip.enabled and await CLIENT_check_vip(room.dueling_players[act_pos]) and dialogText = await dataManager.getUserDialogueText(CLIENT_get_authorize_key(room.dueling_players[act_pos]), card)
client.playLines dialogText
else if settings.modules.vip.enabled and room.hostinfo.mode == 2 and await CLIENT_check_vip(room.dueling_players[act_pos + 1]) and dialogText = await dataManager.getUserDialogueText(CLIENT_get_authorize_key(room.dueling_players[act_pos + 1]), card)
......@@ -2900,16 +3034,16 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server, datas)->
client.playLines dialogues.dialogues[card][Math.floor(Math.random() * dialogues.dialogues[card].length)]
else if settings.modules.dialogues.enabled and dialogues.dialogues_custom[card]
client.playLines dialogues.dialogues_custom[card][Math.floor(Math.random() * dialogues.dialogues_custom[card].length)]
if ygopro.constants.MSG[msg] == 'POS_CHANGE'
if msg_name == 'POS_CHANGE'
loc = buffer.readUInt8(6)
ppos = buffer.readUInt8(8)
cpos = buffer.readUInt8(9)
client.ready_trap = !!(loc & 0x8) and !!(ppos & 0xa) and !!(cpos & 0x5)
else if ygopro.constants.MSG[msg] != 'UPDATE_CARD' and ygopro.constants.MSG[msg] != 'WAITING'
else if msg_name != 'UPDATE_CARD' and msg_name != 'WAITING'
client.ready_trap = false
if room.recovering and client.pos < 4
if ygopro.constants.MSG[msg] != 'WAITING'
if msg_name != 'WAITING'
room.recover_buffers[client.pos].push(buffer)
return true
......@@ -3060,6 +3194,7 @@ ygopro.stoc_follow 'DUEL_END', false, (buffer, info, client, server, datas)->
wait_room_start = (room, time)->
if room and room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and room.ready_player_count_without_host >= room.max_player - 1
#log.info('wait room start', time)
time -= 1
if time
unless time % 5
......@@ -3133,7 +3268,7 @@ ygopro.stoc_follow 'DUEL_START', false, (buffer, info, client, server, datas)->
return unless room and !client.reconnecting
if room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN #first start
room.duel_stage = ygopro.constants.DUEL_STAGE.FINGER
room.start_time = moment().format()
room.start_time = moment_now_string
room.turn = 0
roomlist.start room if !room.windbot and settings.modules.http.websocket_roomlist
#room.duels = []
......@@ -3171,6 +3306,11 @@ ygopro.stoc_follow 'DUEL_START', false, (buffer, info, client, server, datas)->
deck_arena = deck_arena + room.arena
else if room.hostinfo.mode == 2
deck_arena = deck_arena + 'tag'
else if room.random_type and _.endsWith(room.random_type, 'R')
if _.endsWith(room.random_type, 'MR')
deck_arena = deck_arena + 'athletic'
else
deck_arena = deck_arena + 'entertain'
else if room.random_type == 'S'
deck_arena = deck_arena + 'entertain'
else if room.random_type == 'M'
......@@ -3179,7 +3319,7 @@ ygopro.stoc_follow 'DUEL_START', false, (buffer, info, client, server, datas)->
deck_arena = deck_arena + 'custom'
#log.info "DECK LOG START", client.name, room.arena
if settings.modules.deck_log.local
deck_name = moment().format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + client.ip.slice(7) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_')
deck_name = moment_now.format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + client.ip.slice(7) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_')
fs.writeFile settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', (err) ->
if err
log.warn 'DECK SAVE ERROR', err
......@@ -3193,7 +3333,7 @@ ygopro.stoc_follow 'DUEL_START', false, (buffer, info, client, server, datas)->
if error
log.warn 'DECK POST ERROR', error
else
if response.statusCode != 200
if response.statusCode > 300
log.warn 'DECK POST FAIL', response.statusCode, client.name, body
#else
#log.info 'DECK POST OK', response.statusCode, client.name, body
......@@ -3234,7 +3374,7 @@ report_to_big_brother = global.report_to_big_brother = (roomname, sender, ip, le
if error
log.warn 'BIG BROTHER ERROR', error
else
if response.statusCode != 200
if response.statusCode >= 300
log.warn 'BIG BROTHER FAIL', response.statusCode, roomname, body
#else
#log.info 'BIG BROTHER OK', response.statusCode, roomname, body
......@@ -3246,7 +3386,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
return unless room
msg = _.trim(info.msg)
cancel = _.startsWith(msg, "/")
room.last_active_time = moment() unless cancel or not (room.random_type or room.arena) or room.duel_stage == ygopro.constants.DUEL_STAGE.FINGER or room.duel_stage == ygopro.constants.DUEL_STAGE.FIRSTGO or room.duel_stage == ygopro.constants.DUEL_STAGE.SIDING
room.refreshLastActiveTime() unless cancel or not (room.random_type or room.arena) or room.duel_stage == ygopro.constants.DUEL_STAGE.FINGER or room.duel_stage == ygopro.constants.DUEL_STAGE.FIRSTGO or room.duel_stage == ygopro.constants.DUEL_STAGE.SIDING
cmd = msg.split(' ')
isVip = await CLIENT_check_vip(client)
switch cmd[0]
......@@ -3260,7 +3400,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
ygopro.ctos_send(client.server, 'SURRENDER')
else
sur_player = CLIENT_get_partner(client)
if sur_player.closed or sur_player.is_local
if !sur_player or sur_player.closed or sur_player.is_local
sur_player = client
if room.hostinfo.mode==2 and sur_player != client
ygopro.stoc_send_chat(sur_player, "${surrender_confirm_tag}", ygopro.constants.COLORS.BABYBLUE)
......@@ -3422,10 +3562,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
ygopro.stoc_send_chat(client, "${banned_chat_tip}" + (if client.ban_mc and client.ban_mc.message then (": " + client.ban_mc.message) else ""), ygopro.constants.COLORS.RED)
return true
oldmsg = msg
if (_.any(badwords.level3, (badword) ->
regexp = new RegExp(badword, 'i')
return msg.match(regexp)
, msg))
if badwordR.level3.test(msg)
log.warn "BAD WORD LEVEL 3", client.name, client.ip, oldmsg, RegExp.$1
report_to_big_brother room.name, client.name, client.ip, 3, oldmsg, RegExp.$1
cancel = true
......@@ -3451,22 +3588,14 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
client.abuse_count=client.abuse_count+2
ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED)
cancel = true
else if (_.any(badwords.level2, (badword) ->
regexp = new RegExp(badword, 'i')
return msg.match(regexp)
, msg))
else if badwordR.level2.test(msg)
log.warn "BAD WORD LEVEL 2", client.name, client.ip, oldmsg, RegExp.$1
report_to_big_brother room.name, client.name, client.ip, 2, oldmsg, RegExp.$1
client.abuse_count=client.abuse_count+3
ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED)
cancel = true
else
_.each(badwords.level1, (badword) ->
#log.info msg
regexp = new RegExp(badword, "ig")
msg = msg.replace(regexp, "**")
return
, msg)
msg = msg.replace(badwordR.level1g,'**')
if oldmsg != msg
log.warn "BAD WORD LEVEL 1", client.name, client.ip, oldmsg, RegExp.$1
report_to_big_brother room.name, client.name, client.ip, 1, oldmsg, RegExp.$1
......@@ -3476,10 +3605,7 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
struct._setBuff(buffer)
struct.set("msg", msg)
buffer = struct.buffer
else if (_.any(badwords.level0, (badword) ->
regexp = new RegExp(badword, 'i')
return msg.match(regexp)
, msg))
else if badwordR.level0.test(msg)
log.info "BAD WORD LEVEL 0", client.name, client.ip, oldmsg, RegExp.$1
report_to_big_brother room.name, client.name, client.ip, 0, oldmsg, RegExp.$1
if client.abuse_count>=2
......@@ -3543,7 +3669,7 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
if room.random_type or room.arena
if client.pos == 0
room.waiting_for_player = room.waiting_for_player2
room.last_active_time = moment()
room.refreshLastActiveTime()
client.deck_good = true
if room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and room.recovering
recover_player_data = _.find(room.recover_duel_log.players, (player) ->
......@@ -3614,7 +3740,7 @@ ygopro.ctos_follow 'UPDATE_DECK', true, (buffer, info, client, server, datas)->
ygopro.ctos_follow 'RESPONSE', false, (buffer, info, client, server, datas)->
room=ROOM_all[client.rid]
return unless room and (room.random_type or room.arena)
room.last_active_time = moment()
room.refreshLastActiveTime()
await return
ygopro.stoc_follow 'TIME_LIMIT', true, (buffer, info, client, server, datas)->
......@@ -3683,7 +3809,7 @@ ygopro.ctos_follow 'HAND_RESULT', false, (buffer, info, client, server, datas)->
if room.random_type or room.arena
if client.pos == 0
room.waiting_for_player = room.waiting_for_player2
room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's')
room.refreshLastActiveTime(true)
await return
ygopro.ctos_follow 'TP_RESULT', false, (buffer, info, client, server, datas)->
......@@ -3692,7 +3818,7 @@ ygopro.ctos_follow 'TP_RESULT', false, (buffer, info, client, server, datas)->
client.selected_preduel = true
# room.selecting_tp = false
return unless room.random_type or room.arena
room.last_active_time = moment()
room.refreshLastActiveTime()
await return
ygopro.stoc_follow 'CHAT', true, (buffer, info, client, server, datas)->
......@@ -3731,7 +3857,7 @@ ygopro.stoc_follow 'SELECT_HAND', true, (buffer, info, client, server, datas)->
room.waiting_for_player = client
else
room.waiting_for_player2 = client
room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's')
room.refreshLastActiveTime(true)
if room.determine_firstgo
ygopro.ctos_send(server, "HAND_RESULT", {
res: if client.pos == 0 then 2 else 1
......@@ -3752,7 +3878,7 @@ ygopro.stoc_follow 'SELECT_TP', true, (buffer, info, client, server, datas)->
room.duel_stage = ygopro.constants.DUEL_STAGE.FIRSTGO
if room.random_type or room.arena
room.waiting_for_player = client
room.last_active_time = moment()
room.refreshLastActiveTime()
if room.determine_firstgo
ygopro.ctos_send(server, "TP_RESULT", {
res: if room.determine_firstgo == client then 1 else 0
......@@ -3808,7 +3934,7 @@ ygopro.stoc_follow 'CHANGE_SIDE', false, (buffer, info, client, server, datas)->
room.waiting_for_player = client
else
room.waiting_for_player2 = client
room.last_active_time = moment()
room.refreshLastActiveTime()
await return
ygopro.stoc_follow 'REPLAY', true, (buffer, info, client, server, datas)->
......@@ -3817,9 +3943,9 @@ ygopro.stoc_follow 'REPLAY', true, (buffer, info, client, server, datas)->
if !room.replays[room.duel_count - 1]
# console.log("Replay saved: ", room.duel_count - 1, client.pos)
room.replays[room.duel_count - 1] = buffer
if settings.modules.mysql.enabled
if settings.modules.mysql.enabled or room.has_ygopro_error
if client.pos == 0
replay_filename=moment().format("YYYY-MM-DD HH-mm-ss")
replay_filename=moment_now.format("YYYY-MM-DD HH-mm-ss")
if room.hostinfo.mode != 2
for player,i in room.dueling_players
replay_filename=replay_filename + (if i > 0 then " VS " else " ") + player.name
......@@ -3827,29 +3953,30 @@ ygopro.stoc_follow 'REPLAY', true, (buffer, info, client, server, datas)->
for player,i in room.dueling_players
replay_filename=replay_filename + (if i > 0 then (if i == 2 then " VS " else " & ") else " ") + player.name
replay_filename=replay_filename.replace(/[\/\\\?\*]/g, '_')+".yrp"
playerInfos = room.dueling_players.map((player) ->
return {
name: player.name
pos: player.pos
realName: player.name_vpass
startDeckBuffer: player.start_deckbuf
deck: {
main: player.main,
side: player.side
}
isFirst: player.is_first
winner: player.pos == room.winner
ip: player.ip
score: room.scores[player.name_vpass]
lp: if player.lp? then player.lp else room.hostinfo.start_lp
cardCount: if player.card_count? then player.card_count else room.hostinfo.start_hand
}
)
fs.writeFile(settings.modules.tournament_mode.replay_path + replay_filename, buffer, (err)->
if err then log.warn "SAVE REPLAY ERROR", replay_filename, err
)
dataManager.saveDuelLog(room.name, room.process_pid, room.cloud_replay_id, replay_filename, room.hostinfo.mode, room.duel_count, playerInfos) # no synchronize here because too slow
if settings.modules.cloud_replay.enabled and settings.modules.tournament_mode.enabled and settings.modules.tournament_mode.replay_safe
if settings.modules.mysql.enabled
playerInfos = room.dueling_players.map((player) ->
return {
name: player.name
pos: player.pos
realName: player.name_vpass
startDeckBuffer: player.start_deckbuf
deck: {
main: player.main,
side: player.side
}
isFirst: player.is_first
winner: player.pos == room.winner
ip: player.ip
score: room.scores[player.name_vpass]
lp: if player.lp? then player.lp else room.hostinfo.start_lp
cardCount: if player.card_count? then player.card_count else room.hostinfo.start_hand
}
)
dataManager.saveDuelLog(room.name, room.process_pid, room.cloud_replay_id, replay_filename, room.hostinfo.mode, room.duel_count, playerInfos) # no synchronize here because too slow
if settings.modules.mysql.enabled && settings.modules.cloud_replay.enabled and settings.modules.tournament_mode.enabled and settings.modules.tournament_mode.replay_safe
ygopro.stoc_send_chat(client, "${cloud_replay_delay_part1}R##{room.cloud_replay_id}${cloud_replay_delay_part2}", ygopro.constants.COLORS.BABYBLUE)
await return settings.modules.tournament_mode.enabled and settings.modules.tournament_mode.block_replay_to_player or settings.modules.replay_delay and room.hostinfo.mode == 1
else
......@@ -4009,7 +4136,7 @@ if true
else
response.writeHead(200)
if settings.modules.tournament_mode.log_save_path
fs.writeFile(settings.modules.tournament_mode.log_save_path + 'duel_log.' + moment().format('YYYY-MM-DD HH-mm-ss') + '.json', JSON.stringify(await dataManager.getDuelLogJSON(settings.modules.tournament_mode), null, 2), (err) ->
fs.writeFile(settings.modules.tournament_mode.log_save_path + 'duel_log.' + moment_now.format('YYYY-MM-DD HH-mm-ss') + '.json', JSON.stringify(await dataManager.getDuelLogJSON(settings.modules.tournament_mode), null, 2), (err) ->
if err
log.warn 'DUEL LOG SAVE ERROR', err
)
......
// Generated by CoffeeScript 2.5.1
(function() {
// 标准库
var CLIENT_check_vip, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_get_save_data, 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_vip_status, CLIENT_use_cdkey, 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, VIP_generate_cdkeys, _, _async, addCallback, athleticChecker, auth, axios, badwords, ban_user, bunyan, challonge, challonge_cache, challonge_queue_callbacks, checkFileExists, concat_name, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, fs, geoip, getDuelLogQueryFromQs, getSeedTimet, get_callback, get_memory_usage, http, httpRequestListener, importOldConfig, import_datas, init, is_challonge_requesting, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_dialogues_custom, load_tips, load_tips_zh, load_words, log, long_resolve_cards, memory_usage, merge, moment, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, refresh_challonge_cache, release_disconnect, replaced_index, report_to_big_brother, request, roomlist, setting_change, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, url, users_cache, util, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, words, ygopro, zlib;
var CLIENT_check_vip, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_get_save_data, 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_vip_status, CLIENT_use_cdkey, 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, VIP_generate_cdkeys, _, _async, addCallback, athleticChecker, auth, axios, badwordR, badwords, ban_user, bunyan, challonge, challonge_cache, challonge_queue_callbacks, checkFileExists, concat_name, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, fs, geoip, getDuelLogQueryFromQs, getSeedTimet, get_callback, get_memory_usage, http, httpRequestListener, importOldConfig, import_datas, init, is_challonge_requesting, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_dialogues_custom, load_tips, load_tips_zh, load_words, log, long_resolve_cards, memory_usage, merge, moment, moment_long_ago_string, moment_now, moment_now_string, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, refresh_challonge_cache, release_disconnect, replaced_index, report_to_big_brother, request, roomlist, rooms_count, setting_change, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, url, users_cache, util, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, words, ygopro, zlib;
net = require('net');
......@@ -276,6 +276,8 @@
badwords = null;
badwordR = null;
lflists = global.lflists = [];
real_windbot_server_ip = null;
......@@ -296,6 +298,14 @@
disconnect_list = {}; // {old_client, old_server, room_id, timeout, deckbuf}
moment_now = global.moment_now = null;
moment_now_string = global.moment_now_string = null;
moment_long_ago_string = global.moment_long_ago_string = null;
rooms_count = 0;
challonge = null;
challonge_cache = {
......@@ -365,7 +375,8 @@
};
init = async function() {
var AthleticChecker, DataManager, challonge_module_name, challonge_type, chat_color, config, cppversion, defaultConfig, default_data, dirPath, dns, e, http_server, https, https_server, imported, j, l, len, len1, len2, m, mkdirList, options, pgClient, pg_client, pg_query, plugin_filename, plugin_list, plugin_path, postData, ref, vip_info;
var AthleticChecker, DataManager, challonge_module_name, challonge_type, chat_color, config, cppversion, defaultConfig, default_data, dirPath, dns, e, get_rooms_count, http_server, https, https_server, imported, j, l, len, len1, len2, m, mkdirList, options, pgClient, pg_client, pg_query, plugin_filename, plugin_list, plugin_path, postData, ref, vip_info;
log.info('Reading config.');
await createDirectoryIfNotExists("./config");
await importOldConfig();
defaultConfig = (await loadJSONAsync('./data/default_config.json'));
......@@ -391,9 +402,13 @@
if (settings.modules.http.quick_death_rule === true) {
settings.modules.http.quick_death_rule = 1;
imported = true;
} else if (settings.modules.http.quick_death_rule === false) {
settings.modules.http.quick_death_rule = 2;
imported = true;
}
//import the old passwords to new admin user system
if (settings.modules.http.password) {
log.info('Migrating http user.');
await auth.add_user("olduser", settings.modules.http.password, true, {
"get_rooms": true,
"shout": true,
......@@ -407,6 +422,7 @@
imported = true;
}
if (settings.modules.tournament_mode.password) {
log.info('Migrating tournament user.');
await auth.add_user("tournament", settings.modules.tournament_mode.password, true, {
"duel_log": true,
"download_replay": true,
......@@ -418,6 +434,7 @@
imported = true;
}
if (settings.modules.pre_util.password) {
log.info('Migrating pre-dash user.');
await auth.add_user("pre", settings.modules.pre_util.password, true, {
"pre_dashboard": true
});
......@@ -425,6 +442,7 @@
imported = true;
}
if (settings.modules.update_util.password) {
log.info('Migrating update-dash user.');
await auth.add_user("update", settings.modules.update_util.password, true, {
"update_dashboard": true
});
......@@ -457,22 +475,54 @@
delete settings.modules.random_duel.blank_pass_match;
imported = true;
}
//import the old random_duel.blank_pass_match option
if (settings.modules.random_duel.blank_pass_match === true) {
settings.modules.random_duel.blank_pass_modes = {
"S": true,
"M": true,
"T": false,
"OOR": true,
"TOR": true,
"OR": true,
"TR": true,
"CR": true,
"OOMR": true,
"TOMR": true,
"OMR": true,
"TMR": true,
"CMR": true
};
delete settings.modules.random_duel.blank_pass_match;
imported = true;
}
if (settings.modules.random_duel.blank_pass_match === false) {
settings.modules.random_duel.blank_pass_modes = {
"S": true,
"M": false,
"T": false
"M": true,
"T": false,
"OOR": true,
"TOR": true,
"OR": true,
"TR": true,
"CR": true,
"OOMR": false,
"TOMR": false,
"OMR": false,
"TMR": false,
"CMR": false
};
delete settings.modules.random_duel.blank_pass_match;
imported = true;
}
//finish
if (imported) {
log.info('Saving migrated settings.');
await setting_save(settings);
}
if (settings.modules.mysql.enabled) {
DataManager = require('./data-manager/DataManager.js').DataManager;
dataManager = global.dataManager = new DataManager(settings.modules.mysql.db, log);
log.info('Connecting to database.');
await dataManager.init();
} else {
log.warn("Some functions may be limited without MySQL .");
......@@ -503,6 +553,7 @@
}
}
// 读取数据
log.info('Loading data.');
default_data = (await loadJSONAsync('./data/default_data.json'));
try {
tips = global.tips = (await loadJSONAsync('./config/tips.json'));
......@@ -544,6 +595,7 @@
try {
chat_color = (await loadJSONAsync('./config/chat_color.json'));
if (chat_color) {
log.info("Migrating chat color.");
await dataManager.migrateChatColors(chat_color.save_list);
await fs.promises.rename('./config/chat_color.json', './config/chat_color.json.bak');
log.info("Chat color migrated.");
......@@ -553,6 +605,7 @@
}
}
try {
log.info("Reading YGOPro version.");
cppversion = parseInt(((await fs.promises.readFile('ygopro/gframe/game.cpp', 'utf8'))).match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16');
await setting_change(settings, "version", cppversion);
log.info("ygopro version 0x" + settings.version.toString(16), "(from source code)");
......@@ -561,9 +614,38 @@
log.info("ygopro version 0x" + settings.version.toString(16), "(from config)");
}
// load the lflist of current date
log.info("Reading banlists.");
await loadLFList('ygopro/expansions/lflist.conf');
await loadLFList('ygopro/lflist.conf');
badwordR = global.badwordR = {};
badwordR.level0 = new RegExp('(?:' + badwords.level0.join(')|(?:') + ')', 'i');
badwordR.level1 = new RegExp('(?:' + badwords.level1.join(')|(?:') + ')', 'i');
badwordR.level1g = new RegExp('(?:' + badwords.level1.join(')|(?:') + ')', 'ig');
badwordR.level2 = new RegExp('(?:' + badwords.level2.join(')|(?:') + ')', 'i');
badwordR.level3 = new RegExp('(?:' + badwords.level3.join(')|(?:') + ')', 'i');
setInterval(function() {
moment_now = global.moment_now = moment();
moment_now_string = global.moment_now_string = moment_now.format();
moment_long_ago_string = global.moment_long_ago_string = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's').format();
}, 500);
if (settings.modules.max_rooms_count) {
rooms_count = 0;
get_rooms_count = function() {
var _rooms_count, j, len, room;
_rooms_count = 0;
for (j = 0, len = ROOM_all.length; j < len; j++) {
room = ROOM_all[j];
if (room && room.established) {
_rooms_count++;
}
}
rooms_count = _rooms_count;
setTimeout(get_rooms_count, 1000);
};
setTimeout(get_rooms_count, 1000);
}
if (settings.modules.windbot.enabled) {
log.info("Reading bot list.");
windbots = global.windbots = ((await loadJSONAsync(settings.modules.windbot.botlist))).windbots;
real_windbot_server_ip = global.real_windbot_server_ip = settings.modules.windbot.server_ip;
if (!settings.modules.windbot.server_ip.includes("127.0.0.1")) {
......@@ -613,6 +695,7 @@
arena: settings.modules.arena_mode.mode
});
try {
log.info("Sending arena init post.");
await axios.post(settings.modules.arena_mode.init_post.url + "?" + postData);
} catch (error1) {
e = error1;
......@@ -658,11 +741,11 @@
resolve_data = new ResolveData(_data.callback);
if (settings.modules.challonge.cache_ttl && !_data.no_cache && challonge_cache[challonge_type]) {
resolve_data.resolve(null, challonge_cache[challonge_type]);
} else if (is_challonge_requesting[challonge_type] && moment() - is_challonge_requesting[challonge_type] <= 5000) {
} else if (is_challonge_requesting[challonge_type] && moment_now.diff(is_challonge_requesting[challonge_type]) <= 5000) {
challonge_queue_callbacks[challonge_type].push(resolve_data);
} else {
_data.callback = get_callback(challonge_type, resolve_data);
is_challonge_requesting[challonge_type] = moment();
is_challonge_requesting[challonge_type] = moment_now_string;
try {
challonge[challonge_type].index(_data);
} catch (error1) {
......@@ -748,10 +831,10 @@
if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.random_type && room.last_active_time && room.waiting_for_player && room.get_disconnected_count() === 0 && (!settings.modules.side_timeout || room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING) && !room.recovered)) {
continue;
}
time_passed = Math.floor((moment() - room.last_active_time) / 1000);
//log.info time_passed
time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000);
//log.info time_passed, moment_now_string
if (time_passed >= settings.modules.random_duel.hang_timeout) {
room.last_active_time = moment();
room.refreshLastActiveTime();
await ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}");
room.scores[room.waiting_for_player.name_vpass] = -9;
//log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
......@@ -773,10 +856,10 @@
if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.arena && room.last_active_time && room.waiting_for_player && room.get_disconnected_count() === 0 && (!settings.modules.side_timeout || room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING) && !room.recovered)) {
continue;
}
time_passed = Math.floor((moment() - room.last_active_time) / 1000);
time_passed = Math.floor(moment_now.diff(room.last_active_time) / 1000);
//log.info time_passed
if (time_passed >= settings.modules.random_duel.hang_timeout) {
room.last_active_time = moment();
room.refreshLastActiveTime();
ygopro.stoc_send_chat_to_room(room, `${room.waiting_for_player.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED);
room.scores[room.waiting_for_player.name_vpass] = -9;
//log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
......@@ -794,7 +877,7 @@
}
player = room.get_playing_player()[0];
if (player && player.join_time && !player.arena_quit_free) {
waited_time = moment() - player.join_time;
waited_time = moment_now.diff(player.join_time);
if (waited_time >= 30000) {
ygopro.stoc_send_chat(player, "${arena_wait_timeout}", ygopro.constants.COLORS.BABYBLUE);
player.arena_quit_free = true;
......@@ -827,12 +910,11 @@
spawn_windbot();
}
setInterval(function() {
var current_time, l, len1, results, room;
current_time = moment();
var l, len1, results, room;
results = [];
for (l = 0, len1 = ROOM_all.length; l < len1; l++) {
room = ROOM_all[l];
if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.hostinfo.auto_death && !room.auto_death_triggered && current_time - moment(room.start_time) > 60000 * room.hostinfo.auto_death)) {
if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.hostinfo.auto_death && !room.auto_death_triggered && moment_now.diff(room.start_time) > 60000 * room.hostinfo.auto_death)) {
continue;
}
room.auto_death_triggered = true;
......@@ -840,6 +922,7 @@
}
return results;
}, 1000);
log.info("Starting server.");
net.createServer(netRequestHandler).listen(settings.port, function() {
log.info("server started", settings.port);
});
......@@ -991,12 +1074,12 @@
if (settings.modules.windbot.enabled && (uname.slice(0, 2) === 'AI' || (!settings.modules.random_duel.enabled && uname === ''))) {
return ROOM_find_or_create_ai(name);
}
if (settings.modules.random_duel.enabled && (uname === '' || uname === 'S' || uname === 'M' || uname === 'T')) {
if (settings.modules.random_duel.enabled && (uname === '' || uname === 'S' || uname === 'M' || uname === 'T' || uname === 'TOR' || uname === 'TR' || uname === 'OOR' || uname === 'OR' || uname === 'TOMR' || uname === 'TMR' || uname === 'OOMR' || uname === 'OMR' || uname === 'CR' || uname === 'CMR')) {
return (await ROOM_find_or_create_random(uname, player_ip));
}
if (room = ROOM_find_by_name(name)) {
return room;
} else if (memory_usage >= 90) {
} else if (memory_usage >= 90 || (settings.modules.max_rooms_count && rooms_count >= settings.modules.max_rooms_count)) {
return null;
} else {
room = new Room(name);
......@@ -1017,12 +1100,12 @@
if (settings.modules.mysql.enabled) {
randomDuelBanRecord = (await dataManager.getRandomDuelBan(player_ip));
if (randomDuelBanRecord) {
if (randomDuelBanRecord.count > 6 && moment().isBefore(randomDuelBanRecord.time)) {
if (randomDuelBanRecord.count > 6 && moment_now.isBefore(randomDuelBanRecord.time)) {
return {
"error": `\${random_banned_part1}${randomDuelBanRecord.reasons.join('${random_ban_reason_separator}')}\${random_banned_part2}${moment(randomDuelBanRecord.time).fromNow(true)}\${random_banned_part3}`
};
}
if (randomDuelBanRecord.count > 3 && moment().isBefore(randomDuelBanRecord.time) && randomDuelBanRecord.getNeedTip() && type !== 'T') {
if (randomDuelBanRecord.count > 3 && moment_now.isBefore(randomDuelBanRecord.time) && randomDuelBanRecord.getNeedTip() && type !== 'T') {
randomDuelBanRecord.setNeedTip(false);
await dataManager.updateRandomDuelBan(randomDuelBanRecord);
return {
......@@ -1041,14 +1124,14 @@
}
}
max_player = type === 'T' ? 4 : 2;
playerbanned = randomDuelBanRecord && randomDuelBanRecord.count > 3 && moment() < randomDuelBanRecord.time;
playerbanned = randomDuelBanRecord && randomDuelBanRecord.count > 3 && moment_now < randomDuelBanRecord.time;
result = _.find(ROOM_all, function(room) {
return room && room.random_type !== '' && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && !room.windbot && ((type === '' && (room.random_type === settings.modules.random_duel.default_type || settings.modules.random_duel.blank_pass_modes[room.random_type])) || room.random_type === type) && room.get_playing_player().length < max_player && (settings.modules.random_duel.no_rematch_check || room.get_host() === null || room.get_host().ip !== ROOM_players_oppentlist[player_ip]) && (playerbanned === room.deprecated || type === 'T');
});
if (result) {
result.welcome = '${random_duel_enter_room_waiting}';
//log.info 'found room', player_name
} else if (memory_usage < 90) {
} else if (memory_usage < 90 && !(settings.modules.max_rooms_count && rooms_count >= settings.modules.max_rooms_count)) {
type = type ? type : settings.modules.random_duel.default_type;
name = type + ',RANDOM#' + Math.floor(Math.random() * 100000);
result = new Room(name);
......@@ -1496,7 +1579,7 @@
client.established = true;
client.pre_establish_buffers = [];
if (room.random_type || room.arena) {
room.last_active_time = moment();
room.refreshLastActiveTime();
}
CLIENT_import_data(client, dinfo.old_client, room);
CLIENT_send_reconnect_info(client, client.server, room);
......@@ -1528,7 +1611,7 @@
client.established = true;
client.pre_establish_buffers = [];
if (room.random_type || room.arena) {
room.last_active_time = moment();
room.refreshLastActiveTime();
}
CLIENT_import_data(client, player, room);
CLIENT_send_reconnect_info(client, client.server, room);
......@@ -1576,7 +1659,7 @@
};
CLIENT_is_banned_by_mc = global.CLIENT_is_banned_by_mc = function(client) {
return client.ban_mc && client.ban_mc.banned && moment().isBefore(client.ban_mc.until);
return client.ban_mc && client.ban_mc.banned && moment_now.isBefore(client.ban_mc.until);
};
CLIENT_get_absolute_pos = global.CLIENT_get_absolute_pos = function(client) {
......@@ -1703,7 +1786,7 @@
this.hostinfo.mode = 2;
this.hostinfo.start_lp = 16000;
} else if (name.slice(0, 3) === 'AI#') {
this.hostinfo.rule = 2;
this.hostinfo.rule = 5;
this.hostinfo.lflist = -1;
this.hostinfo.time_limit = 0;
this.hostinfo.no_check_deck = true;
......@@ -1725,6 +1808,59 @@
this.hostinfo.mode = 2;
this.hostinfo.start_lp = 16000;
}
if (rule.match(/(^|,|,)(OOR|OCGONLYRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 0;
this.hostinfo.lflist = 0;
}
if (rule.match(/(^|,|,)(OR|OCGRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 5;
this.hostinfo.lflist = 0;
}
if (rule.match(/(^|,|,)(CR|CCGRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 2;
this.hostinfo.lflist = -1;
}
if (rule.match(/(^|,|,)(TOR|TCGONLYRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 1;
this.hostinfo.lflist = _.findIndex(lflists, function(list) {
return list.tcg;
});
}
if (rule.match(/(^|,|,)(TR|TCGRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 5;
this.hostinfo.lflist = _.findIndex(lflists, function(list) {
return list.tcg;
});
}
if (rule.match(/(^|,|,)(OOMR|OCGONLYMATCHRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 0;
this.hostinfo.lflist = 0;
this.hostinfo.mode = 1;
}
if (rule.match(/(^|,|,)(OMR|OCGMATCHRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 5;
this.hostinfo.lflist = 0;
this.hostinfo.mode = 1;
}
if (rule.match(/(^|,|,)(CMR|CCGMATCHRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 2;
this.hostinfo.lflist = -1;
this.hostinfo.mode = 1;
}
if (rule.match(/(^|,|,)(TOMR|TCGONLYMATCHRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 1;
this.hostinfo.lflist = _.findIndex(lflists, function(list) {
return list.tcg;
});
this.hostinfo.mode = 1;
}
if (rule.match(/(^|,|,)(TMR|TCGMATCHRANDOM)(,|,|$)/)) {
this.hostinfo.rule = 5;
this.hostinfo.lflist = _.findIndex(lflists, function(list) {
return list.tcg;
});
this.hostinfo.mode = 1;
}
if (rule.match(/(^|,|,)(TCGONLY|TO)(,|,|$)/)) {
this.hostinfo.rule = 1;
this.hostinfo.lflist = _.findIndex(lflists, function(list) {
......@@ -1736,7 +1872,11 @@
this.hostinfo.lflist = 0;
}
if (rule.match(/(^|,|,)(OT|TCG)(,|,|$)/)) {
this.hostinfo.rule = 5;
}
if (rule.match(/(^|,|,)(SC|CN|CCG|CHINESE)(,|,|$)/)) {
this.hostinfo.rule = 2;
this.hostinfo.lflist = -1;
}
if ((param = rule.match(/(^|,|,)LP(\d+)(,|,|$)/))) {
start_lp = parseInt(param[2]);
......@@ -1786,6 +1926,9 @@
this.hostinfo.lflist = -1;
}
if (rule.match(/(^|,|,)(NOUNIQUE|NU)(,|,|$)/)) {
this.hostinfo.rule = 4;
}
if (rule.match(/(^|,|,)(CUSTOM|DIY)(,|,|$)/)) {
this.hostinfo.rule = 3;
}
if (rule.match(/(^|,|,)(NOCHECK|NC)(,|,|$)/)) {
......@@ -1953,7 +2096,7 @@
}
if (settings.modules.arena_mode.enabled && this.arena) {
//log.info 'SCORE', score_array, @start_time
end_time = moment().format();
end_time = moment_now_string;
if (!this.start_time) {
this.start_time = end_time;
}
......@@ -2003,7 +2146,7 @@
if (error) {
log.warn('SCORE POST ERROR', error);
} else {
if (response.statusCode !== 204 && response.statusCode !== 200) {
if (response.statusCode >= 300) {
log.warn('SCORE POST FAIL', response.statusCode, response.statusMessage, this.name, body);
}
}
......@@ -2156,11 +2299,11 @@
return challonge_duel_log;
}
get_old_hostinfo() { // Just for supporting websocket roomlist in old MyCard client....
var ret;
ret = _.clone(this.hostinfo);
ret.enable_priority = this.hostinfo.duel_rule !== 5;
return ret;
get_roomlist_hostinfo() { // Just for supporting websocket roomlist in old MyCard client....
//ret = _.clone(@hostinfo)
//ret.enable_priority = (@hostinfo.duel_rule != 5)
//return ret
return this.hostinfo;
}
send_replays() {
......@@ -2228,7 +2371,7 @@
connect(client) {
var host_player;
this.players.push(client);
client.join_time = moment();
client.join_time = moment_now_string;
if (this.random_type) {
client.abuse_count = 0;
host_player = this.get_host();
......@@ -2305,7 +2448,7 @@
this.finished = true;
if (!this.finished_by_death) {
this.scores[client.name_vpass] = -9;
if (this.random_type && !client.flee_free && (!settings.modules.reconnect.enabled || this.get_disconnected_count() === 0)) {
if (this.random_type && !client.flee_free && (!settings.modules.reconnect.enabled || this.get_disconnected_count() === 0) && !client.kicked_by_system && !client.kicked_by_player) {
ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}");
if (settings.modules.random_duel.record_match_scores && this.random_type === 'M') {
ROOM_player_flee(client.name_vpass);
......@@ -2541,6 +2684,14 @@
return results;
}
refreshLastActiveTime(longAgo) {
if (longAgo) {
return this.last_active_time = moment_long_ago_string;
} else {
return this.last_active_time = moment_now_string;
}
}
};
// 网络连接
......@@ -2796,7 +2947,7 @@
// 功能模块
// return true to cancel a synchronous message
ygopro.ctos_follow('PLAYER_INFO', true, async function(buffer, info, client, server, datas) {
var banMCRequest, e, geo, lang, name, name_full, struct, vpass;
var geo, lang, name, name_full, struct, vpass;
// checkmate use username$password, but here don't
// so remove the password
name_full = info.name.replace(/\\/g, "").split("$");
......@@ -2817,24 +2968,6 @@
}, name)) {
client.rag = true;
}
if (settings.modules.mycard.enabled && settings.modules.mycard.ban_get && !client.is_local) {
try {
banMCRequest = (await axios.get(settings.modules.mycard.ban_get, {
paramsSerializer: qs.stringify,
params: {
user: name
}
}));
if (typeof banMCRequest.data === "object") {
client.ban_mc = banMCRequest.data;
} else {
log.warn("ban get bad json", banMCRequest.data);
}
} catch (error1) {
e = error1;
log.warn('ban get error', e.toString());
}
}
struct = ygopro.structs.get("CTOS_PlayerInfo");
struct._setBuff(buffer);
struct.set("name", name);
......@@ -2863,7 +2996,7 @@
});
ygopro.ctos_follow('JOIN_GAME', true, async function(buffer, info, client, server, datas) {
var available_logs, check_buffer_indentity, create_room_with_action, duelLog, exactBan, index, j, l, len, len1, name, pre_room, recover_match, replay, replay_id, replays, room, struct;
var available_logs, banMCRequest, check_buffer_indentity, create_room_with_action, duelLog, e, exactBan, index, j, l, len, len1, pre_room, recover_match, replay, replay_id, replays, room, struct;
//log.info info
info.pass = info.pass.trim();
client.pass = info.pass;
......@@ -2906,7 +3039,7 @@
replay = (await dataManager.getRandomCloudReplay());
await client.open_cloud_replay(replay);
} else if (info.version !== settings.version && !settings.alternative_versions.includes(info.version)) {
ygopro.stoc_send_chat(client, settings.modules.update, ygopro.constants.COLORS.RED);
ygopro.stoc_send_chat(client, (info.version < settings.version ? settings.modules.update : settings.modules.wait_update), ygopro.constants.COLORS.RED);
ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 4,
code: settings.version
......@@ -2943,6 +3076,24 @@
ygopro.stoc_die(client, '${invalid_password_payload}');
return;
}
if (settings.modules.mycard.enabled && settings.modules.mycard.ban_get && !client.is_local) {
try {
banMCRequest = (await axios.get(settings.modules.mycard.ban_get, {
paramsSerializer: qs.stringify,
params: {
user: name
}
}));
if (typeof banMCRequest.data === "object") {
client.ban_mc = banMCRequest.data;
} else {
log.warn("ban get bad json", banMCRequest.data);
}
} catch (error1) {
e = error1;
log.warn('ban get error', e.toString());
}
}
check_buffer_indentity = function(buf) {
var checksum, i, m, ref;
checksum = 0;
......@@ -2952,11 +3103,13 @@
return (checksum & 0xFF) === 0;
};
create_room_with_action = async function(buffer, decrypted_buffer, match_permit) {
var action, len2, m, name, opt1, opt2, opt3, options, player, ref, room, room_title, title;
var action, firstByte, len2, m, name, opt0, opt1, opt2, opt3, options, player, ref, ref1, room, room_title, title;
if (client.closed) {
return;
}
action = buffer.readUInt8(1) >> 4;
firstByte = buffer.readUInt8(1);
action = firstByte >> 4;
opt0 = firstByte & 0xf;
if (buffer !== decrypted_buffer && (action === 1 || action === 2 || action === 4)) {
ygopro.stoc_die(client, '${invalid_password_unauthorized}');
return;
......@@ -2980,42 +3133,37 @@
options = {
lflist: settings.hostinfo.lflist,
time_limit: settings.hostinfo.time_limit,
rule: (opt1 >> 5) & 3,
mode: (opt1 >> 3) & 3,
duel_rule: (!!((opt1 >> 2) & 1) ? 4 : 5),
rule: (opt1 >> 5) & 0x7, // 0 1 2 3 4 5
mode: (opt1 >> 3) & 0x3, // 0 1 2
duel_rule: (opt0 >> 1) || 5, // 1 2 3 4 5
no_check_deck: !!((opt1 >> 1) & 1),
no_shuffle_deck: !!(opt1 & 1),
start_lp: opt2,
start_hand: opt3 >> 4,
draw_count: opt3 & 0xF,
no_watch: settings.hostinfo.no_watch,
auto_death: settings.hostinfo.auto_death
auto_death: (ref = !!(opt0 & 0x1)) != null ? ref : {
40: false
}
};
options.lflist = _.findIndex(lflists, function(list) {
return ((options.rule === 1) === list.tcg) && list.date.isBefore();
});
//console.log(options)
if (options.rule === 3) {
options.lflist = -1;
} else {
options.lflist = _.findIndex(lflists, function(list) {
return ((options.rule === 1) === list.tcg) && list.date.isBefore();
});
}
room_title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ');
if (_.any(badwords.level3, function(badword) {
var regexp;
regexp = new RegExp(badword, 'i');
return room_title.match(regexp);
}, room_title)) {
if (badwordR.level3.test(room_title)) {
log.warn("BAD ROOM NAME LEVEL 3", room_title, client.name, client.ip);
ygopro.stoc_die(client, "${bad_roomname_level3}");
return;
} else if (_.any(badwords.level2, function(badword) {
var regexp;
regexp = new RegExp(badword, 'i');
return room_title.match(regexp);
}, room_title)) {
} else if (badwordR.level2.test(room_title)) {
log.warn("BAD ROOM NAME LEVEL 2", room_title, client.name, client.ip);
ygopro.stoc_die(client, "${bad_roomname_level2}");
return;
} else if (_.any(badwords.level1, function(badword) {
var regexp;
regexp = new RegExp(badword, 'i');
return room_title.match(regexp);
}, room_title)) {
} else if (badwordR.level1.test(room_title)) {
log.warn("BAD ROOM NAME LEVEL 1", room_title, client.name, client.ip);
ygopro.stoc_die(client, "${bad_roomname_level1}");
return;
......@@ -3041,9 +3189,9 @@
}
room = (await ROOM_find_or_create_by_name('M#' + info.pass.slice(8)));
if (room) {
ref = room.get_playing_player();
for (m = 0, len2 = ref.length; m < len2; m++) {
player = ref[m];
ref1 = room.get_playing_player();
for (m = 0, len2 = ref1.length; m < len2; m++) {
player = ref1[m];
if (!(player && player.name === client.name)) {
continue;
}
......@@ -3071,7 +3219,7 @@
return;
}
if (!room) {
ygopro.stoc_die(client, "${server_full}");
ygopro.stoc_die(client, settings.modules.full);
} else if (room.error) {
ygopro.stoc_die(client, room.error);
} else {
......@@ -3250,9 +3398,14 @@
//if found.winnerId
// ygopro.stoc_die(client, '${challonge_match_already_finished}')
// return
create_room_name = 'M#' + found.id;
if (recover_match) {
create_room_name = recover_match[0] + ',' + create_room_name;
create_room_name = found.id.toString();
if (!settings.modules.challonge.no_match_mode) {
create_room_name = 'M#' + create_room_name;
if (recover_match) {
create_room_name = recover_match[0] + ',' + create_room_name;
}
} else if (recover_match) {
create_room_name = recover_match[0] + '#' + create_room_name;
}
room = (await ROOM_find_or_create_by_name(create_room_name));
if (room) {
......@@ -3261,7 +3414,7 @@
room.welcome = "${challonge_match_created}";
}
if (!room) {
ygopro.stoc_die(client, "${server_full}");
ygopro.stoc_die(client, settings.modules.full);
} else if (room.error) {
ygopro.stoc_die(client, room.error);
} else {
......@@ -3274,25 +3427,13 @@
} else if (ROOM_connected_ip[client.ip] > 5) {
log.warn("MULTI LOGIN", client.name, client.ip);
ygopro.stoc_die(client, "${too_much_connection}" + client.ip);
} else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && _.any(badwords.level3, function(badword) {
var regexp;
regexp = new RegExp(badword, 'i');
return name.match(regexp);
}, name = client.name)) {
} else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && badwordR.level3.test(client.name)) {
log.warn("BAD NAME LEVEL 3", client.name, client.ip);
ygopro.stoc_die(client, "${bad_name_level3}");
} else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && _.any(badwords.level2, function(badword) {
var regexp;
regexp = new RegExp(badword, 'i');
return name.match(regexp);
}, name = client.name)) {
} else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && badwordR.level2.test(client.name)) {
log.warn("BAD NAME LEVEL 2", client.name, client.ip);
ygopro.stoc_die(client, "${bad_name_level2}");
} else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && _.any(badwords.level1, function(badword) {
var regexp;
regexp = new RegExp(badword, 'i');
return name.match(regexp);
}, name = client.name)) {
} else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && badwordR.level1.test(client.name)) {
log.warn("BAD NAME LEVEL 1", client.name, client.ip);
ygopro.stoc_die(client, "${bad_name_level1}");
} else if (info.pass.length && !ROOM_validate(info.pass)) {
......@@ -3308,7 +3449,7 @@
//log.info 'join_game',info.pass, client.name
room = (await ROOM_find_or_create_by_name(info.pass, client.ip));
if (!room) {
ygopro.stoc_die(client, "${server_full}");
ygopro.stoc_die(client, settings.modules.full);
} else if (room.error) {
ygopro.stoc_die(client, room.error);
} else {
......@@ -3438,19 +3579,20 @@
};
ygopro.stoc_follow('GAME_MSG', true, async function(buffer, info, client, server, datas) {
var act_pos, card, chain, check, count, cpos, deck_found, dialogText, found, hint_type, i, id, j, l, len, len1, len2, len3, limbo_found, loc, m, max_loop, msg, n, o, oppo_pos, phase, player, playertype, pos, ppos, r_player, reason, ref, ref1, ref2, ref3, ref4, room, trigger_location, val, victoryWordPlayerList, win_pos;
var act_pos, card, chain, check, count, cpos, deck_found, dialogText, found, hint_type, i, id, j, l, len, len1, len2, len3, limbo_found, loc, m, max_loop, msg, msg_name, n, o, oppo_pos, phase, player, playertype, pos, ppos, r_player, reason, ref, ref1, ref2, ref3, ref4, room, trigger_location, val, victoryWordPlayerList, win_pos;
room = ROOM_all[client.rid];
if (!(room && !client.reconnecting)) {
return;
}
msg = buffer.readInt8(0);
//console.log client.pos, "MSG", ygopro.constants.MSG[msg]
if (ygopro.constants.MSG[msg] === 'RETRY' && room.recovering) {
msg_name = ygopro.constants.MSG[msg];
//console.log client.pos, "MSG", msg_name
if (msg_name === 'RETRY' && room.recovering) {
room.finish_recover(true);
return true;
}
if (settings.modules.retry_handle.enabled) {
if (ygopro.constants.MSG[msg] === 'RETRY') {
if (msg_name === 'RETRY') {
if (client.retry_count == null) {
client.retry_count = 0;
}
......@@ -3477,12 +3619,12 @@
}
} else {
client.last_game_msg = buffer;
client.last_game_msg_title = ygopro.constants.MSG[msg];
client.last_game_msg_title = msg_name;
}
// log.info(client.name, client.last_game_msg_title)
} else if (ygopro.constants.MSG[msg] !== 'RETRY') {
} else if (msg_name !== 'RETRY') {
client.last_game_msg = buffer;
client.last_game_msg_title = ygopro.constants.MSG[msg];
client.last_game_msg_title = msg_name;
}
// log.info(client.name, client.last_game_msg_title)
if ((msg >= 10 && msg < 30) || msg === 132 || (msg >= 140 && msg <= 144)) { //SELECT和ANNOUNCE开头的消息
......@@ -3494,13 +3636,13 @@
return true;
} else {
room.waiting_for_player = client;
room.last_active_time = moment();
room.refreshLastActiveTime();
}
}
//log.info("#{ygopro.constants.MSG[msg]}等待#{room.waiting_for_player.name}")
//log.info("#{msg_name}等待#{room.waiting_for_player.name}")
//log.info 'MSG', ygopro.constants.MSG[msg]
if (ygopro.constants.MSG[msg] === 'START') {
//log.info 'MSG', msg_name
if (msg_name === 'START') {
playertype = buffer.readUInt8(1);
client.is_first = !(playertype & 0xf);
client.lp = room.hostinfo.start_lp;
......@@ -3534,13 +3676,13 @@
}
}
//ygopro.stoc_send_chat_to_room(room, "LP跟踪调试信息: #{client.name} 初始LP #{client.lp}")
if (ygopro.constants.MSG[msg] === 'HINT') {
if (msg_name === 'HINT') {
hint_type = buffer.readUInt8(1);
if (hint_type === 3) {
client.last_hint_msg = buffer;
}
}
if (ygopro.constants.MSG[msg] === 'NEW_TURN') {
if (msg_name === 'NEW_TURN') {
r_player = buffer.readUInt8(1);
if (client.pos === 0 && (r_player & 0x2) === 0) {
room.turn++;
......@@ -3568,7 +3710,7 @@
ygopro.stoc_send_chat(client, "${surrender_canceled}", ygopro.constants.COLORS.BABYBLUE);
}
}
if (ygopro.constants.MSG[msg] === 'NEW_PHASE') {
if (msg_name === 'NEW_PHASE') {
phase = buffer.readInt16LE(1);
oppo_pos = room.hostinfo.mode === 2 ? 2 : 1;
if (client.pos === 0 && room.death === -2 && !(phase === 0x1 && room.turn < 2)) {
......@@ -3582,7 +3724,7 @@
}
}
}
if (ygopro.constants.MSG[msg] === 'WIN' && client.pos === 0) {
if (msg_name === 'WIN' && client.pos === 0) {
if (room.recovering) {
room.finish_recover(true);
return true;
......@@ -3640,11 +3782,11 @@
}
}
}
if (ygopro.constants.MSG[msg] === 'MATCH_KILL' && client.pos === 0) {
if (msg_name === 'MATCH_KILL' && client.pos === 0) {
room.match_kill = true;
}
//lp跟踪
if (ygopro.constants.MSG[msg] === 'DAMAGE' && client.pos === 0) {
if (msg_name === 'DAMAGE' && client.pos === 0) {
pos = buffer.readUInt8(1);
if (!client.is_first) {
pos = 1 - pos;
......@@ -3661,7 +3803,7 @@
ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK);
}
}
if (ygopro.constants.MSG[msg] === 'RECOVER' && client.pos === 0) {
if (msg_name === 'RECOVER' && client.pos === 0) {
pos = buffer.readUInt8(1);
if (!client.is_first) {
pos = 1 - pos;
......@@ -3672,7 +3814,7 @@
val = buffer.readInt32LE(2);
room.dueling_players[pos].lp += val;
}
if (ygopro.constants.MSG[msg] === 'LPUPDATE' && client.pos === 0) {
if (msg_name === 'LPUPDATE' && client.pos === 0) {
pos = buffer.readUInt8(1);
if (!client.is_first) {
pos = 1 - pos;
......@@ -3683,7 +3825,7 @@
val = buffer.readInt32LE(2);
room.dueling_players[pos].lp = val;
}
if (ygopro.constants.MSG[msg] === 'PAY_LPCOST' && client.pos === 0) {
if (msg_name === 'PAY_LPCOST' && client.pos === 0) {
pos = buffer.readUInt8(1);
if (!client.is_first) {
pos = 1 - pos;
......@@ -3702,7 +3844,7 @@
}
//track card count
//todo: track card count in tag mode
if (ygopro.constants.MSG[msg] === 'MOVE' && room.hostinfo.mode !== 2) {
if (msg_name === 'MOVE' && room.hostinfo.mode !== 2) {
pos = buffer.readUInt8(5);
if (!client.is_first) {
pos = 1 - pos;
......@@ -3720,7 +3862,7 @@
client.card_count++;
}
}
if (ygopro.constants.MSG[msg] === 'DRAW' && room.hostinfo.mode !== 2) {
if (msg_name === 'DRAW' && room.hostinfo.mode !== 2) {
pos = buffer.readUInt8(1);
if (!client.is_first) {
pos = 1 - pos;
......@@ -3731,7 +3873,7 @@
}
}
// check panel confirming cards in heartbeat
if (settings.modules.heartbeat_detection.enabled && ygopro.constants.MSG[msg] === 'CONFIRM_CARDS') {
if (settings.modules.heartbeat_detection.enabled && msg_name === 'CONFIRM_CARDS') {
check = false;
count = buffer.readInt8(2);
max_loop = 3 + (count - 1) * 7;
......@@ -3756,7 +3898,7 @@
}
// chain detection
if (settings.modules.heartbeat_detection.enabled && client.pos === 0) {
if (ygopro.constants.MSG[msg] === 'CHAINING') {
if (msg_name === 'CHAINING') {
card = buffer.readUInt32LE(1);
found = false;
for (n = 0, len2 = long_resolve_cards.length; n < len2; n++) {
......@@ -3773,7 +3915,7 @@
// console.log(0,card)
delete room.long_resolve_card;
}
} else if (ygopro.constants.MSG[msg] === 'CHAINED' && room.long_resolve_card) {
} else if (msg_name === 'CHAINED' && room.long_resolve_card) {
chain = buffer.readInt8(1);
if (!room.long_resolve_chain) {
room.long_resolve_chain = [];
......@@ -3781,7 +3923,7 @@
room.long_resolve_chain[chain] = true;
// console.log(1,chain)
delete room.long_resolve_card;
} else if (ygopro.constants.MSG[msg] === 'CHAIN_SOLVING' && room.long_resolve_chain) {
} else if (msg_name === 'CHAIN_SOLVING' && room.long_resolve_chain) {
chain = buffer.readInt8(1);
// console.log(2,chain)
if (room.long_resolve_chain[chain]) {
......@@ -3791,11 +3933,11 @@
player.heartbeat_protected = true;
}
}
} else if ((ygopro.constants.MSG[msg] === 'CHAIN_NEGATED' || ygopro.constants.MSG[msg] === 'CHAIN_DISABLED') && room.long_resolve_chain) {
} else if ((msg_name === 'CHAIN_NEGATED' || msg_name === 'CHAIN_DISABLED') && room.long_resolve_chain) {
chain = buffer.readInt8(1);
// console.log(3,chain)
delete room.long_resolve_chain[chain];
} else if (ygopro.constants.MSG[msg] === 'CHAIN_END') {
} else if (msg_name === 'CHAIN_END') {
// console.log(4,chain)
delete room.long_resolve_card;
delete room.long_resolve_chain;
......@@ -3803,17 +3945,17 @@
}
//登场台词
if ((settings.modules.dialogues.enabled || settings.modules.vip.enabled) && !room.recovering) {
if (ygopro.constants.MSG[msg] === 'SUMMONING' || ygopro.constants.MSG[msg] === 'SPSUMMONING' || ygopro.constants.MSG[msg] === 'CHAINING') {
if (msg_name === 'SUMMONING' || msg_name === 'SPSUMMONING' || msg_name === 'CHAINING') {
card = buffer.readUInt32LE(1);
trigger_location = buffer.readUInt8(6);
act_pos = buffer.readUInt8(ygopro.constants.MSG[msg] === 'CHAINING' ? 9 : 5);
act_pos = buffer.readUInt8(msg_name === 'CHAINING' ? 9 : 5);
if (!room.dueling_players[0].is_first) {
act_pos = 1 - act_pos;
}
if (room.hostinfo.mode === 2) {
act_pos = act_pos * 2;
}
if (ygopro.constants.MSG[msg] !== 'CHAINING' || (trigger_location & 0x8) && client.ready_trap) {
if (msg_name !== 'CHAINING' || (trigger_location & 0x8) && client.ready_trap) {
if (settings.modules.vip.enabled && (await CLIENT_check_vip(room.dueling_players[act_pos])) && (dialogText = (await dataManager.getUserDialogueText(CLIENT_get_authorize_key(room.dueling_players[act_pos]), card)))) {
client.playLines(dialogText);
} else if (settings.modules.vip.enabled && room.hostinfo.mode === 2 && (await CLIENT_check_vip(room.dueling_players[act_pos + 1])) && (dialogText = (await dataManager.getUserDialogueText(CLIENT_get_authorize_key(room.dueling_players[act_pos + 1]), card)))) {
......@@ -3825,17 +3967,17 @@
}
}
}
if (ygopro.constants.MSG[msg] === 'POS_CHANGE') {
if (msg_name === 'POS_CHANGE') {
loc = buffer.readUInt8(6);
ppos = buffer.readUInt8(8);
cpos = buffer.readUInt8(9);
client.ready_trap = !!(loc & 0x8) && !!(ppos & 0xa) && !!(cpos & 0x5);
} else if (ygopro.constants.MSG[msg] !== 'UPDATE_CARD' && ygopro.constants.MSG[msg] !== 'WAITING') {
} else if (msg_name !== 'UPDATE_CARD' && msg_name !== 'WAITING') {
client.ready_trap = false;
}
}
if (room.recovering && client.pos < 4) {
if (ygopro.constants.MSG[msg] !== 'WAITING') {
if (msg_name !== 'WAITING') {
room.recover_buffers[client.pos].push(buffer);
}
return true;
......@@ -4066,6 +4208,7 @@
wait_room_start = async function(room, time) {
var j, len, player, ref;
if (room && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.ready_player_count_without_host >= room.max_player - 1) {
//log.info('wait room start', time)
time -= 1;
if (time) {
if (!(time % 5)) {
......@@ -4187,7 +4330,7 @@
}
if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) { //first start
room.duel_stage = ygopro.constants.DUEL_STAGE.FINGER;
room.start_time = moment().format();
room.start_time = moment_now_string;
room.turn = 0;
if (!room.windbot && settings.modules.http.websocket_roomlist) {
roomlist.start(room);
......@@ -4246,6 +4389,12 @@
deck_arena = deck_arena + room.arena;
} else if (room.hostinfo.mode === 2) {
deck_arena = deck_arena + 'tag';
} else if (room.random_type && _.endsWith(room.random_type, 'R')) {
if (_.endsWith(room.random_type, 'MR')) {
deck_arena = deck_arena + 'athletic';
} else {
deck_arena = deck_arena + 'entertain';
}
} else if (room.random_type === 'S') {
deck_arena = deck_arena + 'entertain';
} else if (room.random_type === 'M') {
......@@ -4255,7 +4404,7 @@
}
//log.info "DECK LOG START", client.name, room.arena
if (settings.modules.deck_log.local) {
deck_name = moment().format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + client.ip.slice(7) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_');
deck_name = moment_now.format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + client.ip.slice(7) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_');
fs.writeFile(settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', function(err) {
if (err) {
return log.warn('DECK SAVE ERROR', err);
......@@ -4275,7 +4424,7 @@
if (error) {
log.warn('DECK POST ERROR', error);
} else {
if (response.statusCode !== 200) {
if (response.statusCode > 300) {
log.warn('DECK POST FAIL', response.statusCode, client.name, body);
}
}
......@@ -4333,7 +4482,7 @@
if (error) {
log.warn('BIG BROTHER ERROR', error);
} else {
if (response.statusCode !== 200) {
if (response.statusCode >= 300) {
log.warn('BIG BROTHER FAIL', response.statusCode, roomname, body);
}
}
......@@ -4351,7 +4500,7 @@
msg = _.trim(info.msg);
cancel = _.startsWith(msg, "/");
if (!(cancel || !(room.random_type || room.arena) || room.duel_stage === ygopro.constants.DUEL_STAGE.FINGER || room.duel_stage === ygopro.constants.DUEL_STAGE.FIRSTGO || room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING)) {
room.last_active_time = moment();
room.refreshLastActiveTime();
}
cmd = msg.split(' ');
isVip = (await CLIENT_check_vip(client));
......@@ -4369,7 +4518,7 @@
ygopro.ctos_send(client.server, 'SURRENDER');
} else {
sur_player = CLIENT_get_partner(client);
if (sur_player.closed || sur_player.is_local) {
if (!sur_player || sur_player.closed || sur_player.is_local) {
sur_player = client;
}
if (room.hostinfo.mode === 2 && sur_player !== client) {
......@@ -4590,11 +4739,7 @@
return true;
}
oldmsg = msg;
if (_.any(badwords.level3, function(badword) {
var regexp;
regexp = new RegExp(badword, 'i');
return msg.match(regexp);
}, msg)) {
if (badwordR.level3.test(msg)) {
log.warn("BAD WORD LEVEL 3", client.name, client.ip, oldmsg, RegExp.$1);
report_to_big_brother(room.name, client.name, client.ip, 3, oldmsg, RegExp.$1);
cancel = true;
......@@ -4622,23 +4767,14 @@
client.abuse_count = client.abuse_count + 2;
ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
cancel = true;
} else if (_.any(badwords.level2, function(badword) {
var regexp;
regexp = new RegExp(badword, 'i');
return msg.match(regexp);
}, msg)) {
} else if (badwordR.level2.test(msg)) {
log.warn("BAD WORD LEVEL 2", client.name, client.ip, oldmsg, RegExp.$1);
report_to_big_brother(room.name, client.name, client.ip, 2, oldmsg, RegExp.$1);
client.abuse_count = client.abuse_count + 3;
ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
cancel = true;
} else {
_.each(badwords.level1, function(badword) {
var regexp;
//log.info msg
regexp = new RegExp(badword, "ig");
msg = msg.replace(regexp, "**");
}, msg);
msg = msg.replace(badwordR.level1g, '**');
if (oldmsg !== msg) {
log.warn("BAD WORD LEVEL 1", client.name, client.ip, oldmsg, RegExp.$1);
report_to_big_brother(room.name, client.name, client.ip, 1, oldmsg, RegExp.$1);
......@@ -4648,11 +4784,7 @@
struct._setBuff(buffer);
struct.set("msg", msg);
buffer = struct.buffer;
} else if (_.any(badwords.level0, function(badword) {
var regexp;
regexp = new RegExp(badword, 'i');
return msg.match(regexp);
}, msg)) {
} else if (badwordR.level0.test(msg)) {
log.info("BAD WORD LEVEL 0", client.name, client.ip, oldmsg, RegExp.$1);
report_to_big_brother(room.name, client.name, client.ip, 0, oldmsg, RegExp.$1);
}
......@@ -4752,7 +4884,7 @@
if (client.pos === 0) {
room.waiting_for_player = room.waiting_for_player2;
}
room.last_active_time = moment();
room.refreshLastActiveTime();
}
client.deck_good = true;
if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.recovering) {
......@@ -4845,7 +4977,7 @@
if (!(room && (room.random_type || room.arena))) {
return;
}
room.last_active_time = moment();
room.refreshLastActiveTime();
});
ygopro.stoc_follow('TIME_LIMIT', true, async function(buffer, info, client, server, datas) {
......@@ -4944,7 +5076,7 @@
if (client.pos === 0) {
room.waiting_for_player = room.waiting_for_player2;
}
room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's');
room.refreshLastActiveTime(true);
}
});
......@@ -4959,7 +5091,7 @@
if (!(room.random_type || room.arena)) {
return;
}
room.last_active_time = moment();
room.refreshLastActiveTime();
});
ygopro.stoc_follow('CHAT', true, async function(buffer, info, client, server, datas) {
......@@ -5016,7 +5148,7 @@
} else {
room.waiting_for_player2 = client;
}
room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's');
room.refreshLastActiveTime(true);
}
if (room.determine_firstgo) {
ygopro.ctos_send(server, "HAND_RESULT", {
......@@ -5047,7 +5179,7 @@
room.duel_stage = ygopro.constants.DUEL_STAGE.FIRSTGO;
if (room.random_type || room.arena) {
room.waiting_for_player = client;
room.last_active_time = moment();
room.refreshLastActiveTime();
}
if (room.determine_firstgo) {
ygopro.ctos_send(server, "TP_RESULT", {
......@@ -5116,7 +5248,7 @@
} else {
room.waiting_for_player2 = client;
}
room.last_active_time = moment();
room.refreshLastActiveTime();
}
});
......@@ -5130,9 +5262,9 @@
// console.log("Replay saved: ", room.duel_count - 1, client.pos)
room.replays[room.duel_count - 1] = buffer;
}
if (settings.modules.mysql.enabled) {
if (settings.modules.mysql.enabled || room.has_ygopro_error) {
if (client.pos === 0) {
replay_filename = moment().format("YYYY-MM-DD HH-mm-ss");
replay_filename = moment_now.format("YYYY-MM-DD HH-mm-ss");
if (room.hostinfo.mode !== 2) {
ref = room.dueling_players;
for (i = j = 0, len = ref.length; j < len; i = ++j) {
......@@ -5147,32 +5279,34 @@
}
}
replay_filename = replay_filename.replace(/[\/\\\?\*]/g, '_') + ".yrp";
playerInfos = room.dueling_players.map(function(player) {
return {
name: player.name,
pos: player.pos,
realName: player.name_vpass,
startDeckBuffer: player.start_deckbuf,
deck: {
main: player.main,
side: player.side
},
isFirst: player.is_first,
winner: player.pos === room.winner,
ip: player.ip,
score: room.scores[player.name_vpass],
lp: player.lp != null ? player.lp : room.hostinfo.start_lp,
cardCount: player.card_count != null ? player.card_count : room.hostinfo.start_hand
};
});
fs.writeFile(settings.modules.tournament_mode.replay_path + replay_filename, buffer, function(err) {
if (err) {
return log.warn("SAVE REPLAY ERROR", replay_filename, err);
}
});
dataManager.saveDuelLog(room.name, room.process_pid, room.cloud_replay_id, replay_filename, room.hostinfo.mode, room.duel_count, playerInfos); // no synchronize here because too slow
if (settings.modules.mysql.enabled) {
playerInfos = room.dueling_players.map(function(player) {
return {
name: player.name,
pos: player.pos,
realName: player.name_vpass,
startDeckBuffer: player.start_deckbuf,
deck: {
main: player.main,
side: player.side
},
isFirst: player.is_first,
winner: player.pos === room.winner,
ip: player.ip,
score: room.scores[player.name_vpass],
lp: player.lp != null ? player.lp : room.hostinfo.start_lp,
cardCount: player.card_count != null ? player.card_count : room.hostinfo.start_hand
};
});
dataManager.saveDuelLog(room.name, room.process_pid, room.cloud_replay_id, replay_filename, room.hostinfo.mode, room.duel_count, playerInfos); // no synchronize here because too slow
}
}
if (settings.modules.cloud_replay.enabled && settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe) {
if (settings.modules.mysql.enabled && settings.modules.cloud_replay.enabled && settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe) {
ygopro.stoc_send_chat(client, `\${cloud_replay_delay_part1}R#${room.cloud_replay_id}\${cloud_replay_delay_part2}`, ygopro.constants.COLORS.BABYBLUE);
}
return settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.block_replay_to_player || settings.modules.replay_delay && room.hostinfo.mode === 1;
......@@ -5375,7 +5509,7 @@
} else {
response.writeHead(200);
if (settings.modules.tournament_mode.log_save_path) {
fs.writeFile(settings.modules.tournament_mode.log_save_path + 'duel_log.' + moment().format('YYYY-MM-DD HH-mm-ss') + '.json', JSON.stringify((await dataManager.getDuelLogJSON(settings.modules.tournament_mode)), null, 2), function(err) {
fs.writeFile(settings.modules.tournament_mode.log_save_path + 'duel_log.' + moment_now.format('YYYY-MM-DD HH-mm-ss') + '.json', JSON.stringify((await dataManager.getDuelLogJSON(settings.modules.tournament_mode)), null, 2), function(err) {
if (err) {
return log.warn('DUEL LOG SAVE ERROR', err);
}
......
......@@ -7,8 +7,20 @@ loadJSON = require('load-json-file').sync
@i18ns = loadJSON './data/i18n.json'
@i18nR = {}
@reloadI18nR = () ->
for lang, data of @i18ns
@i18nR[lang]={}
for key, text of data
@i18nR[lang][key]={
regex: new RegExp("\\$\\{"+key+"\\}",'g'),
text: text
}
@reloadI18nR()
YGOProMessagesHelper = require("./YGOProMessages.js").YGOProMessagesHelper # 为 SRVPro2 准备的库,这里拿这个库只用来测试,SRVPro1 对异步支持不是特别完善,因此不会有很多异步优化
@helper = new YGOProMessagesHelper()
@helper = new YGOProMessagesHelper(9000)
@structs = @helper.structs
@structs_declaration = @helper.structs_declaration
......@@ -54,9 +66,8 @@ translateHandler = (handler) ->
for line in _.lines(msg)
if player>=10
line="[Server]: "+line
for o,r of @i18ns[client.lang]
re=new RegExp("\\$\\{"+o+"\\}",'g')
line=line.replace(re,r)
for o,r of @i18nR[client.lang]
line=line.replace(r.regex, r.text)
@stoc_send client, 'CHAT', {
player: player
msg: line
......
......@@ -14,9 +14,36 @@
this.i18ns = loadJSON('./data/i18n.json');
this.i18nR = {};
this.reloadI18nR = function() {
var data, key, lang, ref, results, text;
ref = this.i18ns;
results = [];
for (lang in ref) {
data = ref[lang];
this.i18nR[lang] = {};
results.push((function() {
var results1;
results1 = [];
for (key in data) {
text = data[key];
results1.push(this.i18nR[lang][key] = {
regex: new RegExp("\\$\\{" + key + "\\}", 'g'),
text: text
});
}
return results1;
}).call(this));
}
return results;
};
this.reloadI18nR();
YGOProMessagesHelper = require("./YGOProMessages.js").YGOProMessagesHelper; // 为 SRVPro2 准备的库,这里拿这个库只用来测试,SRVPro1 对异步支持不是特别完善,因此不会有很多异步优化
this.helper = new YGOProMessagesHelper();
this.helper = new YGOProMessagesHelper(9000);
this.structs = this.helper.structs;
......@@ -69,7 +96,7 @@
//util
this.stoc_send_chat = function(client, msg, player = 8) {
var i, len, line, o, r, re, ref, ref1;
var i, len, line, o, r, ref, ref1;
if (!client) {
console.log("err stoc_send_chat");
return;
......@@ -80,11 +107,10 @@
if (player >= 10) {
line = "[Server]: " + line;
}
ref1 = this.i18ns[client.lang];
ref1 = this.i18nR[client.lang];
for (o in ref1) {
r = ref1[o];
re = new RegExp("\\$\\{" + o + "\\}", 'g');
line = line.replace(re, r);
line = line.replace(r.regex, r.text);
}
this.stoc_send(client, 'CHAT', {
player: player,
......
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