Commit 246cf5da authored by nanahira's avatar nanahira

Merge branch 'master' into tcg_random

parents 80a8e171 b5310819
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AthleticChecker = void 0;
const axios_1 = __importDefault(require("axios"));
const querystring_1 = __importDefault(require("querystring"));
const moment_1 = __importDefault(require("moment"));
class AthleticChecker {
constructor(config) {
this.config = config;
}
deckToString(deck) {
const deckText = '#ygopro-server deck log\n#main\n' + deck.main.join('\n') + '\n!side\n' + deck.side.join('\n') + '\n';
return deckText;
}
async getAthleticDecks() {
if (this.athleticDeckCache && moment_1.default().diff(this.lastAthleticDeckFetchTime, "seconds") < this.config.ttl) {
return this.athleticDeckCache;
}
const { data } = await axios_1.default.get(this.config.rankURL, {
timeout: 10000,
responseType: "json",
paramsSerializer: querystring_1.default.stringify,
params: this.config.athleticFetchParams
});
const athleticDecks = data.slice(0, this.config.rankCount).map(m => m.name);
this.athleticDeckCache = athleticDecks;
this.lastAthleticDeckFetchTime = moment_1.default();
return athleticDecks;
}
async getDeckType(deck) {
const deckString = this.deckToString(deck);
const { data } = await axios_1.default.post(this.config.identifierURL, querystring_1.default.stringify({ deck: deckString }), {
timeout: 10000,
responseType: "json"
});
return data.deck;
}
async checkAthletic(deck) {
try {
const athleticDecks = await this.getAthleticDecks();
const deckType = await this.getDeckType(deck);
const athletic = athleticDecks.includes(deckType);
return { success: true, athletic, message: null };
}
catch (e) {
return { success: false, message: e.toString() };
}
}
}
exports.AthleticChecker = AthleticChecker;
//# sourceMappingURL=athletic-check.js.map
\ No newline at end of file
import axios from "axios";
import qs from "querystring";
import moment, {Moment} from "moment";
interface Deck {
main: number[];
side: number[];
}
interface Config {
rankURL: string;
identifierURL: string;
athleticFetchParams: any;
rankCount: number;
ttl: number;
}
interface AthleticDecksReturnData {
name: string
}
interface ReturnMessage {
success: boolean;
athletic?: boolean;
message: string;
}
export class AthleticChecker {
config: Config;
athleticDeckCache: string[];
lastAthleticDeckFetchTime: Moment;
constructor(config: Config) {
this.config = config;
}
deckToString(deck: Deck) {
const deckText = '#ygopro-server deck log\n#main\n' + deck.main.join('\n') + '\n!side\n' + deck.side.join('\n') + '\n';
return deckText;
}
async getAthleticDecks(): Promise<string[]> {
if (this.athleticDeckCache && moment().diff(this.lastAthleticDeckFetchTime, "seconds") < this.config.ttl) {
return this.athleticDeckCache;
}
const { data } = await axios.get(this.config.rankURL, {
timeout: 10000,
responseType: "json",
paramsSerializer: qs.stringify,
params: this.config.athleticFetchParams
});
const athleticDecks = (data as AthleticDecksReturnData[]).slice(0, this.config.rankCount).map(m => m.name);
this.athleticDeckCache = athleticDecks;
this.lastAthleticDeckFetchTime = moment();
return athleticDecks;
}
async getDeckType(deck: Deck): Promise<string> {
const deckString = this.deckToString(deck);
const { data } = await axios.post(this.config.identifierURL, qs.stringify({ deck: deckString }), {
timeout: 10000,
responseType: "json"
});
return data.deck;
}
async checkAthletic(deck: Deck): Promise<ReturnMessage> {
try {
const athleticDecks = await this.getAthleticDecks();
const deckType = await this.getDeckType(deck);
const athletic = athleticDecks.includes(deckType);
return { success: true, athletic, message: null }
} catch (e) {
return { success: false, message: e.toString() };
}
}
}
{
"file": "./config/config.json",
"port": 7911,
"version": 4930,
"version": 4945,
"alternative_versions": [],
"hostinfo": {
"lflist": 0,
"rule": 0,
......@@ -197,6 +198,17 @@
"log_save_path": "./config/",
"port": 7933
},
"athletic_check": {
"enabled": false,
"rankURL": "https://api.mycard.moe/ygopro/analytics/deck/type",
"identifierURL": "https://api.mycard.moe/ygopro/identifier/production",
"athleticFetchParams": {
"type": "week",
"source": "mycard-athletic"
},
"rankCount": 10,
"ttl": 600
},
"test_mode": {
"watch_public_hand": false,
"no_connect_count_limit": false,
......
......@@ -200,7 +200,8 @@
"auto_death_part1": "This room is an auto-extra-duel room. The Extra Duel will begin after ",
"auto_death_part2": " minutes.",
"athletic_arena_tip": "During an athletic match, a game quit behavior is regarded as a surrender.",
"windbot_disable_random_room": "By adding the AI, this random game won't get any new player unless they enter the room name:"
"windbot_disable_random_room": "By adding the AI, this random game won't get any new player unless they enter the room name:",
"using_athletic_deck": " is using an athletic deck."
},
"es-es": {
"random_duel_enter_room_waiting": "Tu oponente esta listo, Iniciar!",
......@@ -549,7 +550,8 @@
"auto_death_part1": "本房间为自动加时赛房间。比赛开始",
"auto_death_part2": "分钟后,将自动进入加时赛。",
"athletic_arena_tip": "在竞技匹配中,比赛开始前退出游戏也会视为投降。",
"windbot_disable_random_room": "因为添加了AI,本随机对战房间将只能通过房间名加入:"
"windbot_disable_random_room": "因为添加了AI,本随机对战房间将只能通过房间名加入:",
"using_athletic_deck": " 正在使用竞技卡组。"
},
"ko-kr": {
"random_duel_enter_room_waiting": "땅콩: 게임을 진행하게 준비 또는 시작을 하십시오.",
......
......@@ -452,6 +452,10 @@ if settings.modules.heartbeat_detection.enabled
if settings.modules.tournament_mode.enable_recover
ReplayParser = global.ReplayParser = require "./Replay.js"
if settings.modules.athletic_check.enabled
AthleticChecker = require("./athletic-check.js").AthleticChecker
athleticChecker = global.athleticChecker = new AthleticChecker(settings.modules.athletic_check)
# 组件
ygopro = global.ygopro = require './ygopro.js'
roomlist = global.roomlist = require './roomlist.js' if settings.modules.http.websocket_roomlist
......@@ -1702,7 +1706,7 @@ class Room
else
for player in @players when player.pos != 7
@scores[player.name_vpass] = -5
if @players.length == 2
if @players.length == 2 and !client.arena_quit_free
@scores[client.name_vpass] = -9
@arena_score_handled = true
index = _.indexOf(@players, client)
......@@ -1796,6 +1800,20 @@ class Room
for buffer in @recover_buffers[player.pos]
ygopro.stoc_send(player, "GAME_MSG", buffer)
check_athletic: ->
players = @get_playing_player()
room = this
await Promise.all(players.map((player) ->
main = _.clone(player.main)
side = _.clone(player.side)
using_athletic = await athleticChecker.checkAthletic({main: main, side: side})
if !using_athletic.success
log.warn("GET ATHLETIC FAIL", player.name, using_athletic.message)
else if using_athletic.athletic
ygopro.stoc_send_chat_to_room(room, "#{player.name}${using_athletic_deck}", ygopro.constants.COLORS.BABYBLUE)
))
await return
# 网络连接
net.createServer (client) ->
client.ip = client.remoteAddress
......@@ -2124,7 +2142,7 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
replay_id=Cloud_replay_ids[Math.floor(Math.random()*Cloud_replay_ids.length)]
redisdb.hgetall "replay:"+replay_id, client.open_cloud_replay
else if info.version != settings.version # and (info.version < 9020 or settings.version != 4927) #强行兼容23333版
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 client, 'ERROR_MSG', {
msg: 4
......@@ -2141,12 +2159,12 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
ygopro.stoc_die(client, '${invalid_password_length}')
return
#if info.version >= 9020 and settings.version == 4927 #强行兼容23333版
# info.version = settings.version
# struct = ygopro.structs.get("CTOS_JoinGame")
# struct._setBuff(buffer)
# struct.set("version", info.version)
# buffer = struct.buffer
if info.version != settings.version and settings.alternative_versions.includes(info.version)
info.version = settings.version
struct = ygopro.structs.get("CTOS_JoinGame")
struct._setBuff(buffer)
struct.set("version", info.version)
buffer = struct.buffer
buffer = Buffer.from(info.pass[0...8], 'base64')
......@@ -2372,6 +2390,12 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
else if settings.modules.challonge.enabled
if info.version != settings.version and settings.alternative_versions.includes(info.version)
info.version = settings.version
struct = ygopro.structs.get("CTOS_JoinGame")
struct._setBuff(buffer)
struct.set("version", info.version)
buffer = struct.buffer
pre_room = ROOM_find_by_name(info.pass)
if pre_room and pre_room.duel_stage != ygopro.constants.DUEL_STAGE.BEGIN and settings.modules.cloud_replay.enable_halfway_watch and !pre_room.hostinfo.no_watch
room = pre_room
......@@ -2514,13 +2538,12 @@ ygopro.ctos_follow 'JOIN_GAME', true, (buffer, info, client, server, datas)->
ygopro.stoc_die(client, "${invalid_password_room}")
else
#if info.version >= 9020 and settings.version == 4927 #强行兼容23333版
# info.version = settings.version
# struct = ygopro.structs.get("CTOS_JoinGame")
# struct._setBuff(buffer)
# struct.set("version", info.version)
# buffer = struct.buffer
# #ygopro.stoc_send_chat(client, "看起来你是YGOMobile的用户,请记得更新先行卡补丁,否则会看到白卡", ygopro.constants.COLORS.GREEN)
if info.version != settings.version and settings.alternative_versions.includes(info.version)
info.version = settings.version
struct = ygopro.structs.get("CTOS_JoinGame")
struct._setBuff(buffer)
struct.set("version", info.version)
buffer = struct.buffer
#log.info 'join_game',info.pass, client.name
room = ROOM_find_or_create_by_name(info.pass, client.ip)
......@@ -3055,15 +3078,24 @@ ygopro.stoc_follow 'HS_PLAYER_ENTER', true, (buffer, info, client, server, datas
ygopro.stoc_follow 'HS_PLAYER_CHANGE', true, (buffer, info, client, server, datas)->
room=ROOM_all[client.rid]
return unless room and room.max_player and client.pos == 0
return unless room and client.pos == 0
pos = info.status >> 4
is_ready = (info.status & 0xf) == 9
if pos < room.max_player
if room.arena
room.ready_player_count = 0
for player in room.players
if player.pos == pos
player.is_ready = is_ready
room.ready_player_count = 0
room.ready_player_count_without_host = 0
for player in room.players
if player.pos == pos
player.is_ready = is_ready
if player.is_ready
++room.ready_player_count
unless player.is_host
++room.ready_player_count_without_host
if settings.modules.athletic_check.enabled
possibly_max_player = if room.hostinfo.mode == 2 then 4 else 2
if room.ready_player_count >= possibly_max_player
room.check_athletic()
if room.max_player and pos < room.max_player
if room.arena # mycard
p1 = room.players[0]
p2 = room.players[1]
if !p1 or !p2
......@@ -3087,13 +3119,7 @@ ygopro.stoc_follow 'HS_PLAYER_CHANGE', true, (buffer, info, client, server, data
clearInterval room.waiting_for_player_interval
room.waiting_for_player_interval = null
room.waiting_for_player_time = settings.modules.arena_mode.ready_time
else
room.ready_player_count_without_host = 0
for player in room.players
if player.pos == pos
player.is_ready = is_ready
unless player.is_host
room.ready_player_count_without_host += player.is_ready
else # random duel
if room.ready_player_count_without_host >= room.max_player - 1
#log.info "all ready"
setTimeout (()-> wait_room_start(ROOM_all[client.rid], settings.modules.random_duel.ready_time);return), 1000
......@@ -4001,7 +4027,7 @@ if settings.modules.mycard.enabled
return
)
if settings.modules.arena_mode.punish_quit_before_match
if true # settings.modules.arena_mode.punish_quit_before_match
_async.each(ROOM_all, (room, done) ->
if not (room and room.arena and room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN and room.get_playing_player().length < 2)
done()
......
This diff is collapsed.
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