Commit 77a5d346 authored by nanahira's avatar nanahira

add heartbeat detection

parent fbe54a4c
...@@ -91,6 +91,11 @@ ...@@ -91,6 +91,11 @@
"auto_surrender_after_disconnect": false, "auto_surrender_after_disconnect": false,
"wait_time": 300000 "wait_time": 300000
}, },
"heartbeat_detection": {
"enabled": true,
"interval": 10000,
"wait_time": 5000
},
"mycard": { "mycard": {
"enabled": false, "enabled": false,
"auth_base_url": "https://ygobbs.com", "auth_base_url": "https://ygobbs.com",
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
"SELECT_HAND": "", "SELECT_HAND": "",
"SELECT_TP": "", "SELECT_TP": "",
"REPLAY": "", "REPLAY": "",
"TIME_LIMIT": "STOC_TimeLimit",
"CHAT": "STOC_Chat" "CHAT": "STOC_Chat"
} }
} }
...@@ -582,16 +582,19 @@ CLIENT_send_reconnect_info = (client, server, room) -> ...@@ -582,16 +582,19 @@ CLIENT_send_reconnect_info = (client, server, room) ->
if room.turn and room.turn > 0 if room.turn and room.turn > 0
ygopro.ctos_send(server, 'REQUEST_FIELD') ygopro.ctos_send(server, 'REQUEST_FIELD')
else if room.changing_side else if room.changing_side
client.is_reconnect_recovering = true
ygopro.stoc_send(client, 'DUEL_START') ygopro.stoc_send(client, 'DUEL_START')
if !client.selected_preduel if !client.selected_preduel
ygopro.stoc_send(client, 'CHANGE_SIDE') ygopro.stoc_send(client, 'CHANGE_SIDE')
client.reconnecting = false client.reconnecting = false
else if room.selecting_hand else if room.selecting_hand
client.is_reconnect_recovering = true
ygopro.stoc_send(client, 'DUEL_START') ygopro.stoc_send(client, 'DUEL_START')
if (room.hostinfo.mode != 2 or client.pos == 0 or client.pos == 2) and !client.selected_preduel if (room.hostinfo.mode != 2 or client.pos == 0 or client.pos == 2) and !client.selected_preduel
ygopro.stoc_send(client, 'SELECT_HAND') ygopro.stoc_send(client, 'SELECT_HAND')
client.reconnecting = false client.reconnecting = false
else if room.selecting_tp else if room.selecting_tp
client.is_reconnect_recovering = true
ygopro.stoc_send(client, 'DUEL_START') ygopro.stoc_send(client, 'DUEL_START')
if client == room.selecting_tp and !client.selected_preduel if client == room.selecting_tp and !client.selected_preduel
ygopro.stoc_send(client, 'SELECT_TP') ygopro.stoc_send(client, 'SELECT_TP')
...@@ -639,6 +642,33 @@ CLIENT_reconnect = (client) -> ...@@ -639,6 +642,33 @@ CLIENT_reconnect = (client) ->
if settings.modules.reconnect.enabled if settings.modules.reconnect.enabled
disconnect_list = {} # {old_client, old_server, room_id, timeout, deckbuf} disconnect_list = {} # {old_client, old_server, room_id, timeout, deckbuf}
CLIENT_heartbeat_unregister = (client) ->
if !settings.modules.heartbeat_detection.enabled or !client.heartbeat_timeout
return false
clearTimeout(client.heartbeat_timeout)
delete client.heartbeat_timeout
#log.info(2, client.name)
return true
CLIENT_heartbeat_register = (client, send, extend_time) ->
if !settings.modules.heartbeat_detection.enabled or client.closed or client.is_post_watcher or client.pre_reconnecting or client.pos > 3 or client.confirming_cards
return false
if client.heartbeat_timeout
CLIENT_heartbeat_unregister(client)
client.heartbeat_responsed = false
if send
ygopro.stoc_send(client, "TIME_LIMIT", {
player: (if client.is_first or client.is_reconnect_recovering then 0 else 1),
left_time: 0
})
client.heartbeat_timeout = setTimeout(() ->
CLIENT_heartbeat_unregister(client)
client.destroy() unless client.closed or client.heartbeat_responsed
return
, settings.modules.heartbeat_detection.wait_time * (if extend_time then 1.5 else 1))
#log.info(1, client.name)
return true
class Room class Room
constructor: (name, @hostinfo) -> constructor: (name, @hostinfo) ->
@name = name @name = name
...@@ -1759,6 +1789,8 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server)-> ...@@ -1759,6 +1789,8 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server)->
#log.info 'MSG', ygopro.constants.MSG[msg] #log.info 'MSG', ygopro.constants.MSG[msg]
if ygopro.constants.MSG[msg] == 'START' if ygopro.constants.MSG[msg] == 'START'
playertype = buffer.readUInt8(1) playertype = buffer.readUInt8(1)
if settings.modules.reconnect.enabled
client.is_reconnect_recovering = false # dInfo.isFirst is false after reconnecting, so detect this to make client send CTOS_TIME_CONFIRM, assuming the client did not do anything else before reconnecting. I think doing with the client's dInfo.isFirst is still needed.
client.is_first = !(playertype & 0xf) client.is_first = !(playertype & 0xf)
client.lp = room.hostinfo.start_lp client.lp = room.hostinfo.start_lp
client.card_count = 0 if room.hostinfo.mode != 2 client.card_count = 0 if room.hostinfo.mode != 2
...@@ -1829,13 +1861,16 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server)-> ...@@ -1829,13 +1861,16 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server)->
if ygopro.constants.MSG[msg] == 'WIN' and client.pos == 0 if ygopro.constants.MSG[msg] == 'WIN' and client.pos == 0
pos = buffer.readUInt8(1) pos = buffer.readUInt8(1)
pos = 1 - pos unless client.is_first or pos == 2 or room.turn == 0 or !room.turn pos = 1 - pos unless client.is_first or pos == 2 or room.turn <= 0 or !room.turn
pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2 pos = pos * 2 if pos >= 0 and room.hostinfo.mode == 2
reason = buffer.readUInt8(2) reason = buffer.readUInt8(2)
#log.info {winner: pos, reason: reason} #log.info {winner: pos, reason: reason}
#room.duels.push {winner: pos, reason: reason} #room.duels.push {winner: pos, reason: reason}
room.winner = pos room.winner = pos
room.turn = 0 room.turn = 0
if settings.modules.heartbeat_detection.enabled
for player in room.players
player.confirming_cards = false
if room and !room.finished and room.dueling_players[pos] if room and !room.finished and room.dueling_players[pos]
room.winner_name = room.dueling_players[pos].name room.winner_name = room.dueling_players[pos].name
#log.info room.dueling_players, pos #log.info room.dueling_players, pos
...@@ -1922,6 +1957,26 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server)-> ...@@ -1922,6 +1957,26 @@ ygopro.stoc_follow 'GAME_MSG', true, (buffer, info, client, server)->
count = buffer.readInt8(2) count = buffer.readInt8(2)
client.card_count += count client.card_count += count
# check panel confirming cards in heartbeat
if settings.modules.heartbeat_detection.enabled and ygopro.constants.MSG[msg] == 'CONFIRM_CARDS'
check = false
count = buffer.readInt8(2)
max_loop = 3 + (count - 1) * 7
deck_found = 0
limbo_found = 0 # support custom cards which may be in location 0 in KoishiPro or EdoPro
for i in [3..max_loop] by 7
loc = buffer.readInt8(i + 5)
if (loc & 0x41) > 0
deck_found++
else if loc == 0
limbo_found++
if (deck_found > 0 and count > 1) or limbo_found > 0
check = true
break
if check
#console.log("Confirming cards:" + client.name)
client.confirming_cards = true
#登场台词 #登场台词
if settings.modules.dialogues.enabled if settings.modules.dialogues.enabled
if ygopro.constants.MSG[msg] == 'SUMMONING' or ygopro.constants.MSG[msg] == 'SPSUMMONING' or ygopro.constants.MSG[msg] == 'CHAINING' if ygopro.constants.MSG[msg] == 'SUMMONING' or ygopro.constants.MSG[msg] == 'SPSUMMONING' or ygopro.constants.MSG[msg] == 'CHAINING'
...@@ -2430,6 +2485,44 @@ ygopro.ctos_follow 'RESPONSE', false, (buffer, info, client, server)-> ...@@ -2430,6 +2485,44 @@ ygopro.ctos_follow 'RESPONSE', false, (buffer, info, client, server)->
room.last_active_time = moment() room.last_active_time = moment()
return return
ygopro.stoc_follow 'TIME_LIMIT', false, (buffer, info, client, server)->
room=ROOM_all[client.rid]
return unless room and settings.modules.heartbeat_detection.enabled and room.turn and room.turn > 0
check = false
if room.hostinfo.mode != 2
check = (client.is_first and info.player == 0) or (!client.is_first and info.player == 1)
else
cur_players = []
switch room.turn % 4
when 1
cur_players[0] = 0
cur_players[1] = 3
when 2
cur_players[0] = 0
cur_players[1] = 2
when 3
cur_players[0] = 1
cur_players[1] = 2
when 0
cur_players[0] = 1
cur_players[1] = 3
if !room.dueling_players[0].is_first
cur_players[0] = cur_players[0] + 2
cur_players[1] = cur_players[1] - 2
check = client.pos == cur_players[info.player]
if check
extend_time = settings.modules.reconnect.enabled and client.reconnecting
CLIENT_heartbeat_register(client, false, extend_time)
return
ygopro.ctos_follow 'TIME_CONFIRM', false, (buffer, info, client, server)->
room=ROOM_all[client.rid]
return unless room and settings.modules.heartbeat_detection.enabled
client.confirming_cards = false
client.heartbeat_responsed = true
CLIENT_heartbeat_unregister(client)
return
ygopro.ctos_follow 'HAND_RESULT', false, (buffer, info, client, server)-> ygopro.ctos_follow 'HAND_RESULT', false, (buffer, info, client, server)->
room=ROOM_all[client.rid] room=ROOM_all[client.rid]
return unless room return unless room
...@@ -2604,6 +2697,14 @@ if settings.modules.mycard.enabled ...@@ -2604,6 +2697,14 @@ if settings.modules.mycard.enabled
return return
, 1000 , 1000
if settings.modules.heartbeat_detection.enabled
setInterval ()->
for room in ROOM_all when room and room.started and (room.hostinfo.time_limit == 0 or !room.turn or room.turn <= 0) and room.duel_count and room.duel_count > 0
for player in room.players when (!player.is_local or !room.windbot) and (!room.changing_side or player.selected_preduel)
CLIENT_heartbeat_register(player, true)
return
, settings.modules.heartbeat_detection.interval
# spawn windbot # spawn windbot
if settings.modules.windbot.spawn if settings.modules.windbot.spawn
if /^win/.test(process.platform) if /^win/.test(process.platform)
......
// Generated by CoffeeScript 1.12.7 // Generated by CoffeeScript 1.12.7
(function() { (function() {
var CLIENT_get_authorize_key, CLIENT_import_data, CLIENT_is_able_to_reconnect, CLIENT_is_player, CLIENT_kick, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, Cloud_replay_ids, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, 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_players_banned, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, Room, SERVER_clear_disconnect, _, addCallback, badwords, ban_user, bunyan, challonge, chat_color, config, cppversion, crypto, date, default_config, default_data, dialogues, disconnect_list, duel_log, e, exec, execFile, fs, geoip, get_memory_usage, http, http_server, https, https_server, import_datas, j, l, len, len1, lflists, list, loadJSON, load_dialogues, load_tips, log, memory_usage, merge, moment, net, oldbadwords, oldconfig, olddialogues, oldduellog, oldtips, options, os, path, pgClient, pg_client, pg_query, redis, redisdb, ref, ref1, release_disconnect, report_to_big_brother, request, requestListener, roomlist, setting_change, setting_save, settings, spawn, spawnSync, tips, url, users_cache, wait_room_start, wait_room_start_arena, windbot_bin, windbot_parameters, windbot_process, windbots, ygopro, zlib; var CLIENT_get_authorize_key, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_reconnect, CLIENT_is_player, CLIENT_kick, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, Cloud_replay_ids, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, 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_players_banned, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, Room, SERVER_clear_disconnect, _, addCallback, badwords, ban_user, bunyan, challonge, chat_color, config, cppversion, crypto, date, default_config, default_data, dialogues, disconnect_list, duel_log, e, exec, execFile, fs, geoip, get_memory_usage, http, http_server, https, https_server, import_datas, j, l, len, len1, lflists, list, loadJSON, load_dialogues, load_tips, log, memory_usage, merge, moment, net, oldbadwords, oldconfig, olddialogues, oldduellog, oldtips, options, os, path, pgClient, pg_client, pg_query, redis, redisdb, ref, ref1, release_disconnect, report_to_big_brother, request, requestListener, roomlist, setting_change, setting_save, settings, spawn, spawnSync, tips, url, users_cache, wait_room_start, wait_room_start_arena, windbot_bin, windbot_parameters, windbot_process, windbots, ygopro, zlib;
net = require('net'); net = require('net');
...@@ -756,18 +756,21 @@ ...@@ -756,18 +756,21 @@
if (room.turn && room.turn > 0) { if (room.turn && room.turn > 0) {
ygopro.ctos_send(server, 'REQUEST_FIELD'); ygopro.ctos_send(server, 'REQUEST_FIELD');
} else if (room.changing_side) { } else if (room.changing_side) {
client.is_reconnect_recovering = true;
ygopro.stoc_send(client, 'DUEL_START'); ygopro.stoc_send(client, 'DUEL_START');
if (!client.selected_preduel) { if (!client.selected_preduel) {
ygopro.stoc_send(client, 'CHANGE_SIDE'); ygopro.stoc_send(client, 'CHANGE_SIDE');
} }
client.reconnecting = false; client.reconnecting = false;
} else if (room.selecting_hand) { } else if (room.selecting_hand) {
client.is_reconnect_recovering = true;
ygopro.stoc_send(client, 'DUEL_START'); ygopro.stoc_send(client, 'DUEL_START');
if ((room.hostinfo.mode !== 2 || client.pos === 0 || client.pos === 2) && !client.selected_preduel) { if ((room.hostinfo.mode !== 2 || client.pos === 0 || client.pos === 2) && !client.selected_preduel) {
ygopro.stoc_send(client, 'SELECT_HAND'); ygopro.stoc_send(client, 'SELECT_HAND');
} }
client.reconnecting = false; client.reconnecting = false;
} else if (room.selecting_tp) { } else if (room.selecting_tp) {
client.is_reconnect_recovering = true;
ygopro.stoc_send(client, 'DUEL_START'); ygopro.stoc_send(client, 'DUEL_START');
if (client === room.selecting_tp && !client.selected_preduel) { if (client === room.selecting_tp && !client.selected_preduel) {
ygopro.stoc_send(client, 'SELECT_TP'); ygopro.stoc_send(client, 'SELECT_TP');
...@@ -823,6 +826,38 @@ ...@@ -823,6 +826,38 @@
disconnect_list = {}; disconnect_list = {};
} }
CLIENT_heartbeat_unregister = function(client) {
if (!settings.modules.heartbeat_detection.enabled || !client.heartbeat_timeout) {
return false;
}
clearTimeout(client.heartbeat_timeout);
delete client.heartbeat_timeout;
return true;
};
CLIENT_heartbeat_register = function(client, send, extend_time) {
if (!settings.modules.heartbeat_detection.enabled || client.closed || client.is_post_watcher || client.pre_reconnecting || client.pos > 3 || client.confirming_cards) {
return false;
}
if (client.heartbeat_timeout) {
CLIENT_heartbeat_unregister(client);
}
client.heartbeat_responsed = false;
if (send) {
ygopro.stoc_send(client, "TIME_LIMIT", {
player: (client.is_first || client.is_reconnect_recovering ? 0 : 1),
left_time: 0
});
}
client.heartbeat_timeout = setTimeout(function() {
CLIENT_heartbeat_unregister(client);
if (!(client.closed || client.heartbeat_responsed)) {
client.destroy();
}
}, settings.modules.heartbeat_detection.wait_time * (extend_time ? 1.5 : 1));
return true;
};
Room = (function() { Room = (function() {
function Room(name, hostinfo) { function Room(name, hostinfo) {
var draw_count, lflist, param, rule, start_hand, start_lp, time_limit; var draw_count, lflist, param, rule, start_hand, start_lp, time_limit;
...@@ -2073,7 +2108,7 @@ ...@@ -2073,7 +2108,7 @@
} }
ygopro.stoc_follow('GAME_MSG', true, function(buffer, info, client, server) { ygopro.stoc_follow('GAME_MSG', true, function(buffer, info, client, server) {
var card, count, cpos, hint_type, len2, line, loc, m, msg, oppo_pos, phase, playertype, pos, ppos, reason, ref2, ref3, ref4, room, trigger_location, val, win_pos; var card, check, count, cpos, deck_found, hint_type, i, len2, len3, limbo_found, line, loc, m, max_loop, msg, n, o, oppo_pos, phase, player, playertype, pos, ppos, reason, ref2, ref3, ref4, ref5, ref6, room, trigger_location, val, win_pos;
room = ROOM_all[client.rid]; room = ROOM_all[client.rid];
if (!(room && !client.reconnecting)) { if (!(room && !client.reconnecting)) {
return; return;
...@@ -2118,6 +2153,9 @@ ...@@ -2118,6 +2153,9 @@
} }
if (ygopro.constants.MSG[msg] === 'START') { if (ygopro.constants.MSG[msg] === 'START') {
playertype = buffer.readUInt8(1); playertype = buffer.readUInt8(1);
if (settings.modules.reconnect.enabled) {
client.is_reconnect_recovering = false;
}
client.is_first = !(playertype & 0xf); client.is_first = !(playertype & 0xf);
client.lp = room.hostinfo.start_lp; client.lp = room.hostinfo.start_lp;
if (room.hostinfo.mode !== 2) { if (room.hostinfo.mode !== 2) {
...@@ -2202,7 +2240,7 @@ ...@@ -2202,7 +2240,7 @@
} }
if (ygopro.constants.MSG[msg] === 'WIN' && client.pos === 0) { if (ygopro.constants.MSG[msg] === 'WIN' && client.pos === 0) {
pos = buffer.readUInt8(1); pos = buffer.readUInt8(1);
if (!(client.is_first || pos === 2 || room.turn === 0 || !room.turn)) { if (!(client.is_first || pos === 2 || room.turn <= 0 || !room.turn)) {
pos = 1 - pos; pos = 1 - pos;
} }
if (pos >= 0 && room.hostinfo.mode === 2) { if (pos >= 0 && room.hostinfo.mode === 2) {
...@@ -2211,6 +2249,13 @@ ...@@ -2211,6 +2249,13 @@
reason = buffer.readUInt8(2); reason = buffer.readUInt8(2);
room.winner = pos; room.winner = pos;
room.turn = 0; room.turn = 0;
if (settings.modules.heartbeat_detection.enabled) {
ref2 = room.players;
for (m = 0, len2 = ref2.length; m < len2; m++) {
player = ref2[m];
player.confirming_cards = false;
}
}
if (room && !room.finished && room.dueling_players[pos]) { if (room && !room.finished && room.dueling_players[pos]) {
room.winner_name = room.dueling_players[pos].name; room.winner_name = room.dueling_players[pos].name;
room.scores[room.winner_name] = room.scores[room.winner_name] + 1; room.scores[room.winner_name] = room.scores[room.winner_name] + 1;
...@@ -2263,7 +2308,7 @@ ...@@ -2263,7 +2308,7 @@
if (room.dueling_players[pos].lp < 0) { if (room.dueling_players[pos].lp < 0) {
room.dueling_players[pos].lp = 0; room.dueling_players[pos].lp = 0;
} }
if ((0 < (ref2 = room.dueling_players[pos].lp) && ref2 <= 100)) { if ((0 < (ref3 = room.dueling_players[pos].lp) && ref3 <= 100)) {
ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK); ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK);
} }
} }
...@@ -2302,7 +2347,7 @@ ...@@ -2302,7 +2347,7 @@
if (room.dueling_players[pos].lp < 0) { if (room.dueling_players[pos].lp < 0) {
room.dueling_players[pos].lp = 0; room.dueling_players[pos].lp = 0;
} }
if ((0 < (ref3 = room.dueling_players[pos].lp) && ref3 <= 100)) { if ((0 < (ref4 = room.dueling_players[pos].lp) && ref4 <= 100)) {
ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK); ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK);
} }
} }
...@@ -2334,14 +2379,36 @@ ...@@ -2334,14 +2379,36 @@
client.card_count += count; client.card_count += count;
} }
} }
if (settings.modules.heartbeat_detection.enabled && ygopro.constants.MSG[msg] === 'CONFIRM_CARDS') {
check = false;
count = buffer.readInt8(2);
max_loop = 3 + (count - 1) * 7;
deck_found = 0;
limbo_found = 0;
for (i = n = 3, ref5 = max_loop; n <= ref5; i = n += 7) {
loc = buffer.readInt8(i + 5);
if ((loc & 0x41) > 0) {
deck_found++;
} else if (loc === 0) {
limbo_found++;
}
if ((deck_found > 0 && count > 1) || limbo_found > 0) {
check = true;
break;
}
}
if (check) {
client.confirming_cards = true;
}
}
if (settings.modules.dialogues.enabled) { if (settings.modules.dialogues.enabled) {
if (ygopro.constants.MSG[msg] === 'SUMMONING' || ygopro.constants.MSG[msg] === 'SPSUMMONING' || ygopro.constants.MSG[msg] === 'CHAINING') { if (ygopro.constants.MSG[msg] === 'SUMMONING' || ygopro.constants.MSG[msg] === 'SPSUMMONING' || ygopro.constants.MSG[msg] === 'CHAINING') {
card = buffer.readUInt32LE(1); card = buffer.readUInt32LE(1);
trigger_location = buffer.readUInt8(6); trigger_location = buffer.readUInt8(6);
if (dialogues.dialogues[card] && (ygopro.constants.MSG[msg] !== 'CHAINING' || (trigger_location & 0x8) && client.ready_trap)) { if (dialogues.dialogues[card] && (ygopro.constants.MSG[msg] !== 'CHAINING' || (trigger_location & 0x8) && client.ready_trap)) {
ref4 = _.lines(dialogues.dialogues[card][Math.floor(Math.random() * dialogues.dialogues[card].length)]); ref6 = _.lines(dialogues.dialogues[card][Math.floor(Math.random() * dialogues.dialogues[card].length)]);
for (m = 0, len2 = ref4.length; m < len2; m++) { for (o = 0, len3 = ref6.length; o < len3; o++) {
line = ref4[m]; line = ref6[o];
ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK); ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK);
} }
} }
...@@ -3043,6 +3110,57 @@ ...@@ -3043,6 +3110,57 @@
room.last_active_time = moment(); room.last_active_time = moment();
}); });
ygopro.stoc_follow('TIME_LIMIT', false, function(buffer, info, client, server) {
var check, cur_players, extend_time, room;
room = ROOM_all[client.rid];
if (!(room && settings.modules.heartbeat_detection.enabled && room.turn && room.turn > 0)) {
return;
}
check = false;
if (room.hostinfo.mode !== 2) {
check = (client.is_first && info.player === 0) || (!client.is_first && info.player === 1);
} else {
cur_players = [];
switch (room.turn % 4) {
case 1:
cur_players[0] = 0;
cur_players[1] = 3;
break;
case 2:
cur_players[0] = 0;
cur_players[1] = 2;
break;
case 3:
cur_players[0] = 1;
cur_players[1] = 2;
break;
case 0:
cur_players[0] = 1;
cur_players[1] = 3;
}
if (!room.dueling_players[0].is_first) {
cur_players[0] = cur_players[0] + 2;
cur_players[1] = cur_players[1] - 2;
}
check = client.pos === cur_players[info.player];
}
if (check) {
extend_time = settings.modules.reconnect.enabled && client.reconnecting;
CLIENT_heartbeat_register(client, false, extend_time);
}
});
ygopro.ctos_follow('TIME_CONFIRM', false, function(buffer, info, client, server) {
var room;
room = ROOM_all[client.rid];
if (!(room && settings.modules.heartbeat_detection.enabled)) {
return;
}
client.confirming_cards = false;
client.heartbeat_responsed = true;
CLIENT_heartbeat_unregister(client);
});
ygopro.ctos_follow('HAND_RESULT', false, function(buffer, info, client, server) { ygopro.ctos_follow('HAND_RESULT', false, function(buffer, info, client, server) {
var room; var room;
room = ROOM_all[client.rid]; room = ROOM_all[client.rid];
...@@ -3297,6 +3415,24 @@ ...@@ -3297,6 +3415,24 @@
}, 1000); }, 1000);
} }
if (settings.modules.heartbeat_detection.enabled) {
setInterval(function() {
var len2, len3, m, n, player, ref2, room;
for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
room = ROOM_all[m];
if (room && room.started && (room.hostinfo.time_limit === 0 || !room.turn || room.turn <= 0) && room.duel_count && room.duel_count > 0) {
ref2 = room.players;
for (n = 0, len3 = ref2.length; n < len3; n++) {
player = ref2[n];
if ((!player.is_local || !room.windbot) && (!room.changing_side || player.selected_preduel)) {
CLIENT_heartbeat_register(player, true);
}
}
}
}
}, settings.modules.heartbeat_detection.interval);
}
if (settings.modules.windbot.spawn) { if (settings.modules.windbot.spawn) {
if (/^win/.test(process.platform)) { if (/^win/.test(process.platform)) {
windbot_bin = 'WindBot.exe'; windbot_bin = 'WindBot.exe';
......
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