ygopro-server.js 202 KB
Newer Older
nanahira's avatar
nanahira committed
1
// Generated by CoffeeScript 2.5.1
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2
(function() {
nanahira's avatar
nanahira committed
3
  // 标准库
nanahira's avatar
nanahira committed
4
  var CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, 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, Cloud_replay_ids, 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_banned, ROOM_players_oppentlist, ROOM_players_scores, ROOM_unwelcome, ROOM_validate, ReplayParser, ResolveData, Room, SERVER_clear_disconnect, SERVER_kick, SOCKET_flush_data, _, _async, addCallback, auth, axios, badwords, ban_user, bunyan, challonge, challonge_cache, challonge_module_name, challonge_queue_callbacks, challonge_type, chat_color, config, cppversion, crypto, date, deck_name_match, default_config, default_data, dialogues, disconnect_list, dns, duel_log, e, exec, execFile, fs, geoip, getSeedTimet, get_callback, get_memory_usage, http, http_server, https, https_server, import_datas, imported, is_challonge_requesting, j, l, len, len1, len2, len3, lflists, list, loadJSON, load_dialogues, load_tips, log, long_resolve_cards, m, memory_usage, merge, moment, n, net, oldbadwords, oldconfig, olddialogues, oldduellog, oldtips, options, os, path, pgClient, pg_client, pg_query, plugin_filename, plugin_list, plugin_path, qs, real_windbot_server_ip, redis, redisdb, ref, ref1, ref2, refresh_challonge_cache, release_disconnect, replaced_index, report_to_big_brother, request, requestListener, 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, ygopro, zlib;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
5

神楽坂玲奈's avatar
神楽坂玲奈 committed
6
  net = require('net');
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
7

神楽坂玲奈's avatar
神楽坂玲奈 committed
8 9 10
  http = require('http');

  url = require('url');
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
11

神楽坂玲奈's avatar
神楽坂玲奈 committed
12 13 14 15
  path = require('path');

  fs = require('fs');

mercury233's avatar
mercury233 committed
16 17
  os = require('os');

18 19
  crypto = require('crypto');

mercury233's avatar
mercury233 committed
20 21
  exec = require('child_process').exec;

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
22 23
  execFile = require('child_process').execFile;

mercury233's avatar
mercury233 committed
24 25 26 27
  spawn = require('child_process').spawn;

  spawnSync = require('child_process').spawnSync;

nanahira's avatar
nanahira committed
28 29
  _async = require('async');

nanahira's avatar
nanahira committed
30
  // 三方库
nanahira's avatar
nanahira committed
31
  _ = global._ = require('underscore');
神楽坂玲奈's avatar
神楽坂玲奈 committed
32

神楽坂玲奈's avatar
tip  
神楽坂玲奈 committed
33 34 35 36 37 38
  _.str = require('underscore.string');

  _.mixin(_.str.exports());

  request = require('request');

nanahira's avatar
nanahira committed
39 40
  axios = require('axios');

nanahira's avatar
fix  
nanahira committed
41
  qs = require("querystring");
nanahira's avatar
nanahira committed
42

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
43 44
  bunyan = require('bunyan');

nanahira's avatar
nanahira committed
45
  log = global.log = bunyan.createLogger({
mercury233's avatar
mercury233 committed
46 47 48
    name: "mycard"
  });

nanahira's avatar
nanahira committed
49
  moment = global.moment = require('moment');
50

mercury233's avatar
mercury233 committed
51
  moment.updateLocale('zh-cn', {
mercury233's avatar
mercury233 committed
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
    relativeTime: {
      future: '%s内',
      past: '%s前',
      s: '%d秒',
      m: '1分钟',
      mm: '%d分钟',
      h: '1小时',
      hh: '%d小时',
      d: '1天',
      dd: '%d天',
      M: '1个月',
      MM: '%d个月',
      y: '1年',
      yy: '%d年'
    }
  });

nanahira's avatar
nanahira committed
69
  import_datas = global.import_datas = ["abuse_count", "ban_mc", "vpass", "rag", "rid", "is_post_watcher", "retry_count", "name", "pass", "name_vpass", "is_first", "lp", "card_count", "is_host", "pos", "surrend_confirm", "kick_count", "deck_saved", "main", "side", "side_interval", "side_tcount", "selected_preduel", "last_game_msg", "last_game_msg_title", "last_hint_msg", "start_deckbuf", "challonge_info", "ready_trap", "join_time", "arena_quit_free", "replays_sent"];
nanahira's avatar
nanahira committed
70

mercury233's avatar
mercury233 committed
71 72
  merge = require('deepmerge');

mercury233's avatar
mercury233 committed
73 74
  loadJSON = require('load-json-file').sync;

nanahira's avatar
nanahira committed
75 76
  util = require("util");

nanahira's avatar
nanahira committed
77 78 79 80
  //heapdump = require 'heapdump'

  // 配置
  // 导入旧配置
mercury233's avatar
mercury233 committed
81 82 83 84
  if (!fs.existsSync('./config')) {
    fs.mkdirSync('./config');
  }

mercury233's avatar
mercury233 committed
85
  try {
mercury233's avatar
mercury233 committed
86
    oldconfig = loadJSON('./config.user.json');
mercury233's avatar
mercury233 committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100
    if (oldconfig.tips) {
      oldtips = {};
      oldtips.file = './config/tips.json';
      oldtips.tips = oldconfig.tips;
      fs.writeFileSync(oldtips.file, JSON.stringify(oldtips, null, 2));
      delete oldconfig.tips;
    }
    if (oldconfig.dialogues) {
      olddialogues = {};
      olddialogues.file = './config/dialogues.json';
      olddialogues.dialogues = oldconfig.dialogues;
      fs.writeFileSync(olddialogues.file, JSON.stringify(olddialogues, null, 2));
      delete oldconfig.dialogues;
    }
mercury233's avatar
fix  
mercury233 committed
101 102 103 104 105 106 107 108
    if (oldconfig.modules) {
      if (oldconfig.modules.tournament_mode && oldconfig.modules.tournament_mode.duel_log) {
        oldduellog = {};
        oldduellog.file = './config/duel_log.json';
        oldduellog.duel_log = oldconfig.modules.tournament_mode.duel_log;
        fs.writeFileSync(oldduellog.file, JSON.stringify(oldduellog, null, 2));
        delete oldconfig.oldduellog;
      }
109
    }
mercury233's avatar
mercury233 committed
110
    oldbadwords = {};
mercury233's avatar
fix  
mercury233 committed
111 112 113 114 115 116 117 118 119 120 121 122 123
    if (oldconfig.ban) {
      if (oldconfig.ban.badword_level0) {
        oldbadwords.level0 = oldconfig.ban.badword_level0;
      }
      if (oldconfig.ban.badword_level1) {
        oldbadwords.level1 = oldconfig.ban.badword_level1;
      }
      if (oldconfig.ban.badword_level2) {
        oldbadwords.level2 = oldconfig.ban.badword_level2;
      }
      if (oldconfig.ban.badword_level3) {
        oldbadwords.level3 = oldconfig.ban.badword_level3;
      }
mercury233's avatar
mercury233 committed
124 125 126 127 128 129 130 131 132 133
    }
    if (!_.isEmpty(oldbadwords)) {
      oldbadwords.file = './config/badwords.json';
      fs.writeFileSync(oldbadwords.file, JSON.stringify(oldbadwords, null, 2));
      delete oldconfig.ban.badword_level0;
      delete oldconfig.ban.badword_level1;
      delete oldconfig.ban.badword_level2;
      delete oldconfig.ban.badword_level3;
    }
    if (!_.isEmpty(oldconfig)) {
nanahira's avatar
nanahira committed
134
      // log.info oldconfig
mercury233's avatar
mercury233 committed
135 136 137 138 139 140
      fs.writeFileSync('./config/config.json', JSON.stringify(oldconfig, null, 2));
      log.info('imported old config from config.user.json');
    }
    fs.renameSync('./config.user.json', './config.user.bak');
  } catch (error1) {
    e = error1;
mercury233's avatar
mercury233 committed
141
    if (e.code !== 'ENOENT') {
mercury233's avatar
mercury233 committed
142 143 144
      log.info(e);
    }
  }
mercury233's avatar
mercury233 committed
145

nanahira's avatar
nanahira committed
146 147 148 149 150 151 152 153 154
  setting_save = global.setting_save = function(settings, callback) {
    if (!callback) {
      callback = function(err) {
        if (err) {
          return log.warn("setting save fail", err.toString());
        }
      };
    }
    fs.writeFile(settings.file, JSON.stringify(settings, null, 2), callback);
mercury233's avatar
mercury233 committed
155
  };
mercury233's avatar
mercury233 committed
156

nanahira's avatar
nanahira committed
157
  setting_change = global.setting_change = function(settings, path, val, callback) {
mercury233's avatar
mercury233 committed
158
    var key, target;
mercury233's avatar
mercury233 committed
159
    if (_.isString(val)) {
nanahira's avatar
nanahira committed
160
      // path should be like "modules:welcome"
mercury233's avatar
mercury233 committed
161 162
      log.info("setting changed", path, val);
    }
mercury233's avatar
mercury233 committed
163 164 165 166 167 168 169 170 171 172 173 174
    path = path.split(':');
    if (path.length === 0) {
      settings[path[0]] = val;
    } else {
      target = settings;
      while (path.length > 1) {
        key = path.shift();
        target = target[key];
      }
      key = path.shift();
      target[key] = val;
    }
nanahira's avatar
nanahira committed
175
    setting_save(settings, callback);
mercury233's avatar
mercury233 committed
176
  };
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
177

nanahira's avatar
nanahira committed
178
  // 读取配置
mercury233's avatar
mercury233 committed
179
  default_config = loadJSON('./data/default_config.json');
mercury233's avatar
mercury233 committed
180

181 182 183 184 185 186 187 188 189
  if (fs.existsSync('./config/config.json')) {
    try {
      config = loadJSON('./config/config.json');
    } catch (error1) {
      e = error1;
      console.error("Failed reading config: ", e.toString());
      process.exit(1);
    }
  } else {
mercury233's avatar
mercury233 committed
190 191 192 193 194 195 196 197 198
    config = {};
  }

  settings = global.settings = merge(default_config, config, {
    arrayMerge: function(destination, source) {
      return source;
    }
  });

nanahira's avatar
nanahira committed
199
  auth = global.auth = require('./ygopro-auth.js');
nanahira's avatar
nanahira committed
200

nanahira's avatar
nanahira committed
201
  //import old configs
nanahira's avatar
nanahira committed
202 203
  imported = false;

nanahira's avatar
nanahira committed
204
  //reset http.quick_death_rule from true to 1
nanahira's avatar
nanahira committed
205 206
  if (settings.modules.http.quick_death_rule === true) {
    settings.modules.http.quick_death_rule = 1;
nanahira's avatar
nanahira committed
207 208 209
    imported = true;
  }

nanahira's avatar
nanahira committed
210
  //import the old redis port
nanahira's avatar
nanahira committed
211 212 213 214 215 216
  if (settings.modules.cloud_replay.redis_port) {
    settings.modules.cloud_replay.redis.port = settings.modules.cloud_replay.redis_port;
    delete settings.modules.cloud_replay.redis_port;
    imported = true;
  }

nanahira's avatar
nanahira committed
217
  //import the old passwords to new admin user system
nanahira's avatar
nanahira committed
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
  if (settings.modules.http.password) {
    auth.add_user("olduser", settings.modules.http.password, true, {
      "get_rooms": true,
      "shout": true,
      "stop": true,
      "change_settings": true,
      "ban_user": true,
      "kick_user": true,
      "start_death": true
    });
    delete settings.modules.http.password;
    imported = true;
  }

  if (settings.modules.tournament_mode.password) {
    auth.add_user("tournament", settings.modules.tournament_mode.password, true, {
      "duel_log": true,
      "download_replay": true,
      "clear_duel_log": true,
nanahira's avatar
fix  
nanahira committed
237
      "deck_dashboard_read": true,
nanahira's avatar
nanahira committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
      "deck_dashboard_write": true
    });
    delete settings.modules.tournament_mode.password;
    imported = true;
  }

  if (settings.modules.pre_util.password) {
    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) {
    auth.add_user("update", settings.modules.update_util.password, true, {
      "update_dashboard": true
    });
    delete settings.modules.update_util.password;
    imported = true;
  }

nanahira's avatar
nanahira committed
260
  //import the old enable_priority hostinfo
261 262 263 264
  if (settings.hostinfo.enable_priority || settings.hostinfo.enable_priority === false) {
    if (settings.hostinfo.enable_priority) {
      settings.hostinfo.duel_rule = 3;
    } else {
nanahira's avatar
nanahira committed
265
      settings.hostinfo.duel_rule = 5;
266 267 268 269 270
    }
    delete settings.hostinfo.enable_priority;
    imported = true;
  }

nanahira's avatar
nanahira committed
271
  //import the old Challonge api key option
272 273 274 275 276 277
  if (settings.modules.challonge.api_key) {
    settings.modules.challonge.options.apiKey = settings.modules.challonge.api_key;
    delete settings.modules.challonge.api_key;
    imported = true;
  }

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
  //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
    };
    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
    };
    delete settings.modules.random_duel.blank_pass_match;
    imported = true;
  }

nanahira's avatar
nanahira committed
299
  //finish
nanahira's avatar
nanahira committed
300
  if (imported) {
nanahira's avatar
nanahira committed
301 302 303
    setting_save(settings);
  }

nanahira's avatar
nanahira committed
304
  // 读取数据
mercury233's avatar
mercury233 committed
305
  default_data = loadJSON('./data/default_data.json');
mercury233's avatar
mercury233 committed
306 307

  try {
nanahira's avatar
nanahira committed
308
    tips = global.tips = loadJSON('./config/tips.json');
mercury233's avatar
mercury233 committed
309
  } catch (error1) {
nanahira's avatar
nanahira committed
310
    tips = global.tips = default_data.tips;
mercury233's avatar
mercury233 committed
311 312 313 314
    setting_save(tips);
  }

  try {
nanahira's avatar
nanahira committed
315
    dialogues = global.dialogues = loadJSON('./config/dialogues.json');
mercury233's avatar
mercury233 committed
316
  } catch (error1) {
nanahira's avatar
nanahira committed
317
    dialogues = global.dialogues = default_data.dialogues;
mercury233's avatar
mercury233 committed
318 319 320 321
    setting_save(dialogues);
  }

  try {
nanahira's avatar
nanahira committed
322
    badwords = global.badwords = loadJSON('./config/badwords.json');
mercury233's avatar
mercury233 committed
323
  } catch (error1) {
nanahira's avatar
nanahira committed
324
    badwords = global.badwords = default_data.badwords;
mercury233's avatar
mercury233 committed
325 326 327
    setting_save(badwords);
  }

328
  try {
nanahira's avatar
nanahira committed
329
    duel_log = global.duel_log = loadJSON('./config/duel_log.json');
330
  } catch (error1) {
nanahira's avatar
nanahira committed
331
    duel_log = global.duel_log = default_data.duel_log;
332 333 334
    setting_save(duel_log);
  }

nanahira's avatar
nanahira committed
335
  try {
nanahira's avatar
nanahira committed
336
    chat_color = global.chat_color = loadJSON('./config/chat_color.json');
nanahira's avatar
nanahira committed
337
  } catch (error1) {
nanahira's avatar
nanahira committed
338
    chat_color = global.chat_color = default_data.chat_color;
nanahira's avatar
nanahira committed
339 340 341
    setting_save(chat_color);
  }

342
  try {
mercury233's avatar
mercury233 committed
343
    cppversion = parseInt(fs.readFileSync('ygopro/gframe/game.cpp', 'utf8').match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16');
mercury233's avatar
mercury233 committed
344
    setting_change(settings, "version", cppversion);
mercury233's avatar
fix  
mercury233 committed
345
    log.info("ygopro version 0x" + settings.version.toString(16), "(from source code)");
346
  } catch (error1) {
nanahira's avatar
nanahira committed
347
    //settings.version = settings.version_default
mercury233's avatar
fix  
mercury233 committed
348
    log.info("ygopro version 0x" + settings.version.toString(16), "(from config)");
349
  }
350

nanahira's avatar
nanahira committed
351
  // load the lflist of current date
nanahira's avatar
nanahira committed
352
  lflists = global.lflists = [];
nanahira's avatar
nanahira committed
353 354 355

  try {
    ref = fs.readFileSync('ygopro/expansions/lflist.conf', 'utf8').match(/!.*/g);
nanahira's avatar
nanahira committed
356
    // expansions/lflist
mercury233's avatar
mercury233 committed
357 358
    for (j = 0, len = ref.length; j < len; j++) {
      list = ref[j];
mercury233's avatar
mercury233 committed
359 360 361 362
      date = list.match(/!([\d\.]+)/);
      if (!date) {
        continue;
      }
nanahira's avatar
nanahira committed
363
      lflists.push({
神楽坂玲奈's avatar
神楽坂玲奈 committed
364
        date: moment(list.match(/!([\d\.]+)/)[1], 'YYYY.MM.DD').utcOffset("-08:00"),
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
365
        tcg: list.indexOf('TCG') !== -1
神楽坂玲奈's avatar
神楽坂玲奈 committed
366 367
      });
    }
nanahira's avatar
nanahira committed
368 369 370 371 372 373
  } catch (error1) {

  }

  try {
    ref1 = fs.readFileSync('ygopro/lflist.conf', 'utf8').match(/!.*/g);
nanahira's avatar
nanahira committed
374
    // lflist
nanahira's avatar
nanahira committed
375 376
    for (l = 0, len1 = ref1.length; l < len1; l++) {
      list = ref1[l];
nanahira's avatar
nanahira committed
377 378 379 380 381 382 383 384 385 386 387 388
      date = list.match(/!([\d\.]+)/);
      if (!date) {
        continue;
      }
      lflists.push({
        date: moment(list.match(/!([\d\.]+)/)[1], 'YYYY.MM.DD').utcOffset("-08:00"),
        tcg: list.indexOf('TCG') !== -1
      });
    }
  } catch (error1) {

  }
神楽坂玲奈's avatar
神楽坂玲奈 committed
389

mercury233's avatar
mercury233 committed
390
  if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
391 392
    redis = require('redis');
    zlib = require('zlib');
nanahira's avatar
nanahira committed
393
    redisdb = global.redisdb = redis.createClient(settings.modules.cloud_replay.redis);
mercury233's avatar
mercury233 committed
394 395 396
    redisdb.on('error', function(err) {
      log.warn(err);
    });
mercury233's avatar
mercury233 committed
397 398
  }

mercury233's avatar
mercury233 committed
399
  if (settings.modules.windbot.enabled) {
nanahira's avatar
nanahira committed
400
    windbots = global.windbots = loadJSON(settings.modules.windbot.botlist).windbots;
nanahira's avatar
fix  
nanahira committed
401
    real_windbot_server_ip = global.real_windbot_server_ip = settings.modules.windbot.server_ip;
nanahira's avatar
nanahira committed
402 403 404 405
    if (!settings.modules.windbot.server_ip.includes("127.0.0.1")) {
      dns = require('dns');
      dns.lookup(settings.modules.windbot.server_ip, function(err, addr) {
        if (!err) {
nanahira's avatar
fix  
nanahira committed
406
          return real_windbot_server_ip = global.real_windbot_server_ip = addr;
nanahira's avatar
nanahira committed
407 408 409
        }
      });
    }
mercury233's avatar
mercury233 committed
410 411
  }

nanahira's avatar
nanahira committed
412
  if (settings.modules.heartbeat_detection.enabled) {
nanahira's avatar
nanahira committed
413
    long_resolve_cards = global.long_resolve_cards = loadJSON('./data/long_resolve_cards.json');
nanahira's avatar
nanahira committed
414 415
  }

nanahira's avatar
nanahira committed
416 417 418 419
  if (settings.modules.tournament_mode.enable_recover) {
    ReplayParser = global.ReplayParser = require("./Replay.js");
  }

nanahira's avatar
nanahira committed
420
  // 组件
nanahira's avatar
nanahira committed
421
  ygopro = global.ygopro = require('./ygopro.js');
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
422

mercury233's avatar
mercury233 committed
423
  if (settings.modules.http.websocket_roomlist) {
nanahira's avatar
nanahira committed
424
    roomlist = global.roomlist = require('./roomlist.js');
mercury233's avatar
mercury233 committed
425
  }
神楽坂玲奈's avatar
神楽坂玲奈 committed
426

mercury233's avatar
mercury233 committed
427 428 429 430
  if (settings.modules.i18n.auto_pick) {
    geoip = require('geoip-country-lite');
  }

nanahira's avatar
nanahira committed
431
  // cache users of mycard login
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
432 433
  users_cache = {};

mercury233's avatar
mercury233 committed
434
  if (settings.modules.mycard.enabled) {
mercury233's avatar
merge  
mercury233 committed
435
    pgClient = require('pg').Client;
nanahira's avatar
nanahira committed
436
    pg_client = global.pg_client = new pgClient(settings.modules.mycard.auth_database);
mercury233's avatar
fix  
mercury233 committed
437 438 439
    pg_client.on('error', function(err) {
      log.warn("PostgreSQL ERROR: ", err);
    });
mercury233's avatar
merge  
mercury233 committed
440
    pg_query = pg_client.query('SELECT username, id from users');
mercury233's avatar
fix  
mercury233 committed
441 442 443
    pg_query.on('error', function(err) {
      log.warn("PostgreSQL Query ERROR: ", err);
    });
mercury233's avatar
merge  
mercury233 committed
444
    pg_query.on('row', function(row) {
nanahira's avatar
nanahira committed
445
      //log.info "load user", row.username, row.id
mercury233's avatar
merge  
mercury233 committed
446 447 448 449 450 451 452 453
      users_cache[row.username] = row.id;
    });
    pg_query.on('end', function(result) {
      log.info("users loaded", result.rowCount);
    });
    pg_client.on('drain', pg_client.end.bind(pg_client));
    log.info("loading mycard user...");
    pg_client.connect();
nanahira's avatar
nanahira committed
454 455 456 457 458 459 460
    if (settings.modules.arena_mode.enabled && settings.modules.arena_mode.init_post.enabled) {
      request.post({
        url: settings.modules.arena_mode.init_post.url,
        qs: {
          ak: settings.modules.arena_mode.init_post.accesskey,
          arena: settings.modules.arena_mode.mode
        }
nanahira's avatar
nanahira committed
461 462 463 464 465 466
      }, (error, response, body) => {
        if (error) {
          log.warn('ARENA INIT POST ERROR', error);
        } else {
          if (response.statusCode >= 400) {
            log.warn('ARENA INIT POST FAIL', response.statusCode, response.statusMessage, body);
nanahira's avatar
nanahira committed
467
          }
nanahira's avatar
nanahira committed
468 469
        }
      });
nanahira's avatar
nanahira committed
470
    }
mercury233's avatar
merge  
mercury233 committed
471 472
  }

nanahira's avatar
nanahira committed
473 474 475 476 477 478 479 480 481 482 483 484
  ResolveData = (function() {
    //else
    //  log.info 'ARENA INIT POST OK', response.statusCode, response.statusMessage
    class ResolveData {
      constructor(func) {
        this.func = func;
      }

      resolve(err, data) {
        if (this.resolved) {
          return false;
        }
nanahira's avatar
fix  
nanahira committed
485
        this.resolved = true;
nanahira's avatar
nanahira committed
486 487 488 489 490 491 492 493 494 495 496 497
        this.func(err, data);
        return true;
      }

    };

    ResolveData.prototype.resolved = false;

    return ResolveData;

  }).call(this);

nanahira's avatar
nanahira committed
498
  if (settings.modules.challonge.enabled) {
499 500 501 502
    challonge_module_name = 'challonge';
    if (settings.modules.challonge.use_custom_module) {
      challonge_module_name = settings.modules.challonge.use_custom_module;
    }
nanahira's avatar
nanahira committed
503
    challonge = global.challonge = require(challonge_module_name).createClient(settings.modules.challonge.options);
nanahira's avatar
nanahira committed
504
    if (settings.modules.challonge.cache_ttl) {
nanahira's avatar
fix  
nanahira committed
505 506 507 508
      challonge_cache = {
        participants: null,
        matches: null
      };
nanahira's avatar
nanahira committed
509
    }
nanahira's avatar
nanahira committed
510 511 512 513 514 515 516 517
    challonge_queue_callbacks = {
      participants: [],
      matches: []
    };
    is_challonge_requesting = {
      participants: null,
      matches: null
    };
nanahira's avatar
ref  
nanahira committed
518
    get_callback = function(challonge_type, resolve_data) {
nanahira's avatar
nanahira committed
519
      return (function(err, data) {
nanahira's avatar
ref  
nanahira committed
520
        var cur_resolve_data;
nanahira's avatar
nanahira committed
521
        if (settings.modules.challonge.cache_ttl && !err && data) {
nanahira's avatar
nanahira committed
522 523
          challonge_cache[challonge_type] = data;
        }
nanahira's avatar
nanahira committed
524
        is_challonge_requesting[challonge_type] = null;
nanahira's avatar
nanahira committed
525
        resolve_data.resolve(err, data);
nanahira's avatar
nanahira committed
526
        while (challonge_queue_callbacks[challonge_type].length) {
nanahira's avatar
ref  
nanahira committed
527
          cur_resolve_data = challonge_queue_callbacks[challonge_type].splice(0, 1)[0];
nanahira's avatar
nanahira committed
528
          cur_resolve_data.resolve(err, data);
nanahira's avatar
nanahira committed
529 530 531
        }
      });
    };
nanahira's avatar
nanahira committed
532 533 534 535
    replaced_index = function(challonge_type) {
      return function(_data) {
        var err, resolve_data;
        resolve_data = new ResolveData(_data.callback);
nanahira's avatar
fix  
nanahira committed
536
        if (settings.modules.challonge.cache_ttl && !_data.no_cache && challonge_cache[challonge_type]) {
nanahira's avatar
nanahira committed
537 538 539 540 541 542 543 544 545 546 547 548
          resolve_data.resolve(null, challonge_cache[challonge_type]);
        } else if (is_challonge_requesting[challonge_type] && moment() - 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();
          try {
            challonge[challonge_type].index(_data);
          } catch (error1) {
            err = error1;
            _data.callback(err, null);
          }
nanahira's avatar
js  
nanahira committed
549
        }
nanahira's avatar
nanahira committed
550
      };
nanahira's avatar
nanahira committed
551
    };
nanahira's avatar
nanahira committed
552 553 554 555 556
    ref2 = ["participants", "matches"];
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      challonge_type = ref2[m];
      challonge[challonge_type]._index = replaced_index(challonge_type);
    }
nanahira's avatar
nanahira committed
557 558 559 560 561 562 563 564 565
    challonge.matches._update = function(_data) {
      var err;
      try {
        challonge.matches.update(_data);
      } catch (error1) {
        err = error1;
        log.warn("Errored pushing scores to Challonge.", err);
      }
    };
nanahira's avatar
nanahira committed
566
    refresh_challonge_cache = global.refresh_challonge_cache = function() {
nanahira's avatar
nanahira committed
567
      if (settings.modules.challonge.cache_ttl) {
nanahira's avatar
fix  
nanahira committed
568 569
        challonge_cache.participants = null;
        challonge_cache.matches = null;
nanahira's avatar
nanahira committed
570
      }
nanahira's avatar
nanahira committed
571 572
    };
    refresh_challonge_cache();
nanahira's avatar
nanahira committed
573 574 575 576 577 578 579 580 581 582 583 584
    // challonge.participants._index({
    //   id: settings.modules.challonge.tournament_id,
    //   callback: (() ->
    //     challonge.matches._index({
    //       id: settings.modules.challonge.tournament_id,
    //       callback: (() ->
    //         return
    //       )
    //     })
    //     return
    //   )
    // })
nanahira's avatar
nanahira committed
585 586 587
    if (settings.modules.challonge.cache_ttl) {
      setInterval(refresh_challonge_cache, settings.modules.challonge.cache_ttl);
    }
nanahira's avatar
nanahira committed
588 589
  }

nanahira's avatar
nanahira committed
590
  // 获取可用内存
nanahira's avatar
nanahira committed
591
  memory_usage = global.memory_usage = 0;
mercury233's avatar
mercury233 committed
592

nanahira's avatar
nanahira committed
593
  get_memory_usage = get_memory_usage = function() {
mercury233's avatar
mercury233 committed
594 595
    var prc_free;
    prc_free = exec("free");
mercury233's avatar
fix  
mercury233 committed
596
    prc_free.stdout.on('data', function(data) {
mercury233's avatar
mercury233 committed
597 598 599 600
      var actualFree, buffers, cached, free, line, lines, new_free, percentUsed, total;
      lines = data.toString().split(/\n/g);
      line = lines[0].split(/\s+/);
      new_free = line[6] === 'available' ? true : false;
mercury233's avatar
mercury233 committed
601 602 603 604
      line = lines[1].split(/\s+/);
      total = parseInt(line[1], 10);
      free = parseInt(line[3], 10);
      buffers = parseInt(line[5], 10);
mercury233's avatar
mercury233 committed
605 606 607 608 609 610
      if (new_free) {
        actualFree = parseInt(line[6], 10);
      } else {
        cached = parseInt(line[6], 10);
        actualFree = free + buffers + cached;
      }
mercury233's avatar
mercury233 committed
611
      percentUsed = parseFloat(((1 - (actualFree / total)) * 100).toFixed(2));
nanahira's avatar
nanahira committed
612
      memory_usage = global.memory_usage = percentUsed;
mercury233's avatar
mercury233 committed
613
    });
mercury233's avatar
mercury233 committed
614 615
  };

mercury233's avatar
mercury233 committed
616 617 618 619
  get_memory_usage();

  setInterval(get_memory_usage, 3000);

nanahira's avatar
nanahira committed
620
  Cloud_replay_ids = global.Cloud_replay_ids = [];
mercury233's avatar
mercury233 committed
621

nanahira's avatar
nanahira committed
622
  ROOM_all = global.ROOM_all = [];
mercury233's avatar
mercury233 committed
623

nanahira's avatar
nanahira committed
624
  ROOM_players_oppentlist = global.ROOM_players_oppentlist = {};
mercury233's avatar
mercury233 committed
625

nanahira's avatar
nanahira committed
626
  ROOM_players_banned = global.ROOM_players_banned = [];
mercury233's avatar
mercury233 committed
627

nanahira's avatar
nanahira committed
628
  ROOM_players_scores = global.ROOM_players_scores = {};
629

nanahira's avatar
nanahira committed
630
  ROOM_connected_ip = global.ROOM_connected_ip = {};
mercury233's avatar
mercury233 committed
631

nanahira's avatar
nanahira committed
632
  ROOM_bad_ip = global.ROOM_bad_ip = {};
mercury233's avatar
mercury233 committed
633

nanahira's avatar
nanahira committed
634
  // ban a user manually and permanently
nanahira's avatar
nanahira committed
635 636
  ban_user = global.ban_user = function(name, callback) {
    var bad_ip;
mercury233's avatar
mercury233 committed
637
    settings.ban.banned_user.push(name);
mercury233's avatar
mercury233 committed
638
    setting_save(settings);
nanahira's avatar
nanahira committed
639
    bad_ip = [];
nanahira's avatar
nanahira committed
640 641 642 643 644
    _async.each(ROOM_all, function(room, done) {
      if (!(room && room.established)) {
        done();
        return;
      }
nanahira's avatar
nanahira committed
645
      return _async.each(["players", "watchers"], function(player_type, _done) {
nanahira's avatar
nanahira committed
646 647 648 649 650
        return _async.each(room[player_type], function(player, __done) {
          if (player && (player.name === name || bad_ip.indexOf(player.ip) !== -1)) {
            bad_ip.push(player.ip);
            ROOM_bad_ip[bad_ip] = 99;
            settings.ban.banned_ip.push(player.ip);
nanahira's avatar
nanahira committed
651
            ygopro.stoc_send_chat_to_room(room, `${player.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
652 653 654
            CLIENT_send_replays(player, room);
            CLIENT_kick(player);
          }
nanahira's avatar
nanahira committed
655 656 657 658
          return __done();
        }, _done);
      }, done);
    }, callback);
mercury233's avatar
mercury233 committed
659 660
  };

nanahira's avatar
nanahira committed
661 662
  // automatically ban user to use random duel
  ROOM_ban_player = global.ROOM_ban_player = function(name, ip, reason, countadd = 1) {
mercury233's avatar
mercury233 committed
663
    var bannedplayer, bantime;
664 665 666
    if (settings.modules.test_mode.no_ban_player) {
      return;
    }
mercury233's avatar
mercury233 committed
667 668 669 670
    bannedplayer = _.find(ROOM_players_banned, function(bannedplayer) {
      return ip === bannedplayer.ip;
    });
    if (bannedplayer) {
mercury233's avatar
mercury233 committed
671
      bannedplayer.count = bannedplayer.count + countadd;
mercury233's avatar
mercury233 committed
672 673 674 675 676 677 678 679 680 681 682 683
      bantime = bannedplayer.count > 3 ? Math.pow(2, bannedplayer.count - 3) * 2 : 0;
      bannedplayer.time = moment() < bannedplayer.time ? moment(bannedplayer.time).add(bantime, 'm') : moment().add(bantime, 'm');
      if (!_.find(bannedplayer.reasons, function(bannedreason) {
        return bannedreason === reason;
      })) {
        bannedplayer.reasons.push(reason);
      }
      bannedplayer.need_tip = true;
    } else {
      bannedplayer = {
        "ip": ip,
        "time": moment(),
mercury233's avatar
mercury233 committed
684
        "count": countadd,
mercury233's avatar
mercury233 committed
685 686 687 688 689 690 691
        "reasons": [reason],
        "need_tip": true
      };
      ROOM_players_banned.push(bannedplayer);
    }
  };

nanahira's avatar
nanahira committed
692
  //log.info("banned", name, ip, reason, bannedplayer.count)
nanahira's avatar
nanahira committed
693
  ROOM_kick = function(name, callback) {
nanahira's avatar
nanahira committed
694 695 696 697 698 699 700 701
    var found;
    found = false;
    return _async.each(ROOM_all, function(room, done) {
      if (!(room && room.established && (name === "all" || name === room.process_pid.toString() || name === room.name))) {
        done();
        return;
      }
      found = true;
nanahira's avatar
nanahira committed
702 703
      room.termiate();
      return done();
nanahira's avatar
nanahira committed
704
    }, function(err) {
nanahira's avatar
nanahira committed
705
      callback(null, found);
nanahira's avatar
nanahira committed
706 707 708
    });
  };

nanahira's avatar
nanahira committed
709
  ROOM_player_win = global.ROOM_player_win = function(name) {
710 711 712 713 714 715 716 717 718 719 720 721
    if (!ROOM_players_scores[name]) {
      ROOM_players_scores[name] = {
        win: 0,
        lose: 0,
        flee: 0,
        combo: 0
      };
    }
    ROOM_players_scores[name].win = ROOM_players_scores[name].win + 1;
    ROOM_players_scores[name].combo = ROOM_players_scores[name].combo + 1;
  };

nanahira's avatar
nanahira committed
722
  ROOM_player_lose = global.ROOM_player_lose = function(name) {
723 724 725 726 727 728 729 730 731 732 733 734
    if (!ROOM_players_scores[name]) {
      ROOM_players_scores[name] = {
        win: 0,
        lose: 0,
        flee: 0,
        combo: 0
      };
    }
    ROOM_players_scores[name].lose = ROOM_players_scores[name].lose + 1;
    ROOM_players_scores[name].combo = 0;
  };

nanahira's avatar
nanahira committed
735
  ROOM_player_flee = global.ROOM_player_flee = function(name) {
736 737 738 739 740 741 742 743 744 745 746 747
    if (!ROOM_players_scores[name]) {
      ROOM_players_scores[name] = {
        win: 0,
        lose: 0,
        flee: 0,
        combo: 0
      };
    }
    ROOM_players_scores[name].flee = ROOM_players_scores[name].flee + 1;
    ROOM_players_scores[name].combo = 0;
  };

nanahira's avatar
nanahira committed
748
  ROOM_player_get_score = global.ROOM_player_get_score = function(player) {
749 750 751 752
    var name, score, total;
    name = player.name_vpass;
    score = ROOM_players_scores[name];
    if (!score) {
nanahira's avatar
nanahira committed
753
      return `${player.name} \${random_score_blank}`;
754
    }
mercury233's avatar
mercury233 committed
755
    total = score.win + score.lose;
756
    if (score.win < 2 && total < 3) {
nanahira's avatar
nanahira committed
757
      return `${player.name} \${random_score_not_enough}`;
758 759
    }
    if (score.combo >= 2) {
nanahira's avatar
nanahira committed
760
      return `\${random_score_part1}${player.name} \${random_score_part2} ${Math.ceil(score.win / total * 100)}\${random_score_part3} ${Math.ceil(score.flee / total * 100)}\${random_score_part4_combo}${score.combo}\${random_score_part5_combo}`;
761
    } else {
nanahira's avatar
nanahira committed
762 763
      //return player.name + " 的今日战绩:胜率" + Math.ceil(score.win/total*100) + "%,逃跑率" + Math.ceil(score.flee/total*100) + "%," + score.combo + "连胜中!"
      return `\${random_score_part1}${player.name} \${random_score_part2} ${Math.ceil(score.win / total * 100)}\${random_score_part3} ${Math.ceil(score.flee / total * 100)}\${random_score_part4}`;
764 765 766
    }
  };

mercury233's avatar
mercury233 committed
767 768
  if (settings.modules.random_duel.post_match_scores) {
    setInterval(function() {
mercury233's avatar
mercury233 committed
769 770 771 772
      var scores, scores_by_lose, scores_by_win, scores_pair;
      scores_pair = _.pairs(ROOM_players_scores);
      scores_by_lose = _.sortBy(scores_pair, function(score) {
        return score[1].lose;
nanahira's avatar
nanahira committed
773
      }).reverse(); // 败场由高到低
mercury233's avatar
mercury233 committed
774
      scores_by_win = _.sortBy(scores_by_lose, function(score) {
mercury233's avatar
mercury233 committed
775
        return score[1].win;
nanahira's avatar
nanahira committed
776
      }).reverse(); // 然后胜场由低到高,再逆转,就是先排胜场再排败场
mercury233's avatar
mercury233 committed
777
      scores = _.first(scores_by_win, 10);
nanahira's avatar
nanahira committed
778
      //log.info scores
mercury233's avatar
mercury233 committed
779 780 781 782 783 784
      request.post({
        url: settings.modules.random_duel.post_match_scores,
        form: {
          accesskey: settings.modules.random_duel.post_match_accesskey,
          rank: JSON.stringify(scores)
        }
nanahira's avatar
nanahira committed
785 786 787 788 789 790
      }, (error, response, body) => {
        if (error) {
          log.warn('RANDOM SCORE POST ERROR', error);
        } else {
          if (response.statusCode !== 204 && response.statusCode !== 200) {
            log.warn('RANDOM SCORE POST FAIL', response.statusCode, response.statusMessage, body);
mercury233's avatar
mercury233 committed
791
          }
nanahira's avatar
nanahira committed
792 793 794 795
        }
      });
    //else
    //  log.info 'RANDOM SCORE POST OK', response.statusCode, response.statusMessage
mercury233's avatar
mercury233 committed
796 797 798
    }, 60000);
  }

nanahira's avatar
nanahira committed
799
  ROOM_find_or_create_by_name = global.ROOM_find_or_create_by_name = function(name, player_ip) {
mercury233's avatar
mercury233 committed
800 801
    var room, uname;
    uname = name.toUpperCase();
mercury233's avatar
mercury233 committed
802
    if (settings.modules.windbot.enabled && (uname.slice(0, 2) === 'AI' || (!settings.modules.random_duel.enabled && uname === ''))) {
mercury233's avatar
mercury233 committed
803 804
      return ROOM_find_or_create_ai(name);
    }
mercury233's avatar
mercury233 committed
805
    if (settings.modules.random_duel.enabled && (uname === '' || uname === 'S' || uname === 'M' || uname === 'T')) {
mercury233's avatar
mercury233 committed
806
      return ROOM_find_or_create_random(uname, player_ip);
mercury233's avatar
mercury233 committed
807 808 809
    }
    if (room = ROOM_find_by_name(name)) {
      return room;
mercury233's avatar
mercury233 committed
810
    } else if (memory_usage >= 90) {
mercury233's avatar
mercury233 committed
811 812 813 814 815 816
      return null;
    } else {
      return new Room(name);
    }
  };

nanahira's avatar
nanahira committed
817
  ROOM_find_or_create_random = global.ROOM_find_or_create_random = function(type, player_ip) {
mercury233's avatar
mercury233 committed
818 819 820 821 822 823 824
    var bannedplayer, max_player, name, playerbanned, result;
    bannedplayer = _.find(ROOM_players_banned, function(bannedplayer) {
      return player_ip === bannedplayer.ip;
    });
    if (bannedplayer) {
      if (bannedplayer.count > 6 && moment() < bannedplayer.time) {
        return {
nanahira's avatar
nanahira committed
825
          "error": `\${random_banned_part1}${bannedplayer.reasons.join('${random_ban_reason_separator}')}\${random_banned_part2}${moment(bannedplayer.time).fromNow(true)}\${random_banned_part3}`
mercury233's avatar
mercury233 committed
826 827
        };
      }
mercury233's avatar
mercury233 committed
828
      if (bannedplayer.count > 3 && moment() < bannedplayer.time && bannedplayer.need_tip && type !== 'T') {
mercury233's avatar
mercury233 committed
829 830
        bannedplayer.need_tip = false;
        return {
nanahira's avatar
nanahira committed
831
          "error": `\${random_deprecated_part1}${bannedplayer.reasons.join('${random_ban_reason_separator}')}\${random_deprecated_part2}${moment(bannedplayer.time).fromNow(true)}\${random_deprecated_part3}`
mercury233's avatar
mercury233 committed
832 833 834 835
        };
      } else if (bannedplayer.need_tip) {
        bannedplayer.need_tip = false;
        return {
nanahira's avatar
nanahira committed
836
          "error": `\${random_warn_part1}${bannedplayer.reasons.join('${random_ban_reason_separator}')}\${random_warn_part2}`
mercury233's avatar
mercury233 committed
837 838 839 840 841 842 843 844
        };
      } else if (bannedplayer.count > 2) {
        bannedplayer.need_tip = true;
      }
    }
    max_player = type === 'T' ? 4 : 2;
    playerbanned = bannedplayer && bannedplayer.count > 3 && moment() < bannedplayer.time;
    result = _.find(ROOM_all, function(room) {
845
      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');
mercury233's avatar
mercury233 committed
846 847
    });
    if (result) {
mercury233's avatar
mercury233 committed
848
      result.welcome = '${random_duel_enter_room_waiting}';
nanahira's avatar
nanahira committed
849
    //log.info 'found room', player_name
mercury233's avatar
mercury233 committed
850
    } else if (memory_usage < 90) {
851
      type = type ? type : settings.modules.random_duel.default_type;
mercury233's avatar
mercury233 committed
852 853 854 855
      name = type + ',RANDOM#' + Math.floor(Math.random() * 100000);
      result = new Room(name);
      result.random_type = type;
      result.max_player = max_player;
mercury233's avatar
mercury233 committed
856
      result.welcome = '${random_duel_enter_room_new}';
mercury233's avatar
mercury233 committed
857
      result.deprecated = playerbanned;
mercury233's avatar
mercury233 committed
858
    } else {
nanahira's avatar
nanahira committed
859
      //log.info 'create room', player_name, name
mercury233's avatar
mercury233 committed
860
      return null;
mercury233's avatar
mercury233 committed
861
    }
862 863 864
    if (result.random_type === 'S') {
      result.welcome2 = '${random_duel_enter_room_single}';
    }
mercury233's avatar
mercury233 committed
865
    if (result.random_type === 'M') {
866 867 868 869
      result.welcome2 = '${random_duel_enter_room_match}';
    }
    if (result.random_type === 'T') {
      result.welcome2 = '${random_duel_enter_room_tag}';
mercury233's avatar
mercury233 committed
870 871 872 873
    }
    return result;
  };

nanahira's avatar
nanahira committed
874
  ROOM_find_or_create_ai = global.ROOM_find_or_create_ai = function(name) {
875
    var ainame, namea, result, room, uname, windbot;
mercury233's avatar
mercury233 committed
876 877 878
    if (name === '') {
      name = 'AI';
    }
mercury233's avatar
mercury233 committed
879
    namea = name.split('#');
880
    uname = name.toUpperCase();
mercury233's avatar
mercury233 committed
881 882
    if (room = ROOM_find_by_name(name)) {
      return room;
883
    } else if (uname === 'AI') {
884 885 886
      windbot = _.sample(_.filter(windbots, function(w) {
        return !w.hidden;
      }));
mercury233's avatar
mercury233 committed
887
      name = 'AI#' + Math.floor(Math.random() * 100000);
mercury233's avatar
mercury233 committed
888 889
    } else if (namea.length > 1) {
      ainame = namea[namea.length - 1];
mercury233's avatar
mercury233 committed
890
      windbot = _.sample(_.filter(windbots, function(w) {
mercury233's avatar
mercury233 committed
891 892 893 894
        return w.name === ainame || w.deck === ainame;
      }));
      if (!windbot) {
        return {
mercury233's avatar
mercury233 committed
895
          "error": "${windbot_deck_not_found}"
mercury233's avatar
mercury233 committed
896 897
        };
      }
mercury233's avatar
mercury233 committed
898
      name = namea[0].toUpperCase() + '#N' + Math.floor(Math.random() * 100000);
mercury233's avatar
mercury233 committed
899
    } else {
900 901 902 903
      windbot = _.sample(_.filter(windbots, function(w) {
        return !w.hidden;
      }));
      name = name + '#' + Math.floor(Math.random() * 10000);
mercury233's avatar
mercury233 committed
904
    }
mercury233's avatar
mercury233 committed
905 906 907
    if (name.replace(/[^\x00-\xff]/g, "00").length > 20) {
      log.info("long ai name", name);
      return {
mercury233's avatar
mercury233 committed
908
        "error": "${windbot_name_too_long}"
mercury233's avatar
mercury233 committed
909 910
      };
    }
mercury233's avatar
mercury233 committed
911 912
    result = new Room(name);
    result.windbot = windbot;
nanahira's avatar
nanahira committed
913
    result.private = true;
mercury233's avatar
mercury233 committed
914 915 916
    return result;
  };

nanahira's avatar
nanahira committed
917
  ROOM_find_by_name = global.ROOM_find_by_name = function(name) {
mercury233's avatar
mercury233 committed
918 919
    var result;
    result = _.find(ROOM_all, function(room) {
920
      return room && room.name === name;
mercury233's avatar
mercury233 committed
921 922 923 924
    });
    return result;
  };

nanahira's avatar
nanahira committed
925
  ROOM_find_by_title = global.ROOM_find_by_title = function(title) {
mercury233's avatar
mercury233 committed
926 927 928 929 930 931 932
    var result;
    result = _.find(ROOM_all, function(room) {
      return room && room.title === title;
    });
    return result;
  };

nanahira's avatar
nanahira committed
933
  ROOM_find_by_port = global.ROOM_find_by_port = function(port) {
mercury233's avatar
mercury233 committed
934
    return _.find(ROOM_all, function(room) {
935
      return room && room.port === port;
mercury233's avatar
mercury233 committed
936 937 938
    });
  };

nanahira's avatar
nanahira committed
939 940 941 942 943 944
  ROOM_find_by_pid = global.ROOM_find_by_pid = function(pid) {
    return _.find(ROOM_all, function(room) {
      return room && room.process_pid === pid;
    });
  };

nanahira's avatar
nanahira committed
945
  ROOM_validate = global.ROOM_validate = function(name) {
mercury233's avatar
mercury233 committed
946 947 948 949 950 951 952 953 954
    var client_name, client_name_and_pass, client_pass;
    client_name_and_pass = name.split('$', 2);
    client_name = client_name_and_pass[0];
    client_pass = client_name_and_pass[1];
    if (!client_pass) {
      return true;
    }
    return !_.find(ROOM_all, function(room) {
      var room_name, room_name_and_pass, room_pass;
955 956 957
      if (!room) {
        return false;
      }
mercury233's avatar
mercury233 committed
958 959 960 961 962 963 964
      room_name_and_pass = room.name.split('$', 2);
      room_name = room_name_and_pass[0];
      room_pass = room_name_and_pass[1];
      return client_name === room_name && client_pass !== room_pass;
    });
  };

nanahira's avatar
nanahira committed
965
  ROOM_unwelcome = global.ROOM_unwelcome = function(room, bad_player, reason) {
nanahira's avatar
nanahira committed
966
    var len3, n, player, ref3;
mercury233's avatar
mercury233 committed
967 968 969
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
970 971 972
    ref3 = room.players;
    for (n = 0, len3 = ref3.length; n < len3; n++) {
      player = ref3[n];
mercury233's avatar
mercury233 committed
973
      if (player && player === bad_player) {
nanahira's avatar
nanahira committed
974
        ygopro.stoc_send_chat(player, `\${unwelcome_warn_part1}${reason}\${unwelcome_warn_part2}`, ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
975 976
      } else if (player && player.pos !== 7 && player !== bad_player) {
        player.flee_free = true;
nanahira's avatar
nanahira committed
977
        ygopro.stoc_send_chat(player, `\${unwelcome_tip_part1}${reason}\${unwelcome_tip_part2}`, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
978 979 980 981
      }
    }
  };

nanahira's avatar
nanahira committed
982
  CLIENT_kick = global.CLIENT_kick = function(client) {
983
    var room;
nanahira's avatar
nanahira committed
984 985 986
    if (!client) {
      return false;
    }
nanahira's avatar
nanahira committed
987
    client.system_kicked = true;
nanahira's avatar
typo  
nanahira committed
988
    if (settings.modules.reconnect.enabled && client.closed) {
nanahira's avatar
fix  
nanahira committed
989
      if (client.server && !client.had_new_reconnection) {
nanahira's avatar
fix  
nanahira committed
990
        room = ROOM_all[client.rid];
991 992 993
        if (room) {
          room.disconnect(client);
        } else {
nanahira's avatar
nanahira committed
994
          SERVER_kick(client.server);
995
        }
nanahira's avatar
fix  
nanahira committed
996
      }
nanahira's avatar
nanahira committed
997 998 999
    } else {
      client.destroy();
    }
nanahira's avatar
nanahira committed
1000
    return true;
nanahira's avatar
nanahira committed
1001 1002
  };

nanahira's avatar
nanahira committed
1003
  SERVER_kick = global.SERVER_kick = function(server) {
nanahira's avatar
typo  
nanahira committed
1004
    if (!server) {
nanahira's avatar
nanahira committed
1005 1006 1007 1008 1009 1010 1011
      return false;
    }
    server.system_kicked = true;
    server.destroy();
    return true;
  };

nanahira's avatar
nanahira committed
1012
  release_disconnect = global.release_disconnect = function(dinfo, reconnected) {
nanahira's avatar
nanahira committed
1013 1014 1015 1016
    if (dinfo.old_client && !reconnected) {
      dinfo.old_client.destroy();
    }
    if (dinfo.old_server && !reconnected) {
nanahira's avatar
nanahira committed
1017
      SERVER_kick(dinfo.old_server);
nanahira's avatar
nanahira committed
1018 1019 1020 1021
    }
    clearTimeout(dinfo.timeout);
  };

nanahira's avatar
nanahira committed
1022
  CLIENT_get_authorize_key = global.CLIENT_get_authorize_key = function(client) {
nanahira's avatar
js  
nanahira committed
1023
    if (!settings.modules.mycard.enabled && client.vpass) {
1024
      return client.name_vpass;
nanahira's avatar
js  
nanahira committed
1025 1026
    } else if (settings.modules.mycard.enabled || settings.modules.tournament_mode.enabled || settings.modules.challonge.enabled || client.is_local) {
      return client.name;
nanahira's avatar
nanahira committed
1027
    } else {
1028
      return client.ip + ":" + client.name;
nanahira's avatar
nanahira committed
1029 1030 1031
    }
  };

nanahira's avatar
nanahira committed
1032
  CLIENT_reconnect_unregister = global.CLIENT_reconnect_unregister = function(client, reconnected, exact) {
nanahira's avatar
nanahira committed
1033 1034 1035 1036
    if (!settings.modules.reconnect.enabled) {
      return false;
    }
    if (disconnect_list[CLIENT_get_authorize_key(client)]) {
nanahira's avatar
nanahira committed
1037 1038 1039
      if (exact && disconnect_list[CLIENT_get_authorize_key(client)].old_client !== client) {
        return false;
      }
nanahira's avatar
nanahira committed
1040 1041 1042 1043 1044 1045 1046
      release_disconnect(disconnect_list[CLIENT_get_authorize_key(client)], reconnected);
      delete disconnect_list[CLIENT_get_authorize_key(client)];
      return true;
    }
    return false;
  };

nanahira's avatar
nanahira committed
1047
  CLIENT_reconnect_register = global.CLIENT_reconnect_register = function(client, room_id, error) {
nanahira's avatar
nanahira committed
1048
    var dinfo, room, tmot;
nanahira's avatar
nanahira committed
1049
    room = ROOM_all[room_id];
nanahira's avatar
nanahira committed
1050 1051 1052
    if (client.had_new_reconnection) {
      return false;
    }
nanahira's avatar
nanahira committed
1053
    if (!settings.modules.reconnect.enabled || !room || client.system_kicked || client.flee_free || disconnect_list[CLIENT_get_authorize_key(client)] || client.is_post_watcher || !CLIENT_is_player(client, room) || room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || room.windbot || (settings.modules.reconnect.auto_surrender_after_disconnect && room.hostinfo.mode !== 1) || (room.random_type && room.get_disconnected_count() > 1)) {
nanahira's avatar
nanahira committed
1054 1055
      return false;
    }
nanahira's avatar
nanahira committed
1056 1057 1058
    // for player in room.players
    //   if player != client and CLIENT_get_authorize_key(player) == CLIENT_get_authorize_key(client)
    //     return false # some issues may occur in this case, so return false
nanahira's avatar
nanahira committed
1059
    dinfo = {
nanahira's avatar
nanahira committed
1060
      room_id: room_id,
nanahira's avatar
nanahira committed
1061 1062 1063 1064 1065 1066
      old_client: client,
      old_server: client.server,
      deckbuf: client.start_deckbuf
    };
    tmot = setTimeout(function() {
      room.disconnect(client, error);
nanahira's avatar
nanahira committed
1067
    //SERVER_kick(dinfo.old_server)
nanahira's avatar
nanahira committed
1068 1069 1070
    }, settings.modules.reconnect.wait_time);
    dinfo.timeout = tmot;
    disconnect_list[CLIENT_get_authorize_key(client)] = dinfo;
nanahira's avatar
nanahira committed
1071 1072
    //console.log("#{client.name} ${disconnect_from_game}")
    ygopro.stoc_send_chat_to_room(room, `${client.name} \${disconnect_from_game}` + (error ? `: ${error}` : ''));
nanahira's avatar
nanahira committed
1073 1074 1075 1076
    if (client.time_confirm_required) {
      client.time_confirm_required = false;
      ygopro.ctos_send(client.server, 'TIME_CONFIRM');
    }
nanahira's avatar
nanahira committed
1077
    if (settings.modules.reconnect.auto_surrender_after_disconnect && room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING) {
1078 1079
      ygopro.ctos_send(client.server, 'SURRENDER');
    }
nanahira's avatar
nanahira committed
1080 1081 1082
    return true;
  };

nanahira's avatar
nanahira committed
1083
  CLIENT_import_data = global.CLIENT_import_data = function(client, old_client, room) {
nanahira's avatar
nanahira committed
1084 1085 1086 1087
    var index, key, len3, len4, n, o, player, ref3;
    ref3 = room.players;
    for (index = n = 0, len3 = ref3.length; n < len3; index = ++n) {
      player = ref3[index];
nanahira's avatar
nanahira committed
1088 1089 1090 1091 1092 1093
      if (player === old_client) {
        room.players[index] = client;
        break;
      }
    }
    room.dueling_players[old_client.pos] = client;
nanahira's avatar
nanahira committed
1094
    if (room.waiting_for_player === old_client) {
nanahira's avatar
nanahira committed
1095 1096
      room.waiting_for_player = client;
    }
nanahira's avatar
nanahira committed
1097
    if (room.waiting_for_player2 === old_client) {
nanahira's avatar
nanahira committed
1098 1099
      room.waiting_for_player2 = client;
    }
nanahira's avatar
nanahira committed
1100
    if (room.selecting_tp === old_client) {
nanahira's avatar
nanahira committed
1101 1102
      room.selecting_tp = client;
    }
nanahira's avatar
nanahira committed
1103 1104 1105
    if (room.determine_firstgo === old_client) {
      room.determine_firstgo = client;
    }
nanahira's avatar
nanahira committed
1106 1107
    for (o = 0, len4 = import_datas.length; o < len4; o++) {
      key = import_datas[o];
nanahira's avatar
nanahira committed
1108 1109
      client[key] = old_client[key];
    }
nanahira's avatar
nanahira committed
1110 1111 1112
    old_client.had_new_reconnection = true;
  };

nanahira's avatar
nanahira committed
1113
  SERVER_clear_disconnect = global.SERVER_clear_disconnect = function(server) {
nanahira's avatar
nanahira committed
1114 1115
    var k, v;
    if (!settings.modules.reconnect.enabled) {
nanahira's avatar
nanahira committed
1116
      return false;
nanahira's avatar
nanahira committed
1117 1118 1119 1120 1121 1122
    }
    for (k in disconnect_list) {
      v = disconnect_list[k];
      if (v && server === v.old_server) {
        release_disconnect(v);
        delete disconnect_list[k];
nanahira's avatar
nanahira committed
1123
        return true;
nanahira's avatar
nanahira committed
1124 1125
      }
    }
nanahira's avatar
nanahira committed
1126 1127 1128
    return false;
  };

nanahira's avatar
nanahira committed
1129
  ROOM_clear_disconnect = global.ROOM_clear_disconnect = function(room_id) {
nanahira's avatar
nanahira committed
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
    var k, v;
    if (!settings.modules.reconnect.enabled) {
      return false;
    }
    for (k in disconnect_list) {
      v = disconnect_list[k];
      if (v && room_id === v.room_id) {
        release_disconnect(v);
        delete disconnect_list[k];
        return true;
      }
    }
    return false;
nanahira's avatar
nanahira committed
1143 1144
  };

nanahira's avatar
nanahira committed
1145
  CLIENT_is_player = global.CLIENT_is_player = function(client, room) {
nanahira's avatar
nanahira committed
1146
    var is_player, len3, n, player, ref3;
nanahira's avatar
nanahira committed
1147
    is_player = false;
nanahira's avatar
nanahira committed
1148 1149 1150
    ref3 = room.players;
    for (n = 0, len3 = ref3.length; n < len3; n++) {
      player = ref3[n];
nanahira's avatar
nanahira committed
1151 1152 1153 1154 1155
      if (client === player) {
        is_player = true;
        break;
      }
    }
nanahira's avatar
fix  
nanahira committed
1156
    return is_player && client.pos <= 3;
nanahira's avatar
nanahira committed
1157 1158
  };

nanahira's avatar
nanahira committed
1159
  CLIENT_is_able_to_reconnect = global.CLIENT_is_able_to_reconnect = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1160
    var disconnect_info, room;
nanahira's avatar
nanahira committed
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
    if (!settings.modules.reconnect.enabled) {
      return false;
    }
    if (client.system_kicked) {
      return false;
    }
    disconnect_info = disconnect_list[CLIENT_get_authorize_key(client)];
    if (!disconnect_info) {
      return false;
    }
nanahira's avatar
nanahira committed
1171 1172 1173 1174 1175
    room = ROOM_all[disconnect_info.room_id];
    if (!room) {
      CLIENT_reconnect_unregister(client);
      return false;
    }
nanahira's avatar
nanahira committed
1176 1177 1178 1179 1180 1181
    if (deckbuf && !_.isEqual(deckbuf, disconnect_info.deckbuf)) {
      return false;
    }
    return true;
  };

nanahira's avatar
nanahira committed
1182
  CLIENT_get_kick_reconnect_target = global.CLIENT_get_kick_reconnect_target = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1183 1184 1185
    var len3, len4, n, o, player, ref3, room;
    for (n = 0, len3 = ROOM_all.length; n < len3; n++) {
      room = ROOM_all[n];
nanahira's avatar
nanahira committed
1186
      if (room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && !room.windbot) {
nanahira's avatar
nanahira committed
1187 1188 1189
        ref3 = room.get_playing_player();
        for (o = 0, len4 = ref3.length; o < len4; o++) {
          player = ref3[o];
1190
          if (!player.closed && player.name === client.name && (settings.modules.challonge.enabled || player.pass === client.pass) && (settings.modules.mycard.enabled || settings.modules.tournament_mode.enabled || player.ip === client.ip || (client.vpass && client.vpass === player.vpass)) && (!deckbuf || _.isEqual(player.start_deckbuf, deckbuf))) {
nanahira's avatar
nanahira committed
1191 1192 1193 1194 1195 1196 1197 1198
            return player;
          }
        }
      }
    }
    return null;
  };

nanahira's avatar
nanahira committed
1199
  CLIENT_is_able_to_kick_reconnect = global.CLIENT_is_able_to_kick_reconnect = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1200 1201 1202 1203 1204 1205
    if (!(settings.modules.reconnect.enabled && settings.modules.reconnect.allow_kick_reconnect)) {
      return false;
    }
    if (!CLIENT_get_kick_reconnect_target(client, deckbuf)) {
      return false;
    }
nanahira's avatar
nanahira committed
1206 1207 1208
    return true;
  };

nanahira's avatar
nanahira committed
1209
  CLIENT_send_pre_reconnect_info = global.CLIENT_send_pre_reconnect_info = function(client, room, old_client) {
nanahira's avatar
nanahira committed
1210
    var len3, n, player, ref3, req_pos;
nanahira's avatar
nanahira committed
1211
    ygopro.stoc_send_chat(client, "${pre_reconnecting_to_room}", ygopro.constants.COLORS.BABYBLUE);
1212
    ygopro.stoc_send(client, 'JOIN_GAME', room.join_game_buffer);
nanahira's avatar
nanahira committed
1213 1214 1215 1216 1217 1218 1219
    req_pos = old_client.pos;
    if (old_client.is_host) {
      req_pos += 0x10;
    }
    ygopro.stoc_send(client, 'TYPE_CHANGE', {
      type: req_pos
    });
nanahira's avatar
nanahira committed
1220 1221 1222
    ref3 = room.players;
    for (n = 0, len3 = ref3.length; n < len3; n++) {
      player = ref3[n];
nanahira's avatar
nanahira committed
1223
      ygopro.stoc_send(client, 'HS_PLAYER_ENTER', {
nanahira's avatar
nanahira committed
1224 1225
        name: player.name,
        pos: player.pos
nanahira's avatar
nanahira committed
1226
      });
nanahira's avatar
nanahira committed
1227 1228 1229
    }
  };

nanahira's avatar
nanahira committed
1230
  CLIENT_send_reconnect_info = global.CLIENT_send_reconnect_info = function(client, server, room) {
nanahira's avatar
nanahira committed
1231 1232
    client.reconnecting = true;
    ygopro.stoc_send_chat(client, "${reconnecting_to_room}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
    switch (room.duel_stage) {
      case ygopro.constants.DUEL_STAGE.FINGER:
        ygopro.stoc_send(client, 'DUEL_START');
        if ((room.hostinfo.mode !== 2 || client.pos === 0 || client.pos === 2) && !client.selected_preduel) {
          ygopro.stoc_send(client, 'SELECT_HAND');
        }
        client.reconnecting = false;
        break;
      case ygopro.constants.DUEL_STAGE.FIRSTGO:
        ygopro.stoc_send(client, 'DUEL_START');
nanahira's avatar
nanahira committed
1243
        if (client === room.selecting_tp) { // and !client.selected_preduel
nanahira's avatar
nanahira committed
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
          ygopro.stoc_send(client, 'SELECT_TP');
        }
        client.reconnecting = false;
        break;
      case ygopro.constants.DUEL_STAGE.SIDING:
        ygopro.stoc_send(client, 'DUEL_START');
        if (!client.selected_preduel) {
          ygopro.stoc_send(client, 'CHANGE_SIDE');
        }
        client.reconnecting = false;
        break;
      default:
        ygopro.ctos_send(server, 'REQUEST_FIELD');
        break;
nanahira's avatar
nanahira committed
1258 1259 1260
    }
  };

nanahira's avatar
nanahira committed
1261
  CLIENT_pre_reconnect = global.CLIENT_pre_reconnect = function(client) {
nanahira's avatar
nanahira committed
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
    var dinfo, player;
    if (CLIENT_is_able_to_reconnect(client)) {
      dinfo = disconnect_list[CLIENT_get_authorize_key(client)];
      client.pre_reconnecting = true;
      client.pos = dinfo.old_client.pos;
      client.setTimeout(300000);
      CLIENT_send_pre_reconnect_info(client, ROOM_all[dinfo.room_id], dinfo.old_client);
    } else if (CLIENT_is_able_to_kick_reconnect(client)) {
      player = CLIENT_get_kick_reconnect_target(client);
      client.pre_reconnecting = true;
      client.pos = player.pos;
      client.setTimeout(300000);
      CLIENT_send_pre_reconnect_info(client, ROOM_all[player.rid], player);
nanahira's avatar
nanahira committed
1275 1276 1277
    }
  };

nanahira's avatar
nanahira committed
1278
  CLIENT_reconnect = global.CLIENT_reconnect = function(client) {
nanahira's avatar
nanahira committed
1279
    var current_old_server, dinfo, room;
nanahira's avatar
nanahira committed
1280 1281 1282 1283 1284 1285 1286
    if (!CLIENT_is_able_to_reconnect(client)) {
      ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED);
      CLIENT_kick(client);
      return;
    }
    client.pre_reconnecting = false;
    dinfo = disconnect_list[CLIENT_get_authorize_key(client)];
nanahira's avatar
nanahira committed
1287
    room = ROOM_all[dinfo.room_id];
nanahira's avatar
nanahira committed
1288 1289 1290 1291 1292 1293
    current_old_server = client.server;
    client.server = dinfo.old_server;
    client.server.client = client;
    dinfo.old_client.server = null;
    current_old_server.client = null;
    current_old_server.had_new_reconnection = true;
nanahira's avatar
nanahira committed
1294
    SERVER_kick(current_old_server);
nanahira's avatar
nanahira committed
1295 1296
    client.established = true;
    client.pre_establish_buffers = [];
nanahira's avatar
nanahira committed
1297 1298 1299
    if (room.random_type || room.arena) {
      room.last_active_time = moment();
    }
nanahira's avatar
nanahira committed
1300 1301
    CLIENT_import_data(client, dinfo.old_client, room);
    CLIENT_send_reconnect_info(client, client.server, room);
nanahira's avatar
nanahira committed
1302 1303
    //console.log("#{client.name} ${reconnect_to_game}")
    ygopro.stoc_send_chat_to_room(room, `${client.name} \${reconnect_to_game}`);
nanahira's avatar
nanahira committed
1304 1305 1306
    CLIENT_reconnect_unregister(client, true);
  };

nanahira's avatar
nanahira committed
1307
  CLIENT_kick_reconnect = global.CLIENT_kick_reconnect = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
    var current_old_server, player, room;
    if (!CLIENT_is_able_to_kick_reconnect(client)) {
      ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED);
      CLIENT_kick(client);
      return;
    }
    client.pre_reconnecting = false;
    player = CLIENT_get_kick_reconnect_target(client, deckbuf);
    room = ROOM_all[player.rid];
    current_old_server = client.server;
    client.server = player.server;
    client.server.client = client;
    ygopro.stoc_send_chat(player, "${reconnect_kicked}", ygopro.constants.COLORS.RED);
    player.server = null;
    player.had_new_reconnection = true;
    CLIENT_kick(player);
    current_old_server.client = null;
    current_old_server.had_new_reconnection = true;
nanahira's avatar
nanahira committed
1326
    SERVER_kick(current_old_server);
nanahira's avatar
nanahira committed
1327 1328 1329 1330 1331 1332 1333
    client.established = true;
    client.pre_establish_buffers = [];
    if (room.random_type || room.arena) {
      room.last_active_time = moment();
    }
    CLIENT_import_data(client, player, room);
    CLIENT_send_reconnect_info(client, client.server, room);
nanahira's avatar
nanahira committed
1334 1335
    //console.log("#{client.name} ${reconnect_to_game}")
    ygopro.stoc_send_chat_to_room(room, `${client.name} \${reconnect_to_game}`);
nanahira's avatar
nanahira committed
1336 1337 1338
    CLIENT_reconnect_unregister(client, true);
  };

nanahira's avatar
nanahira committed
1339
  if (settings.modules.reconnect.enabled) {
nanahira's avatar
nanahira committed
1340
    disconnect_list = {}; // {old_client, old_server, room_id, timeout, deckbuf}
nanahira's avatar
nanahira committed
1341 1342
  }

nanahira's avatar
nanahira committed
1343
  CLIENT_heartbeat_unregister = global.CLIENT_heartbeat_unregister = function(client) {
nanahira's avatar
nanahira committed
1344 1345 1346 1347 1348
    if (!settings.modules.heartbeat_detection.enabled || !client.heartbeat_timeout) {
      return false;
    }
    clearTimeout(client.heartbeat_timeout);
    delete client.heartbeat_timeout;
nanahira's avatar
nanahira committed
1349
    //log.info(2, client.name)
nanahira's avatar
nanahira committed
1350 1351 1352
    return true;
  };

nanahira's avatar
nanahira committed
1353
  CLIENT_heartbeat_register = global.CLIENT_heartbeat_register = function(client, send) {
1354
    if (!settings.modules.heartbeat_detection.enabled || client.closed || client.is_post_watcher || client.pre_reconnecting || client.reconnecting || client.waiting_for_last || client.pos > 3 || client.heartbeat_protected) {
nanahira's avatar
nanahira committed
1355 1356 1357 1358 1359 1360 1361 1362
      return false;
    }
    if (client.heartbeat_timeout) {
      CLIENT_heartbeat_unregister(client);
    }
    client.heartbeat_responsed = false;
    if (send) {
      ygopro.stoc_send(client, "TIME_LIMIT", {
nanahira's avatar
nanahira committed
1363 1364 1365 1366 1367
        player: 0,
        left_time: 0
      });
      ygopro.stoc_send(client, "TIME_LIMIT", {
        player: 1,
nanahira's avatar
nanahira committed
1368 1369 1370 1371 1372 1373 1374 1375
        left_time: 0
      });
    }
    client.heartbeat_timeout = setTimeout(function() {
      CLIENT_heartbeat_unregister(client);
      if (!(client.closed || client.heartbeat_responsed)) {
        client.destroy();
      }
1376
    }, settings.modules.heartbeat_detection.wait_time);
nanahira's avatar
nanahira committed
1377
    //log.info(1, client.name)
nanahira's avatar
nanahira committed
1378 1379 1380
    return true;
  };

nanahira's avatar
nanahira committed
1381
  CLIENT_is_banned_by_mc = global.CLIENT_is_banned_by_mc = function(client) {
nanahira's avatar
nanahira committed
1382 1383 1384
    return client.ban_mc && client.ban_mc.banned && moment().isBefore(client.ban_mc.until);
  };

nanahira's avatar
nanahira committed
1385
  CLIENT_send_replays = global.CLIENT_send_replays = function(client, room) {
nanahira's avatar
nanahira committed
1386
    var buffer, i, len3, n, ref3;
1387
    if (!(settings.modules.replay_delay && !(settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.block_replay_to_player) && room.replays.length && room.hostinfo.mode === 1 && !client.replays_sent && !client.closed)) {
nanahira's avatar
nanahira committed
1388 1389
      return false;
    }
nanahira's avatar
nanahira committed
1390
    client.replays_sent = true;
nanahira's avatar
nanahira committed
1391
    i = 0;
nanahira's avatar
nanahira committed
1392 1393 1394
    ref3 = room.replays;
    for (n = 0, len3 = ref3.length; n < len3; n++) {
      buffer = ref3[n];
nanahira's avatar
nanahira committed
1395
      ++i;
nanahira's avatar
fix  
nanahira committed
1396 1397 1398 1399
      if (buffer) {
        ygopro.stoc_send_chat(client, "${replay_hint_part1}" + i + "${replay_hint_part2}", ygopro.constants.COLORS.BABYBLUE);
        ygopro.stoc_send(client, "REPLAY", buffer);
      }
nanahira's avatar
nanahira committed
1400 1401 1402 1403
    }
    return true;
  };

nanahira's avatar
nanahira committed
1404
  SOCKET_flush_data = global.SOCKET_flush_data = function(sk, datas) {
nanahira's avatar
nanahira committed
1405
    var buffer, len3, n;
nanahira's avatar
js  
nanahira committed
1406 1407 1408
    if (!sk || sk.closed) {
      return false;
    }
nanahira's avatar
nanahira committed
1409 1410
    for (n = 0, len3 = datas.length; n < len3; n++) {
      buffer = datas[n];
1411 1412 1413
      sk.write(buffer);
    }
    datas.splice(0, datas.length);
nanahira's avatar
js  
nanahira committed
1414
    return true;
1415 1416
  };

nanahira's avatar
nanahira committed
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
  getSeedTimet = global.getSeedTimet = function(count) {
    var curTime, i, n, offset, ref3, ret;
    ret = [];
    for (i = n = 0, ref3 = count; (0 <= ref3 ? n < ref3 : n > ref3); i = 0 <= ref3 ? ++n : --n) {
      curTime = null;
      while (!curTime || _.any(ret, function(time) {
          return time === curTime.unix();
        })) {
        curTime = moment();
        offset = Math.floor(Math.random() * 240) - 120;
        if (offset > 0) {
          curTime = curTime.add(offset, "s");
        } else if (offset < 0) {
          curTime = curTime.subtract(-offset, "s");
        }
      }
      ret.push(curTime.unix());
    }
    ret.sort(function(a, b) {
      return a - b;
    });
    return ret;
  };

nanahira's avatar
nanahira committed
1441 1442
  Room = class Room {
    constructor(name, hostinfo) {
nanahira's avatar
nanahira committed
1443
      var death_time, draw_count, duel_log_id, duel_rule, i, lflist, n, o, param, rule, seeds, start_hand, start_lp, time_limit;
mercury233's avatar
mercury233 committed
1444 1445
      this.hostinfo = hostinfo;
      this.name = name;
nanahira's avatar
nanahira committed
1446
      //@alive = true
mercury233's avatar
mercury233 committed
1447 1448 1449
      this.players = [];
      this.player_datas = [];
      this.status = 'starting';
nanahira's avatar
nanahira committed
1450
      //@started = false
mercury233's avatar
mercury233 committed
1451 1452 1453
      this.established = false;
      this.watcher_buffers = [];
      this.recorder_buffers = [];
1454
      this.cloud_replay_id = Math.floor(Math.random() * 100000000);
mercury233's avatar
mercury233 committed
1455 1456 1457
      this.watchers = [];
      this.random_type = '';
      this.welcome = '';
mercury233's avatar
mercury233 committed
1458
      this.scores = {};
nanahira's avatar
nanahira committed
1459
      this.decks = {};
1460
      this.duel_count = 0;
nanahira's avatar
nanahira committed
1461
      this.death = 0;
nanahira's avatar
nanahira committed
1462
      this.turn = 0;
nanahira's avatar
nanahira committed
1463
      this.duel_stage = ygopro.constants.DUEL_STAGE.BEGIN;
nanahira's avatar
nanahira committed
1464
      this.replays = [];
nanahira's avatar
nanahira committed
1465
      this.first_list = [];
mercury233's avatar
mercury233 committed
1466
      ROOM_all.push(this);
mercury233's avatar
fix  
mercury233 committed
1467
      this.hostinfo || (this.hostinfo = JSON.parse(JSON.stringify(settings.hostinfo)));
nanahira's avatar
nanahira committed
1468
      delete this.hostinfo.comment;
mercury233's avatar
mercury233 committed
1469
      if (lflists.length) {
1470
        if (this.hostinfo.rule === 1 && this.hostinfo.lflist === 0) {
mercury233's avatar
mercury233 committed
1471
          this.hostinfo.lflist = _.findIndex(lflists, function(list) {
1472 1473 1474 1475 1476 1477
            return list.tcg;
          });
        }
      } else {
        this.hostinfo.lflist = -1;
      }
mercury233's avatar
mercury233 committed
1478 1479 1480 1481 1482
      if (name.slice(0, 2) === 'M#') {
        this.hostinfo.mode = 1;
      } else if (name.slice(0, 2) === 'T#') {
        this.hostinfo.mode = 2;
        this.hostinfo.start_lp = 16000;
mercury233's avatar
mercury233 committed
1483 1484 1485
      } else if (name.slice(0, 3) === 'AI#') {
        this.hostinfo.rule = 2;
        this.hostinfo.lflist = -1;
mercury233's avatar
mercury233 committed
1486
        this.hostinfo.time_limit = 999;
mercury233's avatar
mercury233 committed
1487 1488 1489
      } else if ((param = name.match(/^(\d)(\d)(T|F)(T|F)(T|F)(\d+),(\d+),(\d+)/i))) {
        this.hostinfo.rule = parseInt(param[1]);
        this.hostinfo.mode = parseInt(param[2]);
1490
        this.hostinfo.duel_rule = (param[3] === 'T' ? 3 : 4);
mercury233's avatar
mercury233 committed
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506
        this.hostinfo.no_check_deck = param[4] === 'T';
        this.hostinfo.no_shuffle_deck = param[5] === 'T';
        this.hostinfo.start_lp = parseInt(param[6]);
        this.hostinfo.start_hand = parseInt(param[7]);
        this.hostinfo.draw_count = parseInt(param[8]);
      } else if ((param = name.match(/(.+)#/)) !== null) {
        rule = param[1].toUpperCase();
        if (rule.match(/(^|,|,)(M|MATCH)(,|,|$)/)) {
          this.hostinfo.mode = 1;
        }
        if (rule.match(/(^|,|,)(T|TAG)(,|,|$)/)) {
          this.hostinfo.mode = 2;
          this.hostinfo.start_lp = 16000;
        }
        if (rule.match(/(^|,|,)(TCGONLY|TO)(,|,|$)/)) {
          this.hostinfo.rule = 1;
mercury233's avatar
mercury233 committed
1507
          this.hostinfo.lflist = _.findIndex(lflists, function(list) {
mercury233's avatar
mercury233 committed
1508
            return list.tcg;
mercury233's avatar
mercury233 committed
1509 1510 1511 1512
          });
        }
        if (rule.match(/(^|,|,)(OCGONLY|OO)(,|,|$)/)) {
          this.hostinfo.rule = 0;
1513
          this.hostinfo.lflist = 0;
mercury233's avatar
mercury233 committed
1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573
        }
        if (rule.match(/(^|,|,)(OT|TCG)(,|,|$)/)) {
          this.hostinfo.rule = 2;
        }
        if ((param = rule.match(/(^|,|,)LP(\d+)(,|,|$)/))) {
          start_lp = parseInt(param[2]);
          if (start_lp <= 0) {
            start_lp = 1;
          }
          if (start_lp >= 99999) {
            start_lp = 99999;
          }
          this.hostinfo.start_lp = start_lp;
        }
        if ((param = rule.match(/(^|,|,)(TIME|TM|TI)(\d+)(,|,|$)/))) {
          time_limit = parseInt(param[3]);
          if (time_limit < 0) {
            time_limit = 180;
          }
          if (time_limit >= 1 && time_limit <= 60) {
            time_limit = time_limit * 60;
          }
          if (time_limit >= 999) {
            time_limit = 999;
          }
          this.hostinfo.time_limit = time_limit;
        }
        if ((param = rule.match(/(^|,|,)(START|ST)(\d+)(,|,|$)/))) {
          start_hand = parseInt(param[3]);
          if (start_hand <= 0) {
            start_hand = 1;
          }
          if (start_hand >= 40) {
            start_hand = 40;
          }
          this.hostinfo.start_hand = start_hand;
        }
        if ((param = rule.match(/(^|,|,)(DRAW|DR)(\d+)(,|,|$)/))) {
          draw_count = parseInt(param[3]);
          if (draw_count >= 35) {
            draw_count = 35;
          }
          this.hostinfo.draw_count = draw_count;
        }
        if ((param = rule.match(/(^|,|,)(LFLIST|LF)(\d+)(,|,|$)/))) {
          lflist = parseInt(param[3]) - 1;
          this.hostinfo.lflist = lflist;
        }
        if (rule.match(/(^|,|,)(NOLFLIST|NF)(,|,|$)/)) {
          this.hostinfo.lflist = -1;
        }
        if (rule.match(/(^|,|,)(NOUNIQUE|NU)(,|,|$)/)) {
          this.hostinfo.rule = 3;
        }
        if (rule.match(/(^|,|,)(NOCHECK|NC)(,|,|$)/)) {
          this.hostinfo.no_check_deck = true;
        }
        if (rule.match(/(^|,|,)(NOSHUFFLE|NS)(,|,|$)/)) {
          this.hostinfo.no_shuffle_deck = true;
        }
nanahira's avatar
nanahira committed
1574
        if (rule.match(/(^|,|,)(IGPRIORITY|PR)(,|,|$)/)) { // deprecated
nanahira's avatar
nanahira committed
1575
          this.hostinfo.duel_rule = 4;
1576 1577 1578
        }
        if ((param = rule.match(/(^|,|,)(DUELRULE|MR)(\d+)(,|,|$)/))) {
          duel_rule = parseInt(param[3]);
mercury233's avatar
mercury233 committed
1579
          if (duel_rule && duel_rule > 0 && duel_rule <= 5) {
1580 1581
            this.hostinfo.duel_rule = duel_rule;
          }
mercury233's avatar
mercury233 committed
1582
        }
nanahira's avatar
nanahira committed
1583
        if (rule.match(/(^|,|,)(NOWATCH|NW)(,|,|$)/)) {
nanahira's avatar
nanahira committed
1584
          this.hostinfo.no_watch = true;
nanahira's avatar
nanahira committed
1585
        }
nanahira's avatar
nanahira committed
1586 1587 1588 1589 1590 1591 1592 1593
        if ((param = rule.match(/(^|,|,)(DEATH|DH)(\d*)(,|,|$)/))) {
          death_time = parseInt(param[3]);
          if (death_time && death_time > 0) {
            this.hostinfo.auto_death = death_time;
          } else {
            this.hostinfo.auto_death = 40;
          }
        }
nanahira's avatar
nanahira committed
1594
        if (settings.modules.tournament_mode.enable_recover && (param = rule.match(/(^|,|,)(RC|RECOVER)(\d*)T(\d*)(,|,|$)/))) {
nanahira's avatar
nanahira committed
1595 1596 1597 1598 1599
          this.recovered = true;
          this.recovering = true;
          this.recover_from_turn = parseInt(param[4]);
          duel_log_id = parseInt(param[3]);
          this.recover_duel_log = _.find(duel_log.duel_log, function(duel) {
nanahira's avatar
nanahira committed
1600
            return duel.id === duel_log_id && duel.roommode !== 2 && duel.players[0].deck;
nanahira's avatar
nanahira committed
1601 1602 1603 1604 1605 1606 1607 1608 1609
          });
          if (!this.recover_duel_log || !fs.existsSync(settings.modules.tournament_mode.replay_path + this.recover_duel_log.replay_filename)) {
            this.error = "${cloud_replay_no}";
            return;
          }
          this.recover_replay = ReplayParser.fromFile(settings.modules.tournament_mode.replay_path + this.recover_duel_log.replay_filename);
          this.recover_buffers = [[], [], [], []];
          this.welcome = "${recover_hint}";
        }
mercury233's avatar
mercury233 committed
1610
      }
nanahira's avatar
nanahira committed
1611
      this.hostinfo.replay_mode = 0; // 0x1: Save the replays in file. 0x2: Block the replays to observers.
1612 1613 1614
      if (settings.modules.tournament_mode.enabled) {
        this.hostinfo.replay_mode |= 0x1;
      }
1615
      if ((settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.block_replay_to_player) || (this.hostinfo.mode === 1 && settings.modules.replay_delay)) {
1616 1617
        this.hostinfo.replay_mode |= 0x2;
      }
1618
      param = [0, this.hostinfo.lflist, this.hostinfo.rule, this.hostinfo.mode, this.hostinfo.duel_rule, (this.hostinfo.no_check_deck ? 'T' : 'F'), (this.hostinfo.no_shuffle_deck ? 'T' : 'F'), this.hostinfo.start_lp, this.hostinfo.start_hand, this.hostinfo.draw_count, this.hostinfo.time_limit, this.hostinfo.replay_mode];
nanahira's avatar
nanahira committed
1619 1620
      if (this.recovered) {
        param.push(this.recover_replay.header.seed);
nanahira's avatar
nanahira committed
1621 1622 1623
        seeds = getSeedTimet(2);
        for (i = n = 0; n < 2; i = ++n) {
          param.push(seeds[i]);
nanahira's avatar
nanahira committed
1624 1625
        }
      } else {
nanahira's avatar
nanahira committed
1626 1627 1628
        seeds = getSeedTimet(3);
        for (i = o = 0; o < 3; i = ++o) {
          param.push(seeds[i]);
nanahira's avatar
nanahira committed
1629
        }
nanahira's avatar
nanahira committed
1630
      }
mercury233's avatar
mercury233 committed
1631 1632
      try {
        this.process = spawn('./ygopro', param, {
mercury233's avatar
mercury233 committed
1633
          cwd: 'ygopro'
mercury233's avatar
mercury233 committed
1634
        });
nanahira's avatar
nanahira committed
1635
        this.process_pid = this.process.pid;
nanahira's avatar
nanahira committed
1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
        this.process.on('error', (err) => {
          _.each(this.players, function(player) {
            return ygopro.stoc_die(player, "${create_room_failed}");
          });
          this.delete();
        });
        this.process.on('exit', (code) => {
          if (!this.disconnector) {
            this.disconnector = 'server';
          }
          this.delete();
        });
mercury233's avatar
mercury233 committed
1648
        this.process.stdout.setEncoding('utf8');
nanahira's avatar
nanahira committed
1649 1650 1651 1652 1653 1654 1655 1656
        this.process.stdout.once('data', (data) => {
          this.established = true;
          if (!this.windbot && settings.modules.http.websocket_roomlist) {
            roomlist.create(this);
          }
          this.port = parseInt(data);
          _.each(this.players, (player) => {
            player.server.connect(this.port, '127.0.0.1', function() {
nanahira's avatar
nanahira committed
1657
              var buffer, len3, p, ref3;
nanahira's avatar
nanahira committed
1658
              ref3 = player.pre_establish_buffers;
nanahira's avatar
nanahira committed
1659 1660
              for (p = 0, len3 = ref3.length; p < len3; p++) {
                buffer = ref3[p];
nanahira's avatar
nanahira committed
1661 1662 1663 1664
                player.server.write(buffer);
              }
              player.established = true;
              player.pre_establish_buffers = [];
mercury233's avatar
mercury233 committed
1665
            });
nanahira's avatar
nanahira committed
1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
          });
          if (this.windbot) {
            setTimeout(() => {
              return this.add_windbot(this.windbot);
            }, 200);
          }
        });
        this.process.stderr.on('data', (data) => {
          data = "Debug: " + data;
          data = data.replace(/\n$/, "");
          log.info("YGOPRO " + data);
          ygopro.stoc_send_chat_to_room(this, data, ygopro.constants.COLORS.RED);
          this.has_ygopro_error = true;
          this.ygopro_error_length = this.ygopro_error_length ? this.ygopro_error_length + data.length : data.length;
          if (this.ygopro_error_length > 10000) {
            this.send_replays();
            this.process.kill();
          }
        });
mercury233's avatar
mercury233 committed
1685
      } catch (error1) {
mercury233's avatar
mercury233 committed
1686
        this.error = "${create_room_failed}";
mercury233's avatar
mercury233 committed
1687 1688 1689
      }
    }

nanahira's avatar
nanahira committed
1690
    delete() {
nanahira's avatar
nanahira committed
1691
      var end_time, formatted_replays, index, len3, log_rep_id, n, name, player_ips, player_names, recorder_buffer, ref3, ref4, repbuf, replay_id, room_name, score, score_array, score_form;
mercury233's avatar
mercury233 committed
1692 1693 1694
      if (this.deleted) {
        return;
      }
nanahira's avatar
nanahira committed
1695
      //log.info 'room-delete', this.name, ROOM_all.length
1696
      score_array = [];
nanahira's avatar
nanahira committed
1697 1698 1699
      ref3 = this.scores;
      for (name in ref3) {
        score = ref3[name];
nanahira's avatar
nanahira committed
1700
        score_form = {
1701
          name: name.split('$')[0],
nanahira's avatar
nanahira committed
1702
          score: score,
1703 1704
          deck: null,
          name_vpass: name
nanahira's avatar
nanahira committed
1705 1706 1707 1708 1709
        };
        if (this.decks[name]) {
          score_form.deck = this.decks[name];
        }
        score_array.push(score_form);
1710
      }
1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722
      if (settings.modules.random_duel.record_match_scores && this.random_type === 'M') {
        if (score_array.length === 2) {
          if (score_array[0].score !== score_array[1].score) {
            if (score_array[0].score > score_array[1].score) {
              ROOM_player_win(score_array[0].name_vpass);
              ROOM_player_lose(score_array[1].name_vpass);
            } else {
              ROOM_player_win(score_array[1].name_vpass);
              ROOM_player_lose(score_array[0].name_vpass);
            }
          }
        }
nanahira's avatar
nanahira committed
1723 1724
        if (score_array.length === 1) { // same name
          //log.info score_array[0].name
1725 1726 1727 1728
          ROOM_player_win(score_array[0].name_vpass);
          ROOM_player_lose(score_array[0].name_vpass);
        }
      }
nanahira's avatar
-5  
nanahira committed
1729
      if (settings.modules.arena_mode.enabled && this.arena) {
nanahira's avatar
nanahira committed
1730
        //log.info 'SCORE', score_array, @start_time
nanahira's avatar
-5  
nanahira committed
1731 1732 1733 1734 1735 1736 1737
        end_time = moment().format();
        if (!this.start_time) {
          this.start_time = end_time;
        }
        if (score_array.length !== 2) {
          if (!score_array[0]) {
            score_array[0] = {
nanahira's avatar
nanahira committed
1738
              name: null,
nanahira's avatar
nanahira committed
1739 1740
              score: -5,
              deck: null
nanahira's avatar
-5  
nanahira committed
1741
            };
1742
          }
nanahira's avatar
-5  
nanahira committed
1743 1744
          if (!score_array[1]) {
            score_array[1] = {
nanahira's avatar
nanahira committed
1745
              name: null,
nanahira's avatar
nanahira committed
1746 1747
              score: -5,
              deck: null
mercury233's avatar
merge  
mercury233 committed
1748
            };
nanahira's avatar
-5  
nanahira committed
1749 1750 1751
          }
          score_array[0].score = -5;
          score_array[1].score = -5;
mercury233's avatar
merge  
mercury233 committed
1752
        }
nanahira's avatar
fix  
nanahira committed
1753
        formatted_replays = [];
nanahira's avatar
nanahira committed
1754 1755 1756
        ref4 = this.replays;
        for (n = 0, len3 = ref4.length; n < len3; n++) {
          repbuf = ref4[n];
nanahira's avatar
fix  
nanahira committed
1757 1758 1759 1760
          if (repbuf) {
            formatted_replays.push(repbuf.toString("base64"));
          }
        }
nanahira's avatar
-5  
nanahira committed
1761 1762 1763 1764 1765 1766 1767 1768
        request.post({
          url: settings.modules.arena_mode.post_score,
          form: {
            accesskey: settings.modules.arena_mode.accesskey,
            usernameA: score_array[0].name,
            usernameB: score_array[1].name,
            userscoreA: score_array[0].score,
            userscoreB: score_array[1].score,
nanahira's avatar
nanahira committed
1769 1770
            userdeckA: score_array[0].deck,
            userdeckB: score_array[1].deck,
nanahira's avatar
nanahira committed
1771 1772
            first: JSON.stringify(this.first_list),
            replays: JSON.stringify(formatted_replays),
nanahira's avatar
-5  
nanahira committed
1773 1774 1775 1776
            start: this.start_time,
            end: end_time,
            arena: this.arena
          }
nanahira's avatar
nanahira committed
1777 1778 1779 1780 1781 1782
        }, (error, response, body) => {
          if (error) {
            log.warn('SCORE POST ERROR', error);
          } else {
            if (response.statusCode !== 204 && response.statusCode !== 200) {
              log.warn('SCORE POST FAIL', response.statusCode, response.statusMessage, this.name, body);
nanahira's avatar
-5  
nanahira committed
1783
            }
nanahira's avatar
nanahira committed
1784 1785
          }
        });
mercury233's avatar
mercury233 committed
1786
      }
nanahira's avatar
nanahira committed
1787 1788
      //else
      //  log.info 'SCORE POST OK', response.statusCode, response.statusMessage, @name, body
nanahira's avatar
nanahira committed
1789
      if (settings.modules.challonge.enabled && this.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && this.hostinfo.mode !== 2 && !this.kicked) {
nanahira's avatar
js  
nanahira committed
1790
        room_name = this.name;
nanahira's avatar
nanahira committed
1791
        challonge.matches._update({
1792
          id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
1793
          matchId: this.challonge_info.id,
nanahira's avatar
nanahira committed
1794
          match: this.get_challonge_score(),
nanahira's avatar
nanahira committed
1795 1796
          callback: function(err, data) {
            if (err) {
nanahira's avatar
js  
nanahira committed
1797
              log.warn("Errored pushing scores to Challonge.", room_name, err);
nanahira's avatar
nanahira committed
1798 1799
            } else {
              refresh_challonge_cache();
nanahira's avatar
nanahira committed
1800 1801 1802 1803
            }
          }
        });
      }
mercury233's avatar
mercury233 committed
1804
      if (this.player_datas.length && settings.modules.cloud_replay.enabled) {
1805
        replay_id = this.cloud_replay_id;
mercury233's avatar
mercury233 committed
1806 1807 1808
        if (this.has_ygopro_error) {
          log_rep_id = true;
        }
mercury233's avatar
mercury233 committed
1809 1810 1811
        player_names = this.player_datas[0].name + (this.player_datas[2] ? "+" + this.player_datas[2].name : "") + " VS " + (this.player_datas[1] ? this.player_datas[1].name : "AI") + (this.player_datas[3] ? "+" + this.player_datas[3].name : "");
        player_ips = [];
        _.each(this.player_datas, function(player) {
1812
          player_ips.push(player.key);
mercury233's avatar
mercury233 committed
1813 1814 1815
        });
        recorder_buffer = Buffer.concat(this.recorder_buffers);
        zlib.deflate(recorder_buffer, function(err, replay_buffer) {
1816
          var date_time, recorded_ip;
mercury233's avatar
mercury233 committed
1817
          replay_buffer = replay_buffer.toString('binary');
nanahira's avatar
nanahira committed
1818
          //log.info err, replay_buffer
mercury233's avatar
mercury233 committed
1819
          date_time = moment().format('YYYY-MM-DD HH:mm:ss');
nanahira's avatar
nanahira committed
1820
          //replay_id=Math.floor(Math.random()*100000000)
mercury233's avatar
mercury233 committed
1821
          redisdb.hmset("replay:" + replay_id, "replay_id", replay_id, "replay_buffer", replay_buffer, "player_names", player_names, "date_time", date_time);
nanahira's avatar
nanahira committed
1822
          if (!log_rep_id && !settings.modules.cloud_replay.never_expire) {
mercury233's avatar
mercury233 committed
1823 1824
            redisdb.expire("replay:" + replay_id, 60 * 60 * 24);
          }
mercury233's avatar
mercury233 committed
1825 1826 1827 1828 1829 1830 1831 1832
          recorded_ip = [];
          _.each(player_ips, function(player_ip) {
            if (_.contains(recorded_ip, player_ip)) {
              return;
            }
            recorded_ip.push(player_ip);
            redisdb.lpush(player_ip + ":replays", replay_id);
          });
mercury233's avatar
mercury233 committed
1833
          if (log_rep_id) {
mercury233's avatar
mercury233 committed
1834 1835
            log.info("error replay: R#" + replay_id);
          }
mercury233's avatar
mercury233 committed
1836 1837 1838 1839 1840 1841
        });
      }
      this.watcher_buffers = [];
      this.recorder_buffers = [];
      this.players = [];
      if (this.watcher) {
mercury233's avatar
mercury233 committed
1842
        this.watcher.destroy();
mercury233's avatar
mercury233 committed
1843
      }
mercury233's avatar
fix  
mercury233 committed
1844 1845 1846
      if (this.recorder) {
        this.recorder.destroy();
      }
mercury233's avatar
mercury233 committed
1847 1848
      this.deleted = true;
      index = _.indexOf(ROOM_all, this);
nanahira's avatar
nanahira committed
1849
      if (settings.modules.reconnect.enabled) {
nanahira's avatar
nanahira committed
1850
        ROOM_clear_disconnect(index);
nanahira's avatar
nanahira committed
1851
      }
mercury233's avatar
mercury233 committed
1852
      if (index !== -1) {
1853
        ROOM_all[index] = null;
mercury233's avatar
mercury233 committed
1854
      }
mercury233's avatar
mercury233 committed
1855
      if (!this.windbot && this.established && settings.modules.http.websocket_roomlist) {
nanahira's avatar
nanahira committed
1856 1857
        //ROOM_all.splice(index, 1) unless index == -1
        roomlist.delete(this);
mercury233's avatar
mercury233 committed
1858
      }
nanahira's avatar
nanahira committed
1859
    }
mercury233's avatar
mercury233 committed
1860

nanahira's avatar
nanahira committed
1861
    get_playing_player() {
mercury233's avatar
mercury233 committed
1862 1863 1864 1865 1866 1867 1868 1869
      var playing_player;
      playing_player = [];
      _.each(this.players, function(player) {
        if (player.pos < 4) {
          playing_player.push(player);
        }
      });
      return playing_player;
nanahira's avatar
nanahira committed
1870
    }
mercury233's avatar
mercury233 committed
1871

nanahira's avatar
nanahira committed
1872
    get_host() {
mercury233's avatar
mercury233 committed
1873 1874 1875 1876 1877 1878 1879 1880
      var host_player;
      host_player = null;
      _.each(this.players, function(player) {
        if (player.is_host) {
          host_player = player;
        }
      });
      return host_player;
nanahira's avatar
nanahira committed
1881
    }
mercury233's avatar
mercury233 committed
1882

nanahira's avatar
nanahira committed
1883
    get_disconnected_count() {
nanahira's avatar
nanahira committed
1884
      var found, len3, n, player, ref3;
1885
      if (!settings.modules.reconnect.enabled) {
1886
        return 0;
1887
      }
1888
      found = 0;
nanahira's avatar
nanahira committed
1889 1890 1891
      ref3 = this.get_playing_player();
      for (n = 0, len3 = ref3.length; n < len3; n++) {
        player = ref3[n];
1892 1893
        if (player.closed) {
          found++;
1894 1895 1896
        }
      }
      return found;
nanahira's avatar
nanahira committed
1897
    }
1898

nanahira's avatar
nanahira committed
1899
    get_challonge_score() {
nanahira's avatar
nanahira committed
1900
      var challonge_duel_log;
nanahira's avatar
nanahira committed
1901
      if (!settings.modules.challonge.enabled || this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || this.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
1902 1903 1904
        return null;
      }
      challonge_duel_log = {};
1905
      if (this.scores[this.dueling_players[0].name_vpass] > this.scores[this.dueling_players[1].name_vpass]) {
nanahira's avatar
nanahira committed
1906
        challonge_duel_log.winnerId = this.dueling_players[0].challonge_info.id;
1907
      } else if (this.scores[this.dueling_players[0].name_vpass] < this.scores[this.dueling_players[1].name_vpass]) {
nanahira's avatar
nanahira committed
1908 1909 1910 1911 1912 1913
        challonge_duel_log.winnerId = this.dueling_players[1].challonge_info.id;
      } else {
        challonge_duel_log.winnerId = "tie";
      }
      if (settings.modules.challonge.post_detailed_score) {
        if (this.dueling_players[0].challonge_info.id === this.challonge_info.player1Id && this.dueling_players[1].challonge_info.id === this.challonge_info.player2Id) {
1914
          challonge_duel_log.scoresCsv = this.scores[this.dueling_players[0].name_vpass] + "-" + this.scores[this.dueling_players[1].name_vpass];
nanahira's avatar
nanahira committed
1915
        } else if (this.dueling_players[1].challonge_info.id === this.challonge_info.player1Id && this.dueling_players[0].challonge_info.id === this.challonge_info.player2Id) {
1916
          challonge_duel_log.scoresCsv = this.scores[this.dueling_players[1].name_vpass] + "-" + this.scores[this.dueling_players[0].name_vpass];
nanahira's avatar
nanahira committed
1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930
        } else {
          challonge_duel_log.scoresCsv = "0-0";
          log.warn("Score mismatch.", this.name);
        }
      } else {
        if (challonge_duel_log.winnerId === this.challonge_info.player1Id) {
          challonge_duel_log.scoresCsv = "1-0";
        } else if (challonge_duel_log.winnerId === this.challonge_info.player2Id) {
          challonge_duel_log.scoresCsv = "0-1";
        } else {
          challonge_duel_log.scoresCsv = "0-0";
        }
      }
      return challonge_duel_log;
nanahira's avatar
nanahira committed
1931
    }
nanahira's avatar
nanahira committed
1932

nanahira's avatar
nanahira committed
1933
    get_old_hostinfo() { // Just for supporting websocket roomlist in old MyCard client....
nanahira's avatar
nanahira committed
1934 1935
      var ret;
      ret = _.clone(this.hostinfo);
nanahira's avatar
nanahira committed
1936
      ret.enable_priority = this.hostinfo.duel_rule !== 5;
nanahira's avatar
nanahira committed
1937
      return ret;
nanahira's avatar
nanahira committed
1938
    }
nanahira's avatar
nanahira committed
1939

nanahira's avatar
nanahira committed
1940
    send_replays() {
nanahira's avatar
nanahira committed
1941
      var len3, len4, n, o, player, ref3, ref4;
nanahira's avatar
nanahira committed
1942 1943 1944
      if (!(settings.modules.replay_delay && this.replays.length && this.hostinfo.mode === 1)) {
        return false;
      }
nanahira's avatar
nanahira committed
1945 1946 1947
      ref3 = this.players;
      for (n = 0, len3 = ref3.length; n < len3; n++) {
        player = ref3[n];
nanahira's avatar
nanahira committed
1948 1949 1950
        if (player) {
          CLIENT_send_replays(player, this);
        }
nanahira's avatar
nanahira committed
1951
      }
nanahira's avatar
nanahira committed
1952 1953 1954
      ref4 = this.watchers;
      for (o = 0, len4 = ref4.length; o < len4; o++) {
        player = ref4[o];
nanahira's avatar
nanahira committed
1955 1956 1957
        if (player) {
          CLIENT_send_replays(player, this);
        }
nanahira's avatar
nanahira committed
1958 1959
      }
      return true;
nanahira's avatar
nanahira committed
1960
    }
nanahira's avatar
nanahira committed
1961

nanahira's avatar
nanahira committed
1962
    add_windbot(botdata) {
mercury233's avatar
mercury233 committed
1963 1964
      this.windbot = botdata;
      request({
nanahira's avatar
nanahira committed
1965 1966 1967 1968 1969 1970 1971 1972
        url: `http://${settings.modules.windbot.server_ip}:${settings.modules.windbot.port}/?name=${encodeURIComponent(botdata.name)}&deck=${encodeURIComponent(botdata.deck)}&host=${settings.modules.windbot.my_ip}&port=${settings.port}&dialog=${encodeURIComponent(botdata.dialog)}&version=${settings.version}&password=${encodeURIComponent(this.name)}`
      }, (error, response, body) => {
        if (error) {
          log.warn('windbot add error', error, this.name);
          ygopro.stoc_send_chat_to_room(this, "${add_windbot_failed}", ygopro.constants.COLORS.RED);
        }
      });
    }
mercury233's avatar
mercury233 committed
1973

nanahira's avatar
nanahira committed
1974 1975 1976
    //else
    //log.info "windbot added"
    connect(client) {
mercury233's avatar
mercury233 committed
1977
      var host_player;
mercury233's avatar
mercury233 committed
1978
      this.players.push(client);
nanahira's avatar
nanahira committed
1979
      client.join_time = moment();
mercury233's avatar
mercury233 committed
1980
      if (this.random_type) {
mercury233's avatar
mercury233 committed
1981
        client.abuse_count = 0;
mercury233's avatar
mercury233 committed
1982 1983
        host_player = this.get_host();
        if (host_player && (host_player !== client)) {
nanahira's avatar
nanahira committed
1984
          // 进来时已经有人在等待了,互相记录为匹配过
mercury233's avatar
mercury233 committed
1985 1986
          ROOM_players_oppentlist[host_player.ip] = client.ip;
          ROOM_players_oppentlist[client.ip] = host_player.ip;
mercury233's avatar
mercury233 committed
1987
        } else {
nanahira's avatar
nanahira committed
1988
          // 第一个玩家刚进来,还没就位
mercury233's avatar
mercury233 committed
1989
          ROOM_players_oppentlist[client.ip] = null;
mercury233's avatar
mercury233 committed
1990 1991 1992
        }
      }
      if (this.established) {
nanahira's avatar
nanahira committed
1993
        if (!this.windbot && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1994 1995 1996
          roomlist.update(this);
        }
        client.server.connect(this.port, '127.0.0.1', function() {
nanahira's avatar
nanahira committed
1997 1998 1999 2000
          var buffer, len3, n, ref3;
          ref3 = client.pre_establish_buffers;
          for (n = 0, len3 = ref3.length; n < len3; n++) {
            buffer = ref3[n];
mercury233's avatar
mercury233 committed
2001 2002 2003 2004 2005 2006
            client.server.write(buffer);
          }
          client.established = true;
          client.pre_establish_buffers = [];
        });
      }
nanahira's avatar
nanahira committed
2007
    }
mercury233's avatar
mercury233 committed
2008

nanahira's avatar
nanahira committed
2009
    disconnect(client, error) {
nanahira's avatar
nanahira committed
2010
      var index, left_name, len3, len4, n, o, player, ref3, ref4;
nanahira's avatar
nanahira committed
2011 2012 2013
      if (client.had_new_reconnection) {
        return;
      }
mercury233's avatar
mercury233 committed
2014
      if (client.is_post_watcher) {
nanahira's avatar
nanahira committed
2015
        ygopro.stoc_send_chat_to_room(this, `${client.name} \${quit_watch}` + (error ? `: ${error}` : ''));
mercury233's avatar
mercury233 committed
2016 2017 2018 2019
        index = _.indexOf(this.watchers, client);
        if (index !== -1) {
          this.watchers.splice(index, 1);
        }
nanahira's avatar
nanahira committed
2020
        //client.room = null
nanahira's avatar
nanahira committed
2021
        SERVER_kick(client.server);
mercury233's avatar
mercury233 committed
2022
      } else {
nanahira's avatar
nanahira committed
2023
        //log.info(client.name, @duel_stage != ygopro.constants.DUEL_STAGE.BEGIN, @disconnector, @random_type, @players.length)
nanahira's avatar
nanahira committed
2024
        if (this.arena && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && this.disconnector !== 'server' && !this.arena_score_handled) {
2025
          if (settings.modules.arena_mode.punish_quit_before_match && this.players.length === 2 && !client.arena_quit_free) {
nanahira's avatar
nanahira committed
2026 2027 2028
            ref3 = this.players;
            for (n = 0, len3 = ref3.length; n < len3; n++) {
              player = ref3[n];
2029 2030 2031
              if (player.pos !== 7) {
                this.scores[player.name_vpass] = 0;
              }
2032
            }
2033
            this.scores[client.name_vpass] = -9;
2034
          } else {
nanahira's avatar
nanahira committed
2035 2036 2037
            ref4 = this.players;
            for (o = 0, len4 = ref4.length; o < len4; o++) {
              player = ref4[o];
2038 2039 2040 2041
              if (player.pos !== 7) {
                this.scores[player.name_vpass] = -5;
              }
            }
nanahira's avatar
nanahira committed
2042
            if (this.players.length === 2 && !client.arena_quit_free) {
nanahira's avatar
nanahira committed
2043 2044
              this.scores[client.name_vpass] = -9;
            }
nanahira's avatar
-5  
nanahira committed
2045
          }
nanahira's avatar
nanahira committed
2046
          this.arena_score_handled = true;
2047
        }
mercury233's avatar
mercury233 committed
2048 2049 2050 2051
        index = _.indexOf(this.players, client);
        if (index !== -1) {
          this.players.splice(index, 1);
        }
nanahira's avatar
nanahira committed
2052
        if (this.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && this.disconnector !== 'server' && client.pos < 4) {
2053
          this.finished = true;
nanahira's avatar
nanahira committed
2054
          if (!this.finished_by_death) {
2055
            this.scores[client.name_vpass] = -9;
nanahira's avatar
fix  
nanahira committed
2056
            if (this.random_type && !client.flee_free && (!settings.modules.reconnect.enabled || this.get_disconnected_count() === 0)) {
nanahira's avatar
nanahira committed
2057
              ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}");
mercury233's avatar
mercury233 committed
2058 2059 2060
              if (settings.modules.random_duel.record_match_scores && this.random_type === 'M') {
                ROOM_player_flee(client.name_vpass);
              }
nanahira's avatar
nanahira committed
2061
            }
mercury233's avatar
mercury233 committed
2062
          }
mercury233's avatar
mercury233 committed
2063
        }
nanahira's avatar
nanahira committed
2064 2065
        if (this.players.length && !(this.windbot && client.is_host) && !(this.arena && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && client.pos <= 3)) {
          left_name = (settings.modules.hide_name && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN ? "********" : client.name);
nanahira's avatar
nanahira committed
2066
          ygopro.stoc_send_chat_to_room(this, `${left_name} \${left_game}` + (error ? `: ${error}` : ''));
nanahira's avatar
nanahira committed
2067
          if (!this.windbot && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
2068 2069 2070
            roomlist.update(this);
          }
        } else {
nanahira's avatar
nanahira committed
2071
          //client.room = null
nanahira's avatar
nanahira committed
2072
          this.send_replays();
mercury233's avatar
mercury233 committed
2073
          this.process.kill();
nanahira's avatar
nanahira committed
2074 2075
          //client.room = null
          this.delete();
mercury233's avatar
mercury233 committed
2076
        }
nanahira's avatar
nanahira committed
2077
        if (!CLIENT_reconnect_unregister(client, false, true)) {
nanahira's avatar
nanahira committed
2078
          SERVER_kick(client.server);
nanahira's avatar
nanahira committed
2079
        }
mercury233's avatar
mercury233 committed
2080
      }
nanahira's avatar
nanahira committed
2081
    }
mercury233's avatar
mercury233 committed
2082

nanahira's avatar
nanahira committed
2083
    start_death() {
nanahira's avatar
nanahira committed
2084
      var oppo_pos, win_pos;
nanahira's avatar
nanahira committed
2085
      if (this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || this.death) {
nanahira's avatar
nanahira committed
2086 2087 2088
        return false;
      }
      oppo_pos = this.hostinfo.mode === 2 ? 2 : 1;
nanahira's avatar
nanahira committed
2089
      if (this.duel_stage === ygopro.constants.DUEL_STAGE.DUELING) {
nanahira's avatar
nanahira committed
2090 2091 2092 2093 2094 2095 2096
        switch (settings.modules.http.quick_death_rule) {
          case 3:
            this.death = -2;
            ygopro.stoc_send_chat_to_room(this, "${death_start_phase}", ygopro.constants.COLORS.BABYBLUE);
            break;
          default:
            this.death = (this.turn ? this.turn + 4 : 5);
nanahira's avatar
nanahira committed
2097
            ygopro.stoc_send_chat_to_room(this, "${death_start}", ygopro.constants.COLORS.BABYBLUE); // Extra duel started in siding
nanahira's avatar
nanahira committed
2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138
        }
      } else {
        switch (settings.modules.http.quick_death_rule) {
          case 2:
          case 3:
            if (this.scores[this.dueling_players[0].name_vpass] === this.scores[this.dueling_players[oppo_pos].name_vpass]) {
              if (settings.modules.http.quick_death_rule === 3) {
                this.death = -1;
                ygopro.stoc_send_chat_to_room(this, "${death_start_quick}", ygopro.constants.COLORS.BABYBLUE);
              } else {
                this.death = 5;
                ygopro.stoc_send_chat_to_room(this, "${death_start_siding}", ygopro.constants.COLORS.BABYBLUE);
              }
            } else {
              win_pos = this.scores[this.dueling_players[0].name_vpass] > this.scores[this.dueling_players[oppo_pos].name_vpass] ? 0 : oppo_pos;
              this.finished_by_death = true;
              ygopro.stoc_send_chat_to_room(this, "${death2_finish_part1}" + this.dueling_players[win_pos].name + "${death2_finish_part2}", ygopro.constants.COLORS.BABYBLUE);
              if (this.hostinfo.mode === 1) {
                CLIENT_send_replays(this.dueling_players[oppo_pos - win_pos], this);
              }
              ygopro.stoc_send(this.dueling_players[oppo_pos - win_pos], 'DUEL_END');
              if (this.hostinfo.mode === 2) {
                ygopro.stoc_send(this.dueling_players[oppo_pos - win_pos + 1], 'DUEL_END');
              }
              this.scores[this.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
              CLIENT_kick(this.dueling_players[oppo_pos - win_pos]);
              if (this.hostinfo.mode === 2) {
                CLIENT_kick(this.dueling_players[oppo_pos - win_pos + 1]);
              }
            }
            break;
          case 1:
            this.death = -1;
            ygopro.stoc_send_chat_to_room(this, "${death_start_quick}", ygopro.constants.COLORS.BABYBLUE);
            break;
          default:
            this.death = 5;
            ygopro.stoc_send_chat_to_room(this, "${death_start_siding}", ygopro.constants.COLORS.BABYBLUE);
        }
      }
      return true;
nanahira's avatar
nanahira committed
2139
    }
nanahira's avatar
nanahira committed
2140

nanahira's avatar
nanahira committed
2141
    cancel_death() {
nanahira's avatar
nanahira committed
2142
      if (this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || !this.death) {
nanahira's avatar
nanahira committed
2143 2144 2145 2146 2147
        return false;
      }
      this.death = 0;
      ygopro.stoc_send_chat_to_room(this, "${death_cancel}", ygopro.constants.COLORS.BABYBLUE);
      return true;
nanahira's avatar
nanahira committed
2148
    }
mercury233's avatar
mercury233 committed
2149

nanahira's avatar
nanahira committed
2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161
    termiate() {
      if (this.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
        this.scores[this.dueling_players[0].name_vpass] = 0;
        this.scores[this.dueling_players[1].name_vpass] = 0;
      }
      this.kicked = true;
      this.send_replays();
      this.process.kill();
      return this.delete();
    }

    finish_recover(fail) {
nanahira's avatar
nanahira committed
2162
      var buffer, len3, n, player, ref3, results;
nanahira's avatar
nanahira committed
2163 2164 2165 2166 2167 2168
      if (fail) {
        ygopro.stoc_send_chat_to_room(this, "${recover_fail}", ygopro.constants.COLORS.RED);
        return this.termiate();
      } else {
        ygopro.stoc_send_chat_to_room(this, "${recover_success}", ygopro.constants.COLORS.BABYBLUE);
        this.recovering = false;
nanahira's avatar
nanahira committed
2169
        ref3 = this.get_playing_player();
nanahira's avatar
nanahira committed
2170
        results = [];
nanahira's avatar
nanahira committed
2171 2172
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          player = ref3[n];
nanahira's avatar
nanahira committed
2173
          results.push((function() {
nanahira's avatar
nanahira committed
2174 2175
            var len4, o, ref4, results1;
            ref4 = this.recover_buffers[player.pos];
nanahira's avatar
nanahira committed
2176
            results1 = [];
nanahira's avatar
nanahira committed
2177 2178
            for (o = 0, len4 = ref4.length; o < len4; o++) {
              buffer = ref4[o];
nanahira's avatar
nanahira committed
2179 2180 2181 2182 2183 2184 2185 2186 2187
              results1.push(ygopro.stoc_send(player, "GAME_MSG", buffer));
            }
            return results1;
          }).call(this));
        }
        return results;
      }
    }

nanahira's avatar
nanahira committed
2188
  };
mercury233's avatar
mercury233 committed
2189

nanahira's avatar
nanahira committed
2190
  // 网络连接
神楽坂玲奈's avatar
神楽坂玲奈 committed
2191
  net.createServer(function(client) {
mercury233's avatar
mercury233 committed
2192 2193
    var connect_count, server;
    client.ip = client.remoteAddress;
nanahira's avatar
nanahira committed
2194
    client.is_local = client.ip && (client.ip.includes('127.0.0.1') || client.ip.includes(real_windbot_server_ip));
mercury233's avatar
mercury233 committed
2195
    connect_count = ROOM_connected_ip[client.ip] || 0;
2196
    if (!settings.modules.test_mode.no_connect_count_limit && !client.is_local) {
mercury233's avatar
mercury233 committed
2197 2198 2199
      connect_count++;
    }
    ROOM_connected_ip[client.ip] = connect_count;
nanahira's avatar
nanahira committed
2200 2201 2202
    //log.info "connect", client.ip, ROOM_connected_ip[client.ip]

    // server stand for the connection to ygopro server process
神楽坂玲奈's avatar
神楽坂玲奈 committed
2203 2204
    server = new net.Socket();
    client.server = server;
nanahira's avatar
nanahira committed
2205
    server.client = client;
nanahira's avatar
nanahira committed
2206 2207 2208
    client.setTimeout(2000); //连接前超时2秒
    
    // 释放处理
2209
    client.on('close', function(had_error) {
mercury233's avatar
mercury233 committed
2210
      var room;
nanahira's avatar
nanahira committed
2211
      //log.info "client closed", client.name, had_error
2212
      room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
2213 2214 2215 2216 2217
      connect_count = ROOM_connected_ip[client.ip];
      if (connect_count > 0) {
        connect_count--;
      }
      ROOM_connected_ip[client.ip] = connect_count;
nanahira's avatar
nanahira committed
2218
      //log.info "disconnect", client.ip, ROOM_connected_ip[client.ip]
2219
      if (!client.closed) {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2220
        client.closed = true;
nanahira's avatar
nanahira committed
2221 2222 2223
        if (settings.modules.heartbeat_detection.enabled) {
          CLIENT_heartbeat_unregister(client);
        }
2224
        if (room) {
nanahira's avatar
nanahira committed
2225
          if (!CLIENT_reconnect_register(client, client.rid)) {
nanahira's avatar
nanahira committed
2226 2227 2228
            room.disconnect(client);
          }
        } else if (!client.had_new_reconnection) {
nanahira's avatar
nanahira committed
2229
          SERVER_kick(client.server);
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2230
        }
mercury233's avatar
mercury233 committed
2231 2232
      }
    });
2233
    client.on('error', function(error) {
mercury233's avatar
mercury233 committed
2234
      var room;
nanahira's avatar
nanahira committed
2235
      //log.info "client error", client.name, error
2236
      room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
2237 2238 2239 2240 2241
      connect_count = ROOM_connected_ip[client.ip];
      if (connect_count > 0) {
        connect_count--;
      }
      ROOM_connected_ip[client.ip] = connect_count;
nanahira's avatar
nanahira committed
2242
      //log.info "err disconnect", client.ip, ROOM_connected_ip[client.ip]
2243
      if (!client.closed) {
nanahira's avatar
nanahira committed
2244
        client.closed = true;
2245
        if (room) {
nanahira's avatar
nanahira committed
2246
          if (!CLIENT_reconnect_register(client, client.rid, error)) {
nanahira's avatar
nanahira committed
2247 2248 2249
            room.disconnect(client, error);
          }
        } else if (!client.had_new_reconnection) {
nanahira's avatar
nanahira committed
2250
          SERVER_kick(client.server);
2251
        }
神楽坂玲奈's avatar
神楽坂玲奈 committed
2252
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2253
    });
2254
    client.on('timeout', function() {
nanahira's avatar
nanahira committed
2255
      if (!(settings.modules.reconnect.enabled && (disconnect_list[CLIENT_get_authorize_key(client)] || client.had_new_reconnection))) {
nanahira's avatar
nanahira committed
2256
        client.destroy();
nanahira's avatar
nanahira committed
2257
      }
2258
    });
2259
    server.on('close', function(had_error) {
2260
      var room;
2261 2262
      if (!server.closed) {
        server.closed = true;
mercury233's avatar
mercury233 committed
2263
      }
nanahira's avatar
nanahira committed
2264 2265 2266
      if (!server.client) {
        return;
      }
nanahira's avatar
nanahira committed
2267
      //log.info "server closed", server.client.name, had_error
nanahira's avatar
nanahira committed
2268
      room = ROOM_all[server.client.rid];
nanahira's avatar
nanahira committed
2269
      if (room && !server.system_kicked && !server.had_new_reconnection) {
nanahira's avatar
nanahira committed
2270
        //log.info "server close", server.client.ip, ROOM_connected_ip[server.client.ip]
nanahira's avatar
nanahira committed
2271 2272
        room.disconnector = 'server';
      }
nanahira's avatar
rev  
nanahira committed
2273
      if (!server.client.closed) {
nanahira's avatar
nanahira committed
2274
        ygopro.stoc_send_chat(server.client, "${server_closed}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
2275 2276
        //if room and settings.modules.replay_delay
        //  room.send_replays()
nanahira's avatar
nanahira committed
2277 2278
        CLIENT_kick(server.client);
        SERVER_clear_disconnect(server);
mercury233's avatar
mercury233 committed
2279 2280
      }
    });
2281
    server.on('error', function(error) {
2282
      var room;
2283
      server.closed = error;
nanahira's avatar
nanahira committed
2284 2285 2286
      if (!server.client) {
        return;
      }
nanahira's avatar
nanahira committed
2287
      //log.info "server error", client.name, error
nanahira's avatar
nanahira committed
2288
      room = ROOM_all[server.client.rid];
nanahira's avatar
nanahira committed
2289
      if (room && !server.system_kicked && !server.had_new_reconnection) {
nanahira's avatar
nanahira committed
2290
        //log.info "server err close", client.ip, ROOM_connected_ip[client.ip]
nanahira's avatar
nanahira committed
2291 2292
        room.disconnector = 'server';
      }
nanahira's avatar
nanahira committed
2293
      if (!server.client.closed) {
nanahira's avatar
nanahira committed
2294 2295 2296
        ygopro.stoc_send_chat(server.client, `\${server_error}: ${error}`, ygopro.constants.COLORS.RED);
        //if room and settings.modules.replay_delay
        //  room.send_replays()
nanahira's avatar
nanahira committed
2297 2298
        CLIENT_kick(server.client);
        SERVER_clear_disconnect(server);
mercury233's avatar
mercury233 committed
2299 2300
      }
    });
mercury233's avatar
mercury233 committed
2301
    if (ROOM_bad_ip[client.ip] > 5 || ROOM_connected_ip[client.ip] > 10) {
mercury233's avatar
mercury233 committed
2302
      log.info('BAD IP', client.ip);
nanahira's avatar
nanahira committed
2303
      CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2304 2305
      return;
    }
mercury233's avatar
mercury233 committed
2306
    if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2307 2308 2309
      client.open_cloud_replay = function(err, replay) {
        var buffer;
        if (err || !replay) {
mercury233's avatar
mercury233 committed
2310
          ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
2311
          return;
mercury233's avatar
mercury233 committed
2312
        }
mercury233's avatar
mercury233 committed
2313
        redisdb.expire("replay:" + replay.replay_id, 60 * 60 * 48);
nanahira's avatar
nanahira committed
2314
        buffer = Buffer.from(replay.replay_buffer, 'binary');
mercury233's avatar
mercury233 committed
2315 2316
        zlib.unzip(buffer, function(err, replay_buffer) {
          if (err) {
mercury233's avatar
mercury233 committed
2317
            log.info("cloud replay unzip error: " + err);
mercury233's avatar
mercury233 committed
2318
            ygopro.stoc_send_chat(client, "${cloud_replay_error}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
2319
            CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2320 2321
            return;
          }
nanahira's avatar
nanahira committed
2322
          ygopro.stoc_send_chat(client, `\${cloud_replay_playing} R#${replay.replay_id} ${replay.player_names} ${replay.date_time}`, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
2323
          client.write(replay_buffer, function() {
nanahira's avatar
nanahira committed
2324
            CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2325
          });
mercury233's avatar
mercury233 committed
2326
        });
mercury233's avatar
mercury233 committed
2327 2328
      };
    }
nanahira's avatar
nanahira committed
2329 2330
    // 需要重构
    // 客户端到服务端(ctos)协议分析
神楽坂玲奈's avatar
神楽坂玲奈 committed
2331
    client.pre_establish_buffers = new Array();
nanahira's avatar
nanahira committed
2332
    client.on('data', async function(ctos_buffer) {
2333
      var bad_ip_count, buffer, ctos_filter, handle_data, len3, len4, len5, n, o, p, ref3, ref4, ref5, room;
2334
      if (client.is_post_watcher) {
2335
        room = ROOM_all[client.rid];
2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358
        if (room) {
          handle_data = (await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ["CHAT"], {
            client: client,
            server: client.server
          }));
          if (handle_data.feedback) {
            log.warn(handle_data.feedback.message, client.name, client.ip);
            if (handle_data.feedback.type === "OVERSIZE" || ROOM_bad_ip[client.ip] > 5) {
              bad_ip_count = ROOM_bad_ip[client.ip];
              if (bad_ip_count) {
                ROOM_bad_ip[client.ip] = bad_ip_count + 1;
              } else {
                ROOM_bad_ip[client.ip] = 1;
              }
              CLIENT_kick(client);
              return;
            }
          }
          ref3 = handle_data.datas;
          for (n = 0, len3 = ref3.length; n < len3; n++) {
            buffer = ref3[n];
            room.watcher.write(buffer);
          }
2359
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2360
      } else {
nanahira's avatar
nanahira committed
2361 2362 2363 2364 2365 2366
        ctos_filter = settings.modules.reconnect.enabled && client.pre_reconnecting ? ["UPDATE_DECK"] : null;
        handle_data = (await ygopro.helper.handleBuffer(ctos_buffer, "CTOS", ctos_filter, {
          client: client,
          server: client.server
        }));
        if (handle_data.feedback) {
2367
          log.warn(handle_data.feedback.message, client.name, client.ip);
nanahira's avatar
nanahira committed
2368
          if (handle_data.feedback.type === "OVERSIZE" || ROOM_bad_ip[client.ip] > 5) {
mercury233's avatar
mercury233 committed
2369
            bad_ip_count = ROOM_bad_ip[client.ip];
mercury233's avatar
mercury233 committed
2370
            if (bad_ip_count) {
mercury233's avatar
mercury233 committed
2371
              ROOM_bad_ip[client.ip] = bad_ip_count + 1;
mercury233's avatar
mercury233 committed
2372
            } else {
mercury233's avatar
mercury233 committed
2373
              ROOM_bad_ip[client.ip] = 1;
mercury233's avatar
mercury233 committed
2374
            }
nanahira's avatar
nanahira committed
2375
            CLIENT_kick(client);
nanahira's avatar
nanahira committed
2376
            return;
mercury233's avatar
mercury233 committed
2377
          }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2378
        }
nanahira's avatar
nanahira committed
2379 2380 2381
        if (!client.server) {
          return;
        }
2382
        if (client.established) {
nanahira's avatar
nanahira committed
2383 2384 2385
          ref4 = handle_data.datas;
          for (o = 0, len4 = ref4.length; o < len4; o++) {
            buffer = ref4[o];
2386 2387 2388 2389 2390 2391
            client.server.write(buffer);
          }
        } else {
          ref5 = handle_data.datas;
          for (p = 0, len5 = ref5.length; p < len5; p++) {
            buffer = ref5[p];
2392 2393 2394
            client.pre_establish_buffers.push(buffer);
          }
        }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2395 2396
      }
    });
nanahira's avatar
nanahira committed
2397
    // 服务端到客户端(stoc)
nanahira's avatar
nanahira committed
2398 2399 2400 2401 2402 2403 2404
    server.on('data', async function(stoc_buffer) {
      var buffer, handle_data, len3, n, ref3;
      handle_data = (await ygopro.helper.handleBuffer(stoc_buffer, "STOC", null, {
        client: server.client,
        server: server
      }));
      if (handle_data.feedback) {
2405
        log.warn(handle_data.feedback.message, server.client.name, server.client.ip);
nanahira's avatar
nanahira committed
2406
        if (handle_data.feedback.type === "OVERSIZE") {
2407
          server.destroy();
nanahira's avatar
nanahira committed
2408
          return;
mercury233's avatar
mercury233 committed
2409
        }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
2410
      }
nanahira's avatar
nanahira committed
2411
      if (server.client && !server.client.closed) {
nanahira's avatar
nanahira committed
2412 2413 2414
        ref3 = handle_data.datas;
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          buffer = ref3[n];
nanahira's avatar
nanahira committed
2415 2416
          server.client.write(buffer);
        }
2417
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2418
    });
神楽坂玲奈's avatar
神楽坂玲奈 committed
2419
  }).listen(settings.port, function() {
mercury233's avatar
mercury233 committed
2420
    log.info("server started", settings.port);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2421
  });
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2422

mercury233's avatar
mercury233 committed
2423 2424 2425 2426
  if (settings.modules.stop) {
    log.info("NOTE: server not open due to config, ", settings.modules.stop);
  }

Yuzurisa's avatar
Yuzurisa committed
2427 2428 2429 2430 2431
  deck_name_match = global.deck_name_match = function(deck_name, player_name) {
    var parsed_deck_name;
    if (deck_name === player_name || deck_name === player_name + ".ydk" || deck_name === player_name + ".ydk.ydk") {
      return true;
    }
nanahira's avatar
js  
nanahira committed
2432
    parsed_deck_name = deck_name.match(/^([^\+ \uff0b]+)[\+ \uff0b](.+?)(\.ydk){0,2}$/);
Yuzurisa's avatar
Yuzurisa committed
2433 2434 2435
    return parsed_deck_name && (player_name === parsed_deck_name[1] || player_name === parsed_deck_name[2]);
  };

nanahira's avatar
nanahira committed
2436 2437
  // 功能模块
  // return true to cancel a synchronous message
nanahira's avatar
nanahira committed
2438
  ygopro.ctos_follow('PLAYER_INFO', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
2439
    var banMCRequest, geo, lang, name, name_full, struct, vpass;
nanahira's avatar
nanahira committed
2440 2441
    // checkmate use username$password, but here don't
    // so remove the password
nanahira's avatar
nanahira committed
2442 2443 2444 2445 2446 2447
    name_full = info.name.split("$");
    name = name_full[0];
    vpass = name_full[1];
    if (vpass && !vpass.length) {
      vpass = null;
    }
mercury233's avatar
mercury233 committed
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459
    if (_.any(settings.ban.illegal_id, function(badid) {
      var matchs, regexp;
      regexp = new RegExp(badid, 'i');
      matchs = name.match(regexp);
      if (matchs) {
        name = matchs[1];
        return true;
      }
      return false;
    }, name)) {
      client.rag = true;
    }
2460
    if (settings.modules.mycard.enabled && settings.modules.mycard.ban_get && !client.is_local) {
nanahira's avatar
nanahira committed
2461
      try {
nanahira's avatar
fix  
nanahira committed
2462
        banMCRequest = (await axios.get(settings.modules.mycard.ban_get, {
nanahira's avatar
nanahira committed
2463 2464 2465 2466 2467 2468 2469
          paramsSerializer: qs.stringify,
          params: {
            user: name
          }
        }));
        if (typeof banMCRequest.data === "object") {
          client.ban_mc = banMCRequest.data;
nanahira's avatar
nanahira committed
2470
        } else {
nanahira's avatar
nanahira committed
2471
          log.warn("ban get bad json", banMCRequest.data);
nanahira's avatar
nanahira committed
2472
        }
nanahira's avatar
nanahira committed
2473 2474 2475 2476
      } catch (error1) {
        e = error1;
        log.warn('ban get error', e.toString());
      }
nanahira's avatar
nanahira committed
2477
    }
2478
    struct = ygopro.structs.get("CTOS_PlayerInfo");
2479 2480 2481 2482
    struct._setBuff(buffer);
    struct.set("name", name);
    buffer = struct.buffer;
    client.name = name;
nanahira's avatar
nanahira committed
2483
    client.vpass = vpass;
2484
    client.name_vpass = vpass ? name + "$" + vpass : name;
2485
    if (!settings.modules.i18n.auto_pick || client.is_local) {
nanahira's avatar
nanahira committed
2486
      client.lang = settings.modules.i18n.default;
mercury233's avatar
mercury233 committed
2487 2488 2489
    } else {
      geo = geoip.lookup(client.ip);
      if (!geo) {
mercury233's avatar
mercury233 committed
2490
        log.warn("fail to locate ip", client.name, client.ip);
mercury233's avatar
mercury233 committed
2491 2492 2493 2494 2495
        client.lang = settings.modules.i18n.fallback;
      } else {
        if (lang = settings.modules.i18n.map[geo.country]) {
          client.lang = lang;
        } else {
nanahira's avatar
nanahira committed
2496
          //log.info("Not in map", geo.country, client.name, client.ip)
mercury233's avatar
mercury233 committed
2497 2498 2499
          client.lang = settings.modules.i18n.fallback;
        }
      }
mercury233's avatar
mercury233 committed
2500
    }
2501
    return false;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2502 2503
  });

nanahira's avatar
fix  
nanahira committed
2504
  ygopro.ctos_follow('JOIN_GAME', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
2505
    var available_logs, check_buffer_indentity, create_room_with_action, len3, len4, n, name, o, pre_room, recover_match, ref3, ref4, replay_id, room;
nanahira's avatar
nanahira committed
2506
    //log.info info
mercury233's avatar
mercury233 committed
2507
    info.pass = info.pass.trim();
nanahira's avatar
nanahira committed
2508 2509
    client.pass = info.pass;
    if (CLIENT_is_able_to_reconnect(client) || CLIENT_is_able_to_kick_reconnect(client)) {
nanahira's avatar
nanahira committed
2510 2511 2512
      CLIENT_pre_reconnect(client);
      return;
    } else if (settings.modules.stop) {
mercury233's avatar
mercury233 committed
2513
      ygopro.stoc_die(client, settings.modules.stop);
nanahira's avatar
nanahira committed
2514 2515
    } else if (info.pass === "Marshtomp" || info.pass === "the Big Brother") {
      ygopro.stoc_die(client, "${bad_user_name}");
mercury233's avatar
mercury233 committed
2516
    } else if (info.pass.toUpperCase() === "R" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2517
      ygopro.stoc_send_chat(client, "${cloud_replay_hint}", ygopro.constants.COLORS.BABYBLUE);
2518
      redisdb.lrange(CLIENT_get_authorize_key(client) + ":replays", 0, 2, function(err, result) {
mercury233's avatar
mercury233 committed
2519 2520 2521
        _.each(result, function(replay_id, id) {
          redisdb.hgetall("replay:" + replay_id, function(err, replay) {
            if (err || !replay) {
mercury233's avatar
mercury233 committed
2522 2523 2524
              if (err) {
                log.info("cloud replay getall error: " + err);
              }
mercury233's avatar
mercury233 committed
2525 2526
              return;
            }
nanahira's avatar
nanahira committed
2527
            ygopro.stoc_send_chat(client, `<${id - 0 + 1}> R#${replay_id} ${replay.player_names} ${replay.date_time}`, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
2528
          });
mercury233's avatar
mercury233 committed
2529 2530
        });
      });
nanahira's avatar
nanahira committed
2531
      // 强行等待异步执行完毕_(:з」∠)_
mercury233's avatar
mercury233 committed
2532 2533 2534
      setTimeout((function() {
        ygopro.stoc_send(client, 'ERROR_MSG', {
          msg: 1,
mercury233's avatar
mercury233 committed
2535
          code: 9
mercury233's avatar
mercury233 committed
2536
        });
nanahira's avatar
nanahira committed
2537
        CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2538
      }), 500);
nanahira's avatar
nanahira committed
2539 2540 2541
    } else if (info.pass.toUpperCase() === "RC" && settings.modules.tournament_mode.enable_recover) {
      ygopro.stoc_send_chat(client, "${recover_replay_hint}", ygopro.constants.COLORS.BABYBLUE);
      available_logs = duel_log.duel_log.filter(function(duel) {
nanahira's avatar
nanahira committed
2542
        return duel.id && duel.players[0].deck && duel.roommode !== 2 && _.any(duel.players, function(player) {
nanahira's avatar
nanahira committed
2543 2544 2545 2546 2547
          return player.real_name === client.name_vpass;
        });
      }).slice(0, 8);
      _.each(available_logs, function(duel) {
        var player_names;
nanahira's avatar
nanahira committed
2548
        player_names = duel.players[0].real_name.split("$")[0] + (duel.players[2] ? "+" + duel.players[2].real_name.split("$")[0] : "") + " VS " + (duel.players[1] ? duel.players[1].real_name.split("$")[0] : "AI") + (duel.players[3] ? "+" + duel.players[3].real_name.split("$")[0] : "");
nanahira's avatar
nanahira committed
2549 2550 2551 2552 2553 2554 2555 2556 2557 2558
        return ygopro.stoc_send_chat(client, `<${duel.id}> ${player_names} ${duel.time}`, ygopro.constants.COLORS.BABYBLUE);
      });
      // 强行等待异步执行完毕_(:з」∠)_
      setTimeout((function() {
        ygopro.stoc_send(client, 'ERROR_MSG', {
          msg: 1,
          code: 9
        });
        CLIENT_kick(client);
      }), 500);
mercury233's avatar
mercury233 committed
2559
    } else if (info.pass.slice(0, 2).toUpperCase() === "R#" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2560
      replay_id = info.pass.split("#")[1];
mercury233's avatar
fix  
mercury233 committed
2561
      if (replay_id > 0 && replay_id <= 9) {
mercury233's avatar
mercury233 committed
2562
        redisdb.lindex(client.ip + ":replays", replay_id - 1, function(err, replay_id) {
mercury233's avatar
mercury233 committed
2563
          if (err || !replay_id) {
mercury233's avatar
mercury233 committed
2564 2565 2566
            if (err) {
              log.info("cloud replay replayid error: " + err);
            }
mercury233's avatar
mercury233 committed
2567
            ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
2568 2569 2570 2571
            return;
          }
          redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
        });
mercury233's avatar
mercury233 committed
2572 2573 2574
      } else if (replay_id) {
        redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
      } else {
mercury233's avatar
mercury233 committed
2575
        ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
2576
      }
mercury233's avatar
mercury233 committed
2577
    } else if (info.pass.toUpperCase() === "W" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2578 2579
      replay_id = Cloud_replay_ids[Math.floor(Math.random() * Cloud_replay_ids.length)];
      redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
nanahira's avatar
nanahira committed
2580
    } else if (info.version !== settings.version) { // and (info.version < 9020 or settings.version != 4927) #强行兼容23333版
mercury233's avatar
mercury233 committed
2581
      ygopro.stoc_send_chat(client, settings.modules.update, ygopro.constants.COLORS.RED);
mercury233's avatar
fix  
mercury233 committed
2582 2583 2584 2585
      ygopro.stoc_send(client, 'ERROR_MSG', {
        msg: 4,
        code: settings.version
      });
nanahira's avatar
nanahira committed
2586
      CLIENT_kick(client);
nanahira's avatar
nanahira committed
2587
    } else if (!info.pass.length && !settings.modules.random_duel.enabled && !settings.modules.windbot.enabled && !settings.modules.challonge.enabled) {
mercury233's avatar
mercury233 committed
2588
      ygopro.stoc_die(client, "${blank_room_name}");
mercury233's avatar
fix  
mercury233 committed
2589
    } else if (info.pass.length && settings.modules.mycard.enabled && info.pass.slice(0, 3) !== 'AI#') {
mercury233's avatar
mercury233 committed
2590
      ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2591
      if (info.pass.length <= 8) {
mercury233's avatar
mercury233 committed
2592
        ygopro.stoc_die(client, '${invalid_password_length}');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2593 2594
        return;
      }
nanahira's avatar
nanahira committed
2595 2596
      //if info.version >= 9020 and settings.version == 4927 #强行兼容23333版
      //  info.version = settings.version
2597
      //  struct = ygopro.structs.get("CTOS_JoinGame")
nanahira's avatar
nanahira committed
2598 2599 2600
      //  struct._setBuff(buffer)
      //  struct.set("version", info.version)
      //  buffer = struct.buffer
nanahira's avatar
nanahira committed
2601
      buffer = Buffer.from(info.pass.slice(0, 8), 'base64');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2602
      if (buffer.length !== 6) {
mercury233's avatar
mercury233 committed
2603
        ygopro.stoc_die(client, '${invalid_password_payload}');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2604 2605
        return;
      }
nanahira's avatar
nanahira committed
2606
      check_buffer_indentity = function(buf) {
nanahira's avatar
nanahira committed
2607
        var checksum, i, n, ref3;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2608
        checksum = 0;
nanahira's avatar
nanahira committed
2609
        for (i = n = 0, ref3 = buf.length; (0 <= ref3 ? n < ref3 : n > ref3); i = 0 <= ref3 ? ++n : --n) {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2610
          checksum += buf.readUInt8(i);
2611
        }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2612 2613
        return (checksum & 0xFF) === 0;
      };
nanahira's avatar
nanahira committed
2614
      create_room_with_action = function(buffer, decrypted_buffer, match_permit) {
nanahira's avatar
nanahira committed
2615
        var action, len3, len4, n, name, o, opt1, opt2, opt3, options, player, ref3, ref4, room, room_title, title;
nanahira's avatar
nanahira committed
2616 2617 2618
        if (client.closed) {
          return;
        }
2619 2620
        action = buffer.readUInt8(1) >> 4;
        if (buffer !== decrypted_buffer && (action === 1 || action === 2 || action === 4)) {
mercury233's avatar
mercury233 committed
2621
          ygopro.stoc_die(client, '${invalid_password_unauthorized}');
2622 2623
          return;
        }
nanahira's avatar
nanahira committed
2624 2625 2626 2627 2628
        // 1 create public room
        // 2 create private room
        // 3 join room by id
        // 4 create or join room by id (use for match)
        // 5 join room by title
2629 2630 2631 2632
        switch (action) {
          case 1:
          case 2:
            name = crypto.createHash('md5').update(info.pass + client.name).digest('base64').slice(0, 10).replace('+', '-').replace('/', '_');
mercury233's avatar
mercury233 committed
2633
            if (ROOM_find_by_name(name)) {
mercury233's avatar
mercury233 committed
2634
              ygopro.stoc_die(client, '${invalid_password_existed}');
2635 2636 2637
              return;
            }
            opt1 = buffer.readUInt8(2);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2638
            opt2 = buffer.readUInt16LE(3);
2639 2640
            opt3 = buffer.readUInt8(5);
            options = {
nanahira's avatar
nanahira committed
2641 2642
              lflist: settings.hostinfo.lflist,
              time_limit: settings.hostinfo.time_limit,
2643 2644
              rule: (opt1 >> 5) & 3,
              mode: (opt1 >> 3) & 3,
nanahira's avatar
nanahira committed
2645
              duel_rule: (!!((opt1 >> 2) & 1) ? 4 : 5),
2646 2647 2648 2649
              no_check_deck: !!((opt1 >> 1) & 1),
              no_shuffle_deck: !!(opt1 & 1),
              start_lp: opt2,
              start_hand: opt3 >> 4,
nanahira's avatar
nanahira committed
2650
              draw_count: opt3 & 0xF,
nanahira's avatar
nanahira committed
2651 2652
              no_watch: settings.hostinfo.no_watch,
              auto_death: settings.hostinfo.auto_death
2653
            };
mercury233's avatar
mercury233 committed
2654
            options.lflist = _.findIndex(lflists, function(list) {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2655
              return ((options.rule === 1) === list.tcg) && list.date.isBefore();
神楽坂玲奈's avatar
神楽坂玲奈 committed
2656
            });
nanahira's avatar
nanahira committed
2657 2658 2659 2660 2661 2662
            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)) {
nanahira's avatar
fix  
nanahira committed
2663
              log.warn("BAD ROOM NAME LEVEL 3", room_title, client.name, client.ip);
nanahira's avatar
nanahira committed
2664
              ygopro.stoc_die(client, "${bad_roomname_level3}");
nanahira's avatar
nanahira committed
2665 2666 2667 2668 2669 2670
              return;
            } else if (_.any(badwords.level2, function(badword) {
              var regexp;
              regexp = new RegExp(badword, 'i');
              return room_title.match(regexp);
            }, room_title)) {
nanahira's avatar
fix  
nanahira committed
2671
              log.warn("BAD ROOM NAME LEVEL 2", room_title, client.name, client.ip);
nanahira's avatar
nanahira committed
2672
              ygopro.stoc_die(client, "${bad_roomname_level2}");
nanahira's avatar
nanahira committed
2673 2674 2675 2676 2677 2678
              return;
            } else if (_.any(badwords.level1, function(badword) {
              var regexp;
              regexp = new RegExp(badword, 'i');
              return room_title.match(regexp);
            }, room_title)) {
nanahira's avatar
fix  
nanahira committed
2679
              log.warn("BAD ROOM NAME LEVEL 1", room_title, client.name, client.ip);
nanahira's avatar
nanahira committed
2680
              ygopro.stoc_die(client, "${bad_roomname_level1}");
nanahira's avatar
nanahira committed
2681 2682
              return;
            }
2683
            room = new Room(name, options);
nanahira's avatar
nanahira committed
2684
            if (room) {
nanahira's avatar
nanahira committed
2685
              room.title = room_title;
nanahira's avatar
nanahira committed
2686
              room.private = action === 2;
nanahira's avatar
nanahira committed
2687
            }
2688 2689 2690
            break;
          case 3:
            name = info.pass.slice(8);
mercury233's avatar
mercury233 committed
2691
            room = ROOM_find_by_name(name);
2692
            if (!room) {
mercury233's avatar
mercury233 committed
2693
              ygopro.stoc_die(client, '${invalid_password_not_found}');
2694 2695 2696 2697
              return;
            }
            break;
          case 4:
nanahira's avatar
move  
nanahira committed
2698 2699 2700 2701
            if (match_permit && !match_permit.permit) {
              ygopro.stoc_die(client, '${invalid_password_unauthorized}');
              return;
            }
mercury233's avatar
mercury233 committed
2702
            room = ROOM_find_or_create_by_name('M#' + info.pass.slice(8));
nanahira's avatar
nanahira committed
2703
            if (room) {
nanahira's avatar
nanahira committed
2704 2705 2706
              ref3 = room.get_playing_player();
              for (n = 0, len3 = ref3.length; n < len3; n++) {
                player = ref3[n];
nanahira's avatar
nanahira committed
2707 2708 2709 2710 2711 2712
                if (!(player && player.name === client.name)) {
                  continue;
                }
                ygopro.stoc_die(client, '${invalid_password_unauthorized}');
                return;
              }
nanahira's avatar
nanahira committed
2713
              room.private = true;
nanahira's avatar
nanahira committed
2714 2715 2716 2717 2718
              room.arena = settings.modules.arena_mode.mode;
              if (room.arena === "athletic") {
                room.max_player = 2;
                room.welcome = "${athletic_arena_tip}";
              }
2719
            }
2720
            break;
mercury233's avatar
mercury233 committed
2721 2722 2723 2724 2725 2726 2727 2728
          case 5:
            title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ');
            room = ROOM_find_by_title(title);
            if (!room) {
              ygopro.stoc_die(client, '${invalid_password_not_found}');
              return;
            }
            break;
2729
          default:
mercury233's avatar
mercury233 committed
2730
            ygopro.stoc_die(client, '${invalid_password_action}');
2731 2732
            return;
        }
mercury233's avatar
mercury233 committed
2733
        if (!room) {
mercury233's avatar
mercury233 committed
2734
          ygopro.stoc_die(client, "${server_full}");
mercury233's avatar
mercury233 committed
2735
        } else if (room.error) {
mercury233's avatar
mercury233 committed
2736
          ygopro.stoc_die(client, room.error);
nanahira's avatar
nanahira committed
2737
        } else if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
2738
          if (settings.modules.cloud_replay.enable_halfway_watch && !room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
2739
            client.setTimeout(300000); //连接后超时5分钟
mercury233's avatar
mercury233 committed
2740 2741
            client.rid = _.indexOf(ROOM_all, room);
            client.is_post_watcher = true;
nanahira's avatar
nanahira committed
2742
            ygopro.stoc_send_chat_to_room(room, `${client.name} \${watch_join}`);
mercury233's avatar
mercury233 committed
2743 2744
            room.watchers.push(client);
            ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2745 2746 2747
            ref4 = room.watcher_buffers;
            for (o = 0, len4 = ref4.length; o < len4; o++) {
              buffer = ref4[o];
mercury233's avatar
mercury233 committed
2748 2749 2750 2751 2752
              client.write(buffer);
            }
          } else {
            ygopro.stoc_die(client, "${watch_denied}");
          }
nanahira's avatar
nanahira committed
2753
        } else if (room.hostinfo.no_watch && room.players.length >= (room.hostinfo.mode === 2 ? 4 : 2)) {
nanahira's avatar
fix  
nanahira committed
2754
          ygopro.stoc_die(client, "${watch_denied_room}");
mercury233's avatar
mercury233 committed
2755
        } else {
nanahira's avatar
nanahira committed
2756 2757
          //client.room = room
          client.setTimeout(300000); //连接后超时5分钟
2758 2759
          client.rid = _.indexOf(ROOM_all, room);
          room.connect(client);
mercury233's avatar
mercury233 committed
2760
        }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2761
      };
nanahira's avatar
nanahira committed
2762 2763
      _async.auto({
        match_permit: function(done) {
nanahira's avatar
fix  
nanahira committed
2764 2765 2766 2767
          if (client.closed) {
            done();
            return;
          }
nanahira's avatar
nanahira committed
2768 2769 2770
          if (!settings.modules.arena_mode.check_permit) {
            done(null, null);
            return;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2771
          }
nanahira's avatar
nanahira committed
2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785
          request({
            url: settings.modules.arena_mode.check_permit,
            json: true,
            qs: {
              username: client.name,
              password: info.pass,
              arena: settings.modules.arena_mode.mode
            }
          }, function(error, response, body) {
            if (client.closed) {
              done(null, null);
              return;
            }
            if (!error && body) {
nanahira's avatar
fix  
nanahira committed
2786
              done(null, body);
nanahira's avatar
nanahira committed
2787 2788
            } else {
              log.warn("Match permit request error", error);
nanahira's avatar
fix  
nanahira committed
2789
              done(null, null);
nanahira's avatar
nanahira committed
2790 2791 2792 2793
            }
          });
        },
        get_user: function(done) {
nanahira's avatar
nanahira committed
2794
          var decrypted_buffer, i, id, len3, n, ref3, secret;
nanahira's avatar
nanahira committed
2795
          if (client.closed) {
nanahira's avatar
fix  
nanahira committed
2796
            done();
nanahira's avatar
nanahira committed
2797
            return;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2798
          }
nanahira's avatar
nanahira committed
2799 2800
          if (id = users_cache[client.name]) {
            secret = id % 65535 + 1;
nanahira's avatar
nanahira committed
2801
            decrypted_buffer = Buffer.allocUnsafe(6);
nanahira's avatar
nanahira committed
2802 2803 2804
            ref3 = [0, 2, 4];
            for (n = 0, len3 = ref3.length; n < len3; n++) {
              i = ref3[n];
nanahira's avatar
nanahira committed
2805 2806 2807
              decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
            }
            if (check_buffer_indentity(decrypted_buffer)) {
nanahira's avatar
nanahira committed
2808 2809 2810 2811
              done(null, {
                original: decrypted_buffer,
                decrypted: decrypted_buffer
              });
nanahira's avatar
fix  
nanahira committed
2812
              return;
nanahira's avatar
nanahira committed
2813 2814
            }
          }
nanahira's avatar
nanahira committed
2815
          //TODO: query database directly, like preload.
nanahira's avatar
nanahira committed
2816 2817 2818 2819 2820 2821 2822 2823 2824 2825
          request({
            baseUrl: settings.modules.mycard.auth_base_url,
            url: '/users/' + encodeURIComponent(client.name) + '.json',
            qs: {
              api_key: settings.modules.mycard.auth_key,
              api_username: client.name,
              skip_track_visit: true
            },
            json: true
          }, function(error, response, body) {
nanahira's avatar
nanahira committed
2826
            var len4, o, ref4;
nanahira's avatar
nanahira committed
2827 2828 2829 2830
            if (!error && body && body.user) {
              users_cache[client.name] = body.user.id;
              secret = body.user.id % 65535 + 1;
              decrypted_buffer = Buffer.allocUnsafe(6);
nanahira's avatar
nanahira committed
2831 2832 2833
              ref4 = [0, 2, 4];
              for (o = 0, len4 = ref4.length; o < len4; o++) {
                i = ref4[o];
nanahira's avatar
nanahira committed
2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847
                decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
              }
              if (check_buffer_indentity(decrypted_buffer)) {
                buffer = decrypted_buffer;
              }
            } else {
              log.warn("READ USER FAIL", error, body);
              done("${create_room_failed}");
              return;
            }
            if (!check_buffer_indentity(buffer)) {
              done('${invalid_password_checksum}');
              return;
            }
nanahira's avatar
fix  
nanahira committed
2848
            done(null, {
nanahira's avatar
nanahira committed
2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861
              original: buffer,
              decrypted: decrypted_buffer
            });
          });
        }
      }, function(err, data) {
        if (client.closed) {
          return;
        }
        if (err) {
          ygopro.stoc_die(client, err);
          return;
        }
nanahira's avatar
fix  
nanahira committed
2862
        return create_room_with_action(data.get_user.original, data.get_user.decrypted, data.match_permit);
nanahira's avatar
nanahira committed
2863
      });
nanahira's avatar
nanahira committed
2864 2865
    } else if (settings.modules.challonge.enabled) {
      pre_room = ROOM_find_by_name(info.pass);
nanahira's avatar
nanahira committed
2866
      if (pre_room && pre_room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.cloud_replay.enable_halfway_watch && !pre_room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
2867
        room = pre_room;
nanahira's avatar
nanahira committed
2868
        client.setTimeout(300000); //连接后超时5分钟
nanahira's avatar
nanahira committed
2869 2870
        client.rid = _.indexOf(ROOM_all, room);
        client.is_post_watcher = true;
nanahira's avatar
nanahira committed
2871
        ygopro.stoc_send_chat_to_room(room, `${client.name} \${watch_join}`);
nanahira's avatar
nanahira committed
2872 2873
        room.watchers.push(client);
        ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2874 2875 2876
        ref3 = room.watcher_buffers;
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          buffer = ref3[n];
nanahira's avatar
nanahira committed
2877 2878 2879 2880
          client.write(buffer);
        }
      } else {
        ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2881
        client.setTimeout(300000); //连接后超时5分钟
nanahira's avatar
nanahira committed
2882
        recover_match = info.pass.match(/^(RC|RECOVER)(\d*)T(\d*)$/);
nanahira's avatar
nanahira committed
2883 2884
        _async.auto({
          participant_data: function(done) {
nanahira's avatar
nanahira committed
2885 2886 2887 2888
            challonge.participants._index({
              id: settings.modules.challonge.tournament_id,
              callback: done
            });
nanahira's avatar
nanahira committed
2889 2890
          },
          match_data: function(done) {
nanahira's avatar
nanahira committed
2891 2892
            challonge.matches._index({
              id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
2893 2894
              callback: done,
              no_cache: !!recover_match
nanahira's avatar
nanahira committed
2895 2896
            });
          }
nanahira's avatar
nanahira committed
2897
        }, function(err, datas) {
nanahira's avatar
nanahira committed
2898
          var create_room_name, found, k, len4, len5, match, o, p, player, ref4, ref5, ref6, ref7, user;
nanahira's avatar
nanahira committed
2899 2900 2901
          if (client.closed) {
            return;
          }
nanahira's avatar
nanahira committed
2902
          if (err || !datas.participant_data || !datas.match_data) {
nanahira's avatar
nanahira committed
2903 2904 2905 2906 2907
            log.warn("Failed loading Challonge user info", err);
            ygopro.stoc_die(client, '${challonge_match_load_failed}');
            return;
          }
          found = false;
nanahira's avatar
nanahira committed
2908 2909 2910
          ref4 = datas.participant_data;
          for (k in ref4) {
            user = ref4[k];
nanahira's avatar
nanahira committed
2911 2912 2913
            if (user.participant && user.participant.name && deck_name_match(user.participant.name, client.name)) {
              found = user.participant;
              break;
nanahira's avatar
nanahira committed
2914
            }
nanahira's avatar
nanahira committed
2915 2916 2917 2918 2919 2920 2921
          }
          if (!found) {
            ygopro.stoc_die(client, '${challonge_user_not_found}');
            return;
          }
          client.challonge_info = found;
          found = false;
nanahira's avatar
nanahira committed
2922 2923 2924
          ref5 = datas.match_data;
          for (k in ref5) {
            match = ref5[k];
nanahira's avatar
nanahira committed
2925 2926 2927
            if (match && match.match && !match.match.winnerId && match.match.state !== "complete" && match.match.player1Id && match.match.player2Id && (match.match.player1Id === client.challonge_info.id || match.match.player2Id === client.challonge_info.id)) {
              found = match.match;
              break;
nanahira's avatar
nanahira committed
2928
            }
nanahira's avatar
nanahira committed
2929 2930 2931 2932 2933
          }
          if (!found) {
            ygopro.stoc_die(client, '${challonge_match_not_found}');
            return;
          }
nanahira's avatar
nanahira committed
2934 2935 2936
          //if found.winnerId
          //  ygopro.stoc_die(client, '${challonge_match_already_finished}')
          //  return
nanahira's avatar
nanahira committed
2937 2938 2939 2940 2941
          create_room_name = 'M#' + found.id;
          if (recover_match) {
            create_room_name = recover_match[0] + ',' + create_room_name;
          }
          room = ROOM_find_or_create_by_name(create_room_name);
nanahira's avatar
nanahira committed
2942 2943
          if (room) {
            room.challonge_info = found;
nanahira's avatar
nanahira committed
2944
            // room.max_player = 2
nanahira's avatar
nanahira committed
2945 2946 2947 2948 2949 2950 2951 2952
            room.welcome = "${challonge_match_created}";
          }
          if (!room) {
            ygopro.stoc_die(client, "${server_full}");
          } else if (room.error) {
            ygopro.stoc_die(client, room.error);
          } else if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
            if (settings.modules.cloud_replay.enable_halfway_watch && !room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
2953
              //client.setTimeout(300000) #连接后超时5分钟
nanahira's avatar
nanahira committed
2954 2955
              client.rid = _.indexOf(ROOM_all, room);
              client.is_post_watcher = true;
nanahira's avatar
nanahira committed
2956
              ygopro.stoc_send_chat_to_room(room, `${client.name} \${watch_join}`);
nanahira's avatar
nanahira committed
2957 2958
              room.watchers.push(client);
              ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2959 2960 2961
              ref6 = room.watcher_buffers;
              for (o = 0, len4 = ref6.length; o < len4; o++) {
                buffer = ref6[o];
nanahira's avatar
nanahira committed
2962
                client.write(buffer);
nanahira's avatar
nanahira committed
2963
              }
nanahira's avatar
nanahira committed
2964 2965
            } else {
              ygopro.stoc_die(client, "${watch_denied}");
nanahira's avatar
nanahira committed
2966
            }
nanahira's avatar
nanahira committed
2967 2968 2969
          } else if (room.hostinfo.no_watch && room.players.length >= (room.hostinfo.mode === 2 ? 4 : 2)) {
            ygopro.stoc_die(client, "${watch_denied_room}");
          } else {
nanahira's avatar
nanahira committed
2970 2971 2972
            ref7 = room.get_playing_player();
            for (p = 0, len5 = ref7.length; p < len5; p++) {
              player = ref7[p];
nanahira's avatar
nanahira committed
2973 2974 2975 2976
              if (!(player && player !== client && player.challonge_info.id === client.challonge_info.id)) {
                continue;
              }
              ygopro.stoc_die(client, "${challonge_player_already_in}");
nanahira's avatar
nanahira committed
2977 2978
              return;
            }
nanahira's avatar
nanahira committed
2979 2980
            //client.room = room
            //client.setTimeout(300000) #连接后超时5分钟
nanahira's avatar
nanahira committed
2981 2982
            client.rid = _.indexOf(ROOM_all, room);
            room.connect(client);
nanahira's avatar
nanahira committed
2983 2984 2985
          }
        });
      }
mercury233's avatar
mercury233 committed
2986
    } else if (!client.name || client.name === "") {
mercury233's avatar
mercury233 committed
2987
      ygopro.stoc_die(client, "${bad_user_name}");
mercury233's avatar
mercury233 committed
2988 2989
    } else if (ROOM_connected_ip[client.ip] > 5) {
      log.warn("MULTI LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
2990
      ygopro.stoc_die(client, "${too_much_connection}" + client.ip);
nanahira's avatar
nanahira committed
2991
    } else if (_.indexOf(settings.ban.banned_user, client.name) > -1) { //账号被封
mercury233's avatar
mercury233 committed
2992
      settings.ban.banned_ip.push(client.ip);
mercury233's avatar
mercury233 committed
2993
      setting_save(settings);
mercury233's avatar
mercury233 committed
2994
      log.warn("BANNED USER LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
2995
      ygopro.stoc_die(client, "${banned_user_login}");
nanahira's avatar
nanahira committed
2996
    } else if (_.indexOf(settings.ban.banned_ip, client.ip) > -1) { //IP被封
mercury233's avatar
mercury233 committed
2997
      log.warn("BANNED IP LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
2998
      ygopro.stoc_die(client, "${banned_ip_login}");
2999
    } else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && _.any(badwords.level3, function(badword) {
mercury233's avatar
mercury233 committed
3000
      var regexp;
mercury233's avatar
fix  
mercury233 committed
3001
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
3002 3003
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
3004
      log.warn("BAD NAME LEVEL 3", client.name, client.ip);
mercury233's avatar
mercury233 committed
3005
      ygopro.stoc_die(client, "${bad_name_level3}");
3006
    } else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && _.any(badwords.level2, function(badword) {
mercury233's avatar
mercury233 committed
3007
      var regexp;
mercury233's avatar
fix  
mercury233 committed
3008
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
3009 3010
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
3011
      log.warn("BAD NAME LEVEL 2", client.name, client.ip);
mercury233's avatar
mercury233 committed
3012
      ygopro.stoc_die(client, "${bad_name_level2}");
3013
    } else if (!settings.modules.tournament_mode.enabled && !settings.modules.challonge.enabled && _.any(badwords.level1, function(badword) {
mercury233's avatar
mercury233 committed
3014
      var regexp;
mercury233's avatar
fix  
mercury233 committed
3015
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
3016 3017
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
3018
      log.warn("BAD NAME LEVEL 1", client.name, client.ip);
mercury233's avatar
mercury233 committed
3019
      ygopro.stoc_die(client, "${bad_name_level1}");
mercury233's avatar
mercury233 committed
3020
    } else if (info.pass.length && !ROOM_validate(info.pass)) {
mercury233's avatar
mercury233 committed
3021
      ygopro.stoc_die(client, "${invalid_password_room}");
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
3022
    } else {
nanahira's avatar
nanahira committed
3023 3024
      //if info.version >= 9020 and settings.version == 4927 #强行兼容23333版
      //  info.version = settings.version
3025
      //  struct = ygopro.structs.get("CTOS_JoinGame")
nanahira's avatar
nanahira committed
3026 3027 3028 3029 3030 3031
      //  struct._setBuff(buffer)
      //  struct.set("version", info.version)
      //  buffer = struct.buffer
      //  #ygopro.stoc_send_chat(client, "看起来你是YGOMobile的用户,请记得更新先行卡补丁,否则会看到白卡", ygopro.constants.COLORS.GREEN)

      //log.info 'join_game',info.pass, client.name
mercury233's avatar
mercury233 committed
3032
      room = ROOM_find_or_create_by_name(info.pass, client.ip);
mercury233's avatar
mercury233 committed
3033
      if (!room) {
mercury233's avatar
mercury233 committed
3034
        ygopro.stoc_die(client, "${server_full}");
mercury233's avatar
mercury233 committed
3035
      } else if (room.error) {
mercury233's avatar
mercury233 committed
3036
        ygopro.stoc_die(client, room.error);
nanahira's avatar
nanahira committed
3037
      } else if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
3038
        if (settings.modules.cloud_replay.enable_halfway_watch && !room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
3039
          client.setTimeout(300000); //连接后超时5分钟
3040
          client.rid = _.indexOf(ROOM_all, room);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3041
          client.is_post_watcher = true;
nanahira's avatar
nanahira committed
3042
          ygopro.stoc_send_chat_to_room(room, `${client.name} \${watch_join}`);
3043
          room.watchers.push(client);
mercury233's avatar
mercury233 committed
3044
          ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
3045 3046 3047
          ref4 = room.watcher_buffers;
          for (o = 0, len4 = ref4.length; o < len4; o++) {
            buffer = ref4[o];
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3048 3049 3050
            client.write(buffer);
          }
        } else {
mercury233's avatar
mercury233 committed
3051
          ygopro.stoc_die(client, "${watch_denied}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3052
        }
nanahira's avatar
nanahira committed
3053
      } else if (room.hostinfo.no_watch && room.players.length >= (room.hostinfo.mode === 2 ? 4 : 2)) {
nanahira's avatar
nanahira committed
3054
        ygopro.stoc_die(client, "${watch_denied_room}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3055
      } else {
nanahira's avatar
nanahira committed
3056
        client.setTimeout(300000); //连接后超时5分钟
3057 3058
        client.rid = _.indexOf(ROOM_all, room);
        room.connect(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3059
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
3060 3061 3062
    }
  });

nanahira's avatar
nanahira committed
3063
  ygopro.stoc_follow('JOIN_GAME', false, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3064
    var len3, n, player, recorder, ref3, room, watcher;
nanahira's avatar
nanahira committed
3065
    //欢迎信息
3066
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
3067
    if (!(room && !client.reconnecting)) {
3068 3069
      return;
    }
3070 3071 3072
    if (!room.join_game_buffer) {
      room.join_game_buffer = buffer;
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3073
    if (settings.modules.welcome) {
mercury233's avatar
mercury233 committed
3074
      ygopro.stoc_send_chat(client, settings.modules.welcome, ygopro.constants.COLORS.GREEN);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3075
    }
3076 3077
    if (room.welcome) {
      ygopro.stoc_send_chat(client, room.welcome, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
add  
mercury233 committed
3078
    }
3079 3080 3081
    if (room.welcome2) {
      ygopro.stoc_send_chat(client, room.welcome2, ygopro.constants.COLORS.PINK);
    }
nanahira's avatar
nanahira committed
3082
    if (settings.modules.arena_mode.enabled && !client.is_local) { //and not client.score_shown
mercury233's avatar
mercury233 committed
3083 3084 3085 3086
      request({
        url: settings.modules.arena_mode.get_score + encodeURIComponent(client.name),
        json: true
      }, function(error, response, body) {
mercury233's avatar
merge  
mercury233 committed
3087
        var rank_txt;
mercury233's avatar
merge  
mercury233 committed
3088 3089 3090 3091
        if (error) {
          log.warn('LOAD SCORE ERROR', client.name, error);
        } else if (!body || _.isString(body)) {
          log.warn('LOAD SCORE FAIL', client.name, response.statusCode, response.statusMessage, body);
mercury233's avatar
mercury233 committed
3092
        } else {
nanahira's avatar
nanahira committed
3093
          //log.info 'LOAD SCORE', client.name, body
mercury233's avatar
mercury233 committed
3094
          rank_txt = body.arena_rank > 0 ? "${rank_arena}" + body.arena_rank : "${rank_blank}";
nanahira's avatar
nanahira committed
3095
          ygopro.stoc_send_chat(client, `${client.name}\${exp_value_part1}${body.exp}\${exp_value_part2}\${exp_value_part3}${Math.round(body.pt)}${rank_txt}\${exp_value_part4}`, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
3096 3097 3098
        }
      });
    }
nanahira's avatar
nanahira committed
3099
    //client.score_shown = true
3100 3101
    if (settings.modules.random_duel.record_match_scores && room.random_type === 'M') {
      ygopro.stoc_send_chat_to_room(room, ROOM_player_get_score(client), ygopro.constants.COLORS.GREEN);
nanahira's avatar
nanahira committed
3102 3103 3104
      ref3 = room.players;
      for (n = 0, len3 = ref3.length; n < len3; n++) {
        player = ref3[n];
3105 3106 3107 3108 3109
        if (player.pos !== 7 && player !== client) {
          ygopro.stoc_send_chat(client, ROOM_player_get_score(player), ygopro.constants.COLORS.GREEN);
        }
      }
    }
3110 3111
    if (!room.recorder) {
      room.recorder = recorder = net.connect(room.port, function() {
mercury233's avatar
mercury233 committed
3112 3113 3114 3115 3116
        ygopro.ctos_send(recorder, 'PLAYER_INFO', {
          name: "Marshtomp"
        });
        ygopro.ctos_send(recorder, 'JOIN_GAME', {
          version: settings.version,
mercury233's avatar
mercury233 committed
3117
          pass: "Marshtomp"
mercury233's avatar
mercury233 committed
3118
        });
mercury233's avatar
mercury233 committed
3119
        ygopro.ctos_send(recorder, 'HS_TOOBSERVER');
mercury233's avatar
mercury233 committed
3120 3121
      });
      recorder.on('data', function(data) {
3122
        room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
3123
        if (!(room && settings.modules.cloud_replay.enabled)) {
mercury233's avatar
mercury233 committed
3124 3125
          return;
        }
mercury233's avatar
mercury233 committed
3126
        room.recorder_buffers.push(data);
mercury233's avatar
mercury233 committed
3127 3128 3129
      });
      recorder.on('error', function(error) {});
    }
nanahira's avatar
nanahira committed
3130
    if (settings.modules.cloud_replay.enable_halfway_watch && !room.watcher && !room.hostinfo.no_watch) {
3131
      room.watcher = watcher = settings.modules.test_mode.watch_public_hand ? room.recorder : net.connect(room.port, function() {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3132 3133 3134 3135 3136
        ygopro.ctos_send(watcher, 'PLAYER_INFO', {
          name: "the Big Brother"
        });
        ygopro.ctos_send(watcher, 'JOIN_GAME', {
          version: settings.version,
mercury233's avatar
mercury233 committed
3137
          pass: "the Big Brother"
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3138
        });
mercury233's avatar
mercury233 committed
3139
        ygopro.ctos_send(watcher, 'HS_TOOBSERVER');
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3140
      });
mercury233's avatar
fix  
mercury233 committed
3141
      watcher.on('data', function(data) {
nanahira's avatar
nanahira committed
3142
        var len4, o, ref4, w;
3143 3144
        room = ROOM_all[client.rid];
        if (!room) {
3145 3146
          return;
        }
3147
        room.watcher_buffers.push(data);
nanahira's avatar
nanahira committed
3148 3149 3150
        ref4 = room.watchers;
        for (o = 0, len4 = ref4.length; o < len4; o++) {
          w = ref4[o];
nanahira's avatar
nanahira committed
3151
          if (w) { //a WTF fix
mercury233's avatar
test3  
mercury233 committed
3152
            w.write(data);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3153
          }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3154 3155
        }
      });
mercury233's avatar
mercury233 committed
3156 3157 3158
      watcher.on('error', function(error) {
        log.error("watcher error", error);
      });
神楽坂玲奈's avatar
神楽坂玲奈 committed
3159
    }
神楽坂玲奈's avatar
tip  
神楽坂玲奈 committed
3160
  });
神楽坂玲奈's avatar
神楽坂玲奈 committed
3161

nanahira's avatar
nanahira committed
3162
  // 登场台词
nanahira's avatar
nanahira committed
3163
  load_dialogues = global.load_dialogues = async function(callback) {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3164
    request({
mercury233's avatar
mercury233 committed
3165
      url: settings.modules.dialogues.get,
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3166 3167 3168
      json: true
    }, function(error, response, body) {
      if (_.isString(body)) {
mercury233's avatar
test3  
mercury233 committed
3169
        log.warn("dialogues bad json", body);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3170
      } else if (error || !body) {
mercury233's avatar
test3  
mercury233 committed
3171
        log.warn('dialogues error', error, response);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3172
      } else {
mercury233's avatar
mercury233 committed
3173 3174
        setting_change(dialogues, "dialogues", body);
        log.info("dialogues loaded", _.size(dialogues.dialogues));
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3175
      }
nanahira's avatar
nanahira committed
3176 3177 3178
      if (callback) {
        callback(error, body);
      }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3179
    });
mercury233's avatar
mercury233 committed
3180 3181
  };

3182
  if (settings.modules.dialogues.get) {
mercury233's avatar
mercury233 committed
3183
    load_dialogues();
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3184 3185
  }

nanahira's avatar
nanahira committed
3186
  ygopro.stoc_follow('GAME_MSG', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3187
    var card, chain, check, count, cpos, deck_found, found, hint_type, i, id, len3, len4, len5, len6, limbo_found, line, loc, max_loop, msg, n, o, oppo_pos, p, phase, player, playertype, pos, ppos, q, r, reason, ref3, ref4, ref5, ref6, ref7, ref8, room, trigger_location, val, win_pos;
3188
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
3189
    if (!(room && !client.reconnecting)) {
3190 3191
      return;
    }
神楽坂玲奈's avatar
神楽坂玲奈 committed
3192
    msg = buffer.readInt8(0);
nanahira's avatar
nanahira committed
3193 3194 3195 3196 3197
    //console.log client.pos, "MSG", ygopro.constants.MSG[msg]
    if (ygopro.constants.MSG[msg] === 'RETRY' && room.recovering) {
      room.finish_recover(true);
      return true;
    }
nanahira's avatar
nanahira committed
3198 3199 3200 3201 3202 3203 3204 3205 3206 3207
    if (settings.modules.retry_handle.enabled) {
      if (ygopro.constants.MSG[msg] === 'RETRY') {
        if (client.retry_count == null) {
          client.retry_count = 0;
        }
        client.retry_count++;
        log.warn("MSG_RETRY detected", client.name, client.ip, msg, client.retry_count);
        if (settings.modules.retry_handle.max_retry_count && client.retry_count >= settings.modules.retry_handle.max_retry_count) {
          ygopro.stoc_send_chat_to_room(room, client.name + "${retry_too_much_room_part1}" + settings.modules.retry_handle.max_retry_count + "${retry_too_much_room_part2}", ygopro.constants.COLORS.BABYBLUE);
          ygopro.stoc_send_chat(client, "${retry_too_much_part1}" + settings.modules.retry_handle.max_retry_count + "${retry_too_much_part2}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
3208
          CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
3209
          CLIENT_kick(client);
nanahira's avatar
nanahira committed
3210 3211 3212 3213 3214 3215 3216 3217
          return true;
        }
        if (client.last_game_msg) {
          if (settings.modules.retry_handle.max_retry_count) {
            ygopro.stoc_send_chat(client, "${retry_part1}" + client.retry_count + "${retry_part2}" + settings.modules.retry_handle.max_retry_count + "${retry_part3}", ygopro.constants.COLORS.RED);
          } else {
            ygopro.stoc_send_chat(client, "${retry_not_counted}", ygopro.constants.COLORS.BABYBLUE);
          }
nanahira's avatar
nanahira committed
3218 3219 3220
          if (client.last_hint_msg) {
            ygopro.stoc_send(client, 'GAME_MSG', client.last_hint_msg);
          }
nanahira's avatar
nanahira committed
3221 3222 3223 3224 3225
          ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg);
          return true;
        }
      } else {
        client.last_game_msg = buffer;
nanahira's avatar
nanahira committed
3226
        client.last_game_msg_title = ygopro.constants.MSG[msg];
nanahira's avatar
nanahira committed
3227
      }
nanahira's avatar
nanahira committed
3228
    // log.info(client.name, client.last_game_msg_title)
nanahira's avatar
nanahira committed
3229 3230 3231
    } else if (ygopro.constants.MSG[msg] !== 'RETRY') {
      client.last_game_msg = buffer;
      client.last_game_msg_title = ygopro.constants.MSG[msg];
nanahira's avatar
nanahira committed
3232
    }
nanahira's avatar
nanahira committed
3233 3234
    // log.info(client.name, client.last_game_msg_title)
    if ((msg >= 10 && msg < 30) || msg === 132 || (msg >= 140 && msg <= 144)) { //SELECT和ANNOUNCE开头的消息
nanahira's avatar
nanahira committed
3235 3236 3237 3238 3239 3240 3241 3242 3243 3244
      if (room.recovering) {
        ygopro.ctos_send(server, 'RESPONSE', room.recover_replay.responses.splice(0, 1)[0]);
        if (!room.recover_replay.responses.length) {
          room.finish_recover();
        }
        return true;
      } else {
        room.waiting_for_player = client;
        room.last_active_time = moment();
      }
3245
    }
nanahira's avatar
nanahira committed
3246 3247 3248
    //log.info("#{ygopro.constants.MSG[msg]}等待#{room.waiting_for_player.name}")

    //log.info 'MSG', ygopro.constants.MSG[msg]
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3249 3250 3251
    if (ygopro.constants.MSG[msg] === 'START') {
      playertype = buffer.readUInt8(1);
      client.is_first = !(playertype & 0xf);
3252
      client.lp = room.hostinfo.start_lp;
nanahira's avatar
nanahira committed
3253 3254 3255
      if (room.hostinfo.mode !== 2) {
        client.card_count = 0;
      }
nanahira's avatar
nanahira committed
3256
      room.duel_stage = ygopro.constants.DUEL_STAGE.DUELING;
nanahira's avatar
nanahira committed
3257
      if (client.pos === 0) {
3258
        room.turn = 0;
nanahira's avatar
nanahira committed
3259
        room.duel_count++;
nanahira's avatar
nanahira committed
3260 3261 3262 3263 3264 3265 3266
        if (room.death && room.duel_count > 1) {
          if (room.death === -1) {
            ygopro.stoc_send_chat_to_room(room, "${death_start_final}", ygopro.constants.COLORS.BABYBLUE);
          } else {
            ygopro.stoc_send_chat_to_room(room, "${death_start_extra}", ygopro.constants.COLORS.BABYBLUE);
          }
        }
nanahira's avatar
nanahira committed
3267 3268 3269
        if (room.recovering) {
          ygopro.stoc_send_chat_to_room(room, "${recover_start_hint}", ygopro.constants.COLORS.BABYBLUE);
        }
nanahira's avatar
fix  
nanahira committed
3270
      }
nanahira's avatar
nanahira committed
3271
      if (client.is_first && (room.hostinfo.mode !== 2 || client.pos === 0 || client.pos === 2)) {
nanahira's avatar
nanahira committed
3272
        room.first_list.push(client.name_vpass);
nanahira's avatar
nanahira committed
3273
      }
nanahira's avatar
nanahira committed
3274 3275 3276 3277
      if (settings.modules.retry_handle.enabled) {
        client.retry_count = 0;
        client.last_game_msg = null;
      }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3278
    }
nanahira's avatar
nanahira committed
3279
    //ygopro.stoc_send_chat_to_room(room, "LP跟踪调试信息: #{client.name} 初始LP #{client.lp}")
nanahira's avatar
nanahira committed
3280 3281
    if (ygopro.constants.MSG[msg] === 'HINT') {
      hint_type = buffer.readUInt8(1);
nanahira's avatar
typo  
nanahira committed
3282
      if (hint_type === 3) {
nanahira's avatar
nanahira committed
3283 3284 3285
        client.last_hint_msg = buffer;
      }
    }
3286
    if (ygopro.constants.MSG[msg] === 'NEW_TURN') {
nanahira's avatar
nanahira committed
3287
      if (client.pos === 0) {
nanahira's avatar
nanahira committed
3288
        room.turn++;
nanahira's avatar
nanahira committed
3289 3290 3291
        if (room.recovering && room.recover_from_turn <= room.turn) {
          room.finish_recover();
        }
nanahira's avatar
nanahira committed
3292
        if (room.death && room.death !== -2) {
nanahira's avatar
nanahira committed
3293
          if (room.turn >= room.death) {
nanahira's avatar
nanahira committed
3294 3295 3296
            oppo_pos = room.hostinfo.mode === 2 ? 2 : 1;
            if (room.dueling_players[0].lp !== room.dueling_players[oppo_pos].lp && room.turn > 1) {
              win_pos = room.dueling_players[0].lp > room.dueling_players[oppo_pos].lp ? 0 : oppo_pos;
nanahira's avatar
nanahira committed
3297
              ygopro.stoc_send_chat_to_room(room, "${death_finish_part1}" + room.dueling_players[win_pos].name + "${death_finish_part2}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
3298
              if (room.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
3299
                room.finished_by_death = true;
nanahira's avatar
nanahira committed
3300 3301
                ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos], 'DUEL_END');
                ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos + 1], 'DUEL_END');
3302
                room.scores[room.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
nanahira's avatar
nanahira committed
3303 3304
                CLIENT_kick(room.dueling_players[oppo_pos - win_pos]);
                CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]);
nanahira's avatar
nanahira committed
3305 3306 3307
              } else {
                ygopro.ctos_send(room.dueling_players[oppo_pos - win_pos].server, 'SURRENDER');
              }
nanahira's avatar
nanahira committed
3308
            } else {
nanahira's avatar
nanahira committed
3309
              room.death = -1;
nanahira's avatar
nanahira committed
3310 3311 3312 3313 3314 3315
              ygopro.stoc_send_chat_to_room(room, "${death_remain_final}", ygopro.constants.COLORS.BABYBLUE);
            }
          } else {
            ygopro.stoc_send_chat_to_room(room, "${death_remain_part1}" + (room.death - room.turn) + "${death_remain_part2}", ygopro.constants.COLORS.BABYBLUE);
          }
        }
3316 3317 3318 3319 3320
      }
      if (client.surrend_confirm) {
        client.surrend_confirm = false;
        ygopro.stoc_send_chat(client, "${surrender_canceled}", ygopro.constants.COLORS.BABYBLUE);
      }
mercury233's avatar
mercury233 committed
3321
    }
nanahira's avatar
nanahira committed
3322 3323 3324
    if (ygopro.constants.MSG[msg] === 'NEW_PHASE') {
      phase = buffer.readInt16LE(1);
      oppo_pos = room.hostinfo.mode === 2 ? 2 : 1;
nanahira's avatar
fix  
nanahira committed
3325 3326 3327 3328 3329
      if (client.pos === 0 && room.death === -2 && !(phase === 0x1 && room.turn < 2)) {
        if (room.dueling_players[0].lp !== room.dueling_players[oppo_pos].lp) {
          win_pos = room.dueling_players[0].lp > room.dueling_players[oppo_pos].lp ? 0 : oppo_pos;
          ygopro.stoc_send_chat_to_room(room, "${death_finish_part1}" + room.dueling_players[win_pos].name + "${death_finish_part2}", ygopro.constants.COLORS.BABYBLUE);
          if (room.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
3330
            room.finished_by_death = true;
nanahira's avatar
fix  
nanahira committed
3331 3332
            ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos], 'DUEL_END');
            ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos + 1], 'DUEL_END');
3333
            room.scores[room.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
nanahira's avatar
nanahira committed
3334 3335
            CLIENT_kick(room.dueling_players[oppo_pos - win_pos]);
            CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]);
nanahira's avatar
fix  
nanahira committed
3336 3337 3338
          } else {
            ygopro.ctos_send(room.dueling_players[oppo_pos - win_pos].server, 'SURRENDER');
          }
nanahira's avatar
nanahira committed
3339
        } else {
nanahira's avatar
fix  
nanahira committed
3340 3341
          room.death = -1;
          ygopro.stoc_send_chat_to_room(room, "${death_remain_final}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
3342 3343 3344
        }
      }
    }
nanahira's avatar
nanahira committed
3345
    if (ygopro.constants.MSG[msg] === 'WIN' && client.pos === 0) {
nanahira's avatar
nanahira committed
3346 3347 3348 3349
      if (room.recovering) {
        room.finish_recover(true);
        return true;
      }
mercury233's avatar
mercury233 committed
3350
      pos = buffer.readUInt8(1);
nanahira's avatar
nanahira committed
3351
      if (!(client.is_first || pos === 2 || room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING)) {
mercury233's avatar
mercury233 committed
3352 3353
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3354 3355 3356
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
mercury233's avatar
mercury233 committed
3357
      reason = buffer.readUInt8(2);
nanahira's avatar
nanahira committed
3358 3359
      //log.info {winner: pos, reason: reason}
      //room.duels.push {winner: pos, reason: reason}
mercury233's avatar
mercury233 committed
3360
      room.winner = pos;
nanahira's avatar
nanahira committed
3361
      room.turn = 0;
nanahira's avatar
nanahira committed
3362
      room.duel_stage = ygopro.constants.DUEL_STAGE.END;
nanahira's avatar
nanahira committed
3363
      if (settings.modules.heartbeat_detection.enabled) {
nanahira's avatar
nanahira committed
3364 3365 3366
        ref3 = room.players;
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          player = ref3[n];
3367
          player.heartbeat_protected = false;
nanahira's avatar
nanahira committed
3368
        }
nanahira's avatar
nanahira committed
3369 3370
        delete room.long_resolve_card;
        delete room.long_resolve_chain;
nanahira's avatar
nanahira committed
3371
      }
mercury233's avatar
fix  
mercury233 committed
3372
      if (room && !room.finished && room.dueling_players[pos]) {
3373
        room.winner_name = room.dueling_players[pos].name_vpass;
nanahira's avatar
nanahira committed
3374
        //log.info room.dueling_players, pos
mercury233's avatar
mercury233 committed
3375
        room.scores[room.winner_name] = room.scores[room.winner_name] + 1;
nanahira's avatar
nanahira committed
3376 3377 3378 3379
        if (room.match_kill) {
          room.match_kill = false;
          room.scores[room.winner_name] = 99;
        }
mercury233's avatar
mercury233 committed
3380
      }
nanahira's avatar
fix  
nanahira committed
3381
      if (room.death) {
nanahira's avatar
nanahira committed
3382
        if (settings.modules.http.quick_death_rule === 1 || settings.modules.http.quick_death_rule === 3) {
nanahira's avatar
fix  
nanahira committed
3383 3384 3385 3386 3387
          room.death = -1;
        } else {
          room.death = 5;
        }
      }
mercury233's avatar
mercury233 committed
3388
    }
nanahira's avatar
nanahira committed
3389 3390 3391
    if (ygopro.constants.MSG[msg] === 'MATCH_KILL' && client.pos === 0) {
      room.match_kill = true;
    }
nanahira's avatar
nanahira committed
3392
    //lp跟踪
nanahira's avatar
nanahira committed
3393
    if (ygopro.constants.MSG[msg] === 'DAMAGE' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3394 3395 3396 3397
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3398 3399 3400
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3401
      val = buffer.readInt32LE(2);
3402
      room.dueling_players[pos].lp -= val;
nanahira's avatar
fix  
nanahira committed
3403 3404 3405
      if (room.dueling_players[pos].lp < 0) {
        room.dueling_players[pos].lp = 0;
      }
nanahira's avatar
nanahira committed
3406
      if ((0 < (ref4 = room.dueling_players[pos].lp) && ref4 <= 100)) {
mercury233's avatar
mercury233 committed
3407
        ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3408 3409
      }
    }
nanahira's avatar
nanahira committed
3410
    if (ygopro.constants.MSG[msg] === 'RECOVER' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3411 3412 3413 3414
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3415 3416 3417
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3418
      val = buffer.readInt32LE(2);
3419
      room.dueling_players[pos].lp += val;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3420
    }
nanahira's avatar
nanahira committed
3421
    if (ygopro.constants.MSG[msg] === 'LPUPDATE' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3422 3423 3424 3425
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3426 3427 3428
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3429
      val = buffer.readInt32LE(2);
3430
      room.dueling_players[pos].lp = val;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3431
    }
nanahira's avatar
nanahira committed
3432
    if (ygopro.constants.MSG[msg] === 'PAY_LPCOST' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3433 3434 3435 3436
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3437 3438 3439
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3440
      val = buffer.readInt32LE(2);
3441
      room.dueling_players[pos].lp -= val;
nanahira's avatar
fix  
nanahira committed
3442 3443 3444
      if (room.dueling_players[pos].lp < 0) {
        room.dueling_players[pos].lp = 0;
      }
nanahira's avatar
nanahira committed
3445
      if ((0 < (ref5 = room.dueling_players[pos].lp) && ref5 <= 100)) {
mercury233's avatar
mercury233 committed
3446
        ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3447 3448
      }
    }
nanahira's avatar
nanahira committed
3449 3450
    //track card count
    //todo: track card count in tag mode
nanahira's avatar
nanahira committed
3451
    if (ygopro.constants.MSG[msg] === 'MOVE' && room.hostinfo.mode !== 2) {
nanahira's avatar
nanahira committed
3452 3453 3454 3455 3456
      pos = buffer.readUInt8(5);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      loc = buffer.readUInt8(6);
nanahira's avatar
nanahira committed
3457 3458
      if ((loc & 0xe) && pos === 0) {
        client.card_count--;
nanahira's avatar
nanahira committed
3459 3460 3461 3462 3463 3464
      }
      pos = buffer.readUInt8(9);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      loc = buffer.readUInt8(10);
nanahira's avatar
nanahira committed
3465 3466
      if ((loc & 0xe) && pos === 0) {
        client.card_count++;
nanahira's avatar
nanahira committed
3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478
      }
    }
    if (ygopro.constants.MSG[msg] === 'DRAW' && room.hostinfo.mode !== 2) {
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      if (pos === 0) {
        count = buffer.readInt8(2);
        client.card_count += count;
      }
    }
nanahira's avatar
nanahira committed
3479
    // check panel confirming cards in heartbeat
nanahira's avatar
nanahira committed
3480 3481 3482 3483 3484
    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;
nanahira's avatar
nanahira committed
3485
      limbo_found = 0; // support custom cards which may be in location 0 in KoishiPro or EdoPro
nanahira's avatar
nanahira committed
3486
      for (i = o = 3, ref6 = max_loop; o <= ref6; i = o += 7) {
nanahira's avatar
nanahira committed
3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498
        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) {
nanahira's avatar
nanahira committed
3499
        //console.log("Confirming cards:" + client.name)
3500
        client.heartbeat_protected = true;
nanahira's avatar
nanahira committed
3501 3502
      }
    }
nanahira's avatar
nanahira committed
3503
    // chain detection
nanahira's avatar
nanahira committed
3504 3505 3506 3507
    if (settings.modules.heartbeat_detection.enabled && client.pos === 0) {
      if (ygopro.constants.MSG[msg] === 'CHAINING') {
        card = buffer.readUInt32LE(1);
        found = false;
nanahira's avatar
nanahira committed
3508 3509
        for (p = 0, len4 = long_resolve_cards.length; p < len4; p++) {
          id = long_resolve_cards[p];
nanahira's avatar
nanahira committed
3510 3511 3512 3513 3514 3515 3516 3517 3518
          if (!(id === card)) {
            continue;
          }
          found = true;
          break;
        }
        if (found) {
          room.long_resolve_card = card;
        } else {
nanahira's avatar
nanahira committed
3519
          // console.log(0,card)
nanahira's avatar
nanahira committed
3520 3521 3522 3523 3524 3525 3526 3527
          delete room.long_resolve_card;
        }
      } else if (ygopro.constants.MSG[msg] === 'CHAINED' && room.long_resolve_card) {
        chain = buffer.readInt8(1);
        if (!room.long_resolve_chain) {
          room.long_resolve_chain = [];
        }
        room.long_resolve_chain[chain] = true;
nanahira's avatar
nanahira committed
3528
        // console.log(1,chain)
nanahira's avatar
nanahira committed
3529 3530 3531
        delete room.long_resolve_card;
      } else if (ygopro.constants.MSG[msg] === 'CHAIN_SOLVING' && room.long_resolve_chain) {
        chain = buffer.readInt8(1);
nanahira's avatar
nanahira committed
3532
        // console.log(2,chain)
nanahira's avatar
nanahira committed
3533
        if (room.long_resolve_chain[chain]) {
nanahira's avatar
nanahira committed
3534 3535 3536
          ref7 = room.get_playing_player();
          for (q = 0, len5 = ref7.length; q < len5; q++) {
            player = ref7[q];
nanahira's avatar
nanahira committed
3537 3538 3539 3540 3541
            player.heartbeat_protected = true;
          }
        }
      } else if ((ygopro.constants.MSG[msg] === 'CHAIN_NEGATED' || ygopro.constants.MSG[msg] === 'CHAIN_DISABLED') && room.long_resolve_chain) {
        chain = buffer.readInt8(1);
nanahira's avatar
nanahira committed
3542
        // console.log(3,chain)
nanahira's avatar
nanahira committed
3543 3544
        delete room.long_resolve_chain[chain];
      } else if (ygopro.constants.MSG[msg] === 'CHAIN_END') {
nanahira's avatar
nanahira committed
3545
        // console.log(4,chain)
nanahira's avatar
nanahira committed
3546 3547 3548 3549
        delete room.long_resolve_card;
        delete room.long_resolve_chain;
      }
    }
nanahira's avatar
nanahira committed
3550
    //登场台词
nanahira's avatar
nanahira committed
3551
    if (settings.modules.dialogues.enabled && !room.recovering) {
nanahira's avatar
nanahira committed
3552
      if (ygopro.constants.MSG[msg] === 'SUMMONING' || ygopro.constants.MSG[msg] === 'SPSUMMONING' || ygopro.constants.MSG[msg] === 'CHAINING') {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3553
        card = buffer.readUInt32LE(1);
nanahira's avatar
fix  
nanahira committed
3554
        trigger_location = buffer.readUInt8(6);
nanahira's avatar
nanahira committed
3555
        if (dialogues.dialogues[card] && (ygopro.constants.MSG[msg] !== 'CHAINING' || (trigger_location & 0x8) && client.ready_trap)) {
nanahira's avatar
nanahira committed
3556 3557 3558
          ref8 = _.lines(dialogues.dialogues[card][Math.floor(Math.random() * dialogues.dialogues[card].length)]);
          for (r = 0, len6 = ref8.length; r < len6; r++) {
            line = ref8[r];
mercury233's avatar
mercury233 committed
3559
            ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3560
          }
神楽坂玲奈's avatar
神楽坂玲奈 committed
3561
        }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
3562
      }
nanahira's avatar
nanahira committed
3563 3564 3565 3566 3567 3568 3569 3570
      if (ygopro.constants.MSG[msg] === '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') {
        client.ready_trap = false;
      }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
3571
    }
nanahira's avatar
nanahira committed
3572 3573 3574 3575 3576 3577
    if (room.recovering && client.pos < 4) {
      if (ygopro.constants.MSG[msg] !== 'WAITING') {
        room.recover_buffers[client.pos].push(buffer);
      }
      return true;
    }
nanahira's avatar
nanahira committed
3578
    return false;
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
3579 3580
  });

nanahira's avatar
nanahira committed
3581
  //房间管理
nanahira's avatar
nanahira committed
3582
  ygopro.ctos_follow('HS_TOOBSERVER', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3583
    var len3, n, player, ref3, room;
3584 3585 3586 3587
    room = ROOM_all[client.rid];
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
3588
    if (room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
3589 3590 3591
      ygopro.stoc_send_chat(client, "${watch_denied_room}", ygopro.constants.COLORS.RED);
      return true;
    }
nanahira's avatar
nanahira committed
3592
    if ((!room.arena && !settings.modules.challonge.enabled) || client.is_local) {
3593 3594
      return false;
    }
nanahira's avatar
nanahira committed
3595 3596 3597
    ref3 = room.players;
    for (n = 0, len3 = ref3.length; n < len3; n++) {
      player = ref3[n];
3598 3599 3600 3601 3602 3603 3604
      if (player === client) {
        ygopro.stoc_send_chat(client, "${cannot_to_observer}", ygopro.constants.COLORS.BABYBLUE);
        return true;
      }
    }
    return false;
  });
nanahira's avatar
js  
nanahira committed
3605

nanahira's avatar
nanahira committed
3606
  ygopro.ctos_follow('HS_KICK', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3607
    var len3, n, player, ref3, room;
3608 3609
    room = ROOM_all[client.rid];
    if (!room) {
3610 3611
      return;
    }
nanahira's avatar
nanahira committed
3612 3613 3614
    ref3 = room.players;
    for (n = 0, len3 = ref3.length; n < len3; n++) {
      player = ref3[n];
mercury233's avatar
mercury233 committed
3615
      if (player && player.pos === info.pos && player !== client) {
nanahira's avatar
nanahira committed
3616
        if (room.arena === "athletic" || settings.modules.challonge.enabled) {
nanahira's avatar
nanahira committed
3617
          ygopro.stoc_send_chat_to_room(room, `${client.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
3618
          CLIENT_kick(client);
3619 3620
          return true;
        }
mercury233's avatar
mercury233 committed
3621
        client.kick_count = client.kick_count ? client.kick_count + 1 : 1;
mercury233's avatar
fix  
mercury233 committed
3622
        if (client.kick_count >= 5 && room.random_type) {
nanahira's avatar
nanahira committed
3623
          ygopro.stoc_send_chat_to_room(room, `${client.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3624
          ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
nanahira's avatar
nanahira committed
3625
          CLIENT_kick(client);
mercury233's avatar
mercury233 committed
3626 3627
          return true;
        }
nanahira's avatar
nanahira committed
3628
        ygopro.stoc_send_chat_to_room(room, `${player.name} \${kicked_by_player}`, ygopro.constants.COLORS.RED);
3629 3630 3631 3632 3633
      }
    }
    return false;
  });

nanahira's avatar
nanahira committed
3634
  ygopro.stoc_follow('TYPE_CHANGE', true, async function(buffer, info, client, server, datas) {
神楽坂玲奈's avatar
神楽坂玲奈 committed
3635 3636 3637
    var is_host, selftype;
    selftype = info.type & 0xf;
    is_host = ((info.type >> 4) & 0xf) !== 0;
nanahira's avatar
nanahira committed
3638 3639 3640
    // if room and room.hostinfo.no_watch and selftype == 7
    //   ygopro.stoc_die(client, "${watch_denied_room}")
    //   return true
神楽坂玲奈's avatar
神楽坂玲奈 committed
3641
    client.is_host = is_host;
mercury233's avatar
test3  
mercury233 committed
3642
    client.pos = selftype;
nanahira's avatar
nanahira committed
3643
    //console.log "TYPE_CHANGE to #{client.name}:", info, selftype, is_host
nanahira's avatar
nanahira committed
3644
    return false;
神楽坂玲奈's avatar
神楽坂玲奈 committed
3645 3646
  });

nanahira's avatar
nanahira committed
3647
  ygopro.stoc_follow('HS_PLAYER_ENTER', true, async function(buffer, info, client, server, datas) {
3648 3649
    var pos, room, struct;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
3650
    if (!(room && settings.modules.hide_name && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN)) {
3651 3652 3653 3654
      return false;
    }
    pos = info.pos;
    if (pos < 4 && pos !== client.pos) {
3655
      struct = ygopro.structs.get("STOC_HS_PlayerEnter");
3656 3657 3658 3659 3660 3661 3662
      struct._setBuff(buffer);
      struct.set("name", "********");
      buffer = struct.buffer;
    }
    return false;
  });

nanahira's avatar
nanahira committed
3663
  ygopro.stoc_follow('HS_PLAYER_CHANGE', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3664
    var is_ready, len3, len4, n, o, p1, p2, player, pos, ref3, ref4, room;
3665
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
3666
    if (!(room && room.max_player && client.pos === 0)) {
3667 3668 3669 3670
      return;
    }
    pos = info.status >> 4;
    is_ready = (info.status & 0xf) === 9;
3671
    if (pos < room.max_player) {
3672 3673
      if (room.arena) {
        room.ready_player_count = 0;
nanahira's avatar
nanahira committed
3674 3675 3676
        ref3 = room.players;
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          player = ref3[n];
3677 3678 3679
          if (player.pos === pos) {
            player.is_ready = is_ready;
          }
3680
        }
3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702
        p1 = room.players[0];
        p2 = room.players[1];
        if (!p1 || !p2) {
          if (room.waiting_for_player_interval) {
            clearInterval(room.waiting_for_player_interval);
            room.waiting_for_player_interval = null;
          }
          return;
        }
        room.waiting_for_player2 = room.waiting_for_player;
        room.waiting_for_player = null;
        if (p1.is_ready && p2.is_ready) {
          room.waiting_for_player = p1.is_host ? p1 : p2;
        }
        if (!p1.is_ready && p2.is_ready) {
          room.waiting_for_player = p1;
        }
        if (!p2.is_ready && p1.is_ready) {
          room.waiting_for_player = p2;
        }
        if (room.waiting_for_player !== room.waiting_for_player2) {
          room.waiting_for_player2 = room.waiting_for_player;
nanahira's avatar
nanahira committed
3703
          room.waiting_for_player_time = settings.modules.arena_mode.ready_time;
3704 3705 3706 3707 3708 3709
          room.waiting_for_player_interval = setInterval((function() {
            wait_room_start_arena(ROOM_all[client.rid]);
          }), 1000);
        } else if (!room.waiting_for_player && room.waiting_for_player_interval) {
          clearInterval(room.waiting_for_player_interval);
          room.waiting_for_player_interval = null;
nanahira's avatar
nanahira committed
3710
          room.waiting_for_player_time = settings.modules.arena_mode.ready_time;
3711 3712 3713
        }
      } else {
        room.ready_player_count_without_host = 0;
nanahira's avatar
nanahira committed
3714 3715 3716
        ref4 = room.players;
        for (o = 0, len4 = ref4.length; o < len4; o++) {
          player = ref4[o];
3717 3718 3719 3720 3721 3722 3723 3724
          if (player.pos === pos) {
            player.is_ready = is_ready;
          }
          if (!player.is_host) {
            room.ready_player_count_without_host += player.is_ready;
          }
        }
        if (room.ready_player_count_without_host >= room.max_player - 1) {
nanahira's avatar
nanahira committed
3725
          //log.info "all ready"
3726
          setTimeout((function() {
nanahira's avatar
nanahira committed
3727
            wait_room_start(ROOM_all[client.rid], settings.modules.random_duel.ready_time);
3728
          }), 1000);
3729 3730 3731 3732 3733
        }
      }
    }
  });

nanahira's avatar
nanahira committed
3734
  ygopro.ctos_follow('REQUEST_FIELD', true, async function(buffer, info, client, server, datas) {
3735 3736 3737
    return true;
  });

nanahira's avatar
nanahira committed
3738
  ygopro.stoc_follow('FIELD_FINISH', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3739 3740
    var room;
    room = ROOM_all[client.rid];
3741
    if (!(room && settings.modules.reconnect.enabled)) {
nanahira's avatar
nanahira committed
3742 3743
      return true;
    }
3744
    client.reconnecting = false;
nanahira's avatar
nanahira committed
3745
    if (client.time_confirm_required) { // client did not send TIME_CONFIRM
3746
      client.waiting_for_last = true;
nanahira's avatar
nanahira committed
3747
    } else if (client.last_game_msg && client.last_game_msg_title !== 'WAITING') { // client sent TIME_CONFIRM
3748 3749 3750 3751
      if (client.last_hint_msg) {
        ygopro.stoc_send(client, 'GAME_MSG', client.last_hint_msg);
      }
      ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg);
nanahira's avatar
nanahira committed
3752 3753 3754 3755
    }
    return true;
  });

nanahira's avatar
nanahira committed
3756 3757
  ygopro.stoc_follow('DUEL_END', false, async function(buffer, info, client, server, datas) {
    var len3, len4, n, o, player, ref3, ref4, room;
nanahira's avatar
move  
nanahira committed
3758 3759 3760 3761
    room = ROOM_all[client.rid];
    if (!(room && settings.modules.replay_delay && room.hostinfo.mode === 1)) {
      return;
    }
3762
    SOCKET_flush_data(client, datas);
nanahira's avatar
move  
nanahira committed
3763
    CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
3764
    if (!room.replays_sent_to_watchers) {
nanahira's avatar
move  
nanahira committed
3765
      room.replays_sent_to_watchers = true;
nanahira's avatar
nanahira committed
3766 3767 3768
      ref3 = room.players;
      for (n = 0, len3 = ref3.length; n < len3; n++) {
        player = ref3[n];
nanahira's avatar
js  
nanahira committed
3769 3770 3771 3772
        if (player && player.pos > 3) {
          CLIENT_send_replays(player, room);
        }
      }
nanahira's avatar
nanahira committed
3773 3774 3775
      ref4 = room.watchers;
      for (o = 0, len4 = ref4.length; o < len4; o++) {
        player = ref4[o];
nanahira's avatar
move  
nanahira committed
3776
        if (player) {
nanahira's avatar
nanahira committed
3777
          CLIENT_send_replays(player, room);
nanahira's avatar
move  
nanahira committed
3778 3779 3780 3781 3782
        }
      }
    }
  });

nanahira's avatar
nanahira committed
3783
  wait_room_start = async function(room, time) {
nanahira's avatar
nanahira committed
3784
    var len3, n, player, ref3;
nanahira's avatar
nanahira committed
3785
    if (room && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.ready_player_count_without_host >= room.max_player - 1) {
3786 3787 3788
      time -= 1;
      if (time) {
        if (!(time % 5)) {
nanahira's avatar
nanahira committed
3789
          ygopro.stoc_send_chat_to_room(room, `${time <= 9 ? ' ' : ''}${time}\${kick_count_down}`, time <= 9 ? ygopro.constants.COLORS.RED : ygopro.constants.COLORS.LIGHTBLUE);
3790 3791 3792 3793 3794
        }
        setTimeout((function() {
          wait_room_start(room, time);
        }), 1000);
      } else {
nanahira's avatar
nanahira committed
3795 3796 3797
        ref3 = room.players;
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          player = ref3[n];
mercury233's avatar
fix  
mercury233 committed
3798
          if (player && player.is_host) {
mercury233's avatar
mercury233 committed
3799
            ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
nanahira's avatar
nanahira committed
3800
            ygopro.stoc_send_chat_to_room(room, `${player.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
3801
            CLIENT_kick(player);
3802 3803 3804 3805 3806 3807
          }
        }
      }
    }
  };

nanahira's avatar
nanahira committed
3808
  wait_room_start_arena = async function(room) {
nanahira's avatar
nanahira committed
3809
    var display_name, len3, n, player, ref3;
nanahira's avatar
nanahira committed
3810
    if (room && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.waiting_for_player) {
3811 3812 3813
      room.waiting_for_player_time = room.waiting_for_player_time - 1;
      if (room.waiting_for_player_time > 0) {
        if (!(room.waiting_for_player_time % 5)) {
nanahira's avatar
nanahira committed
3814 3815 3816
          ref3 = room.players;
          for (n = 0, len3 = ref3.length; n < len3; n++) {
            player = ref3[n];
nanahira's avatar
fix  
nanahira committed
3817 3818 3819 3820
            if (!(player)) {
              continue;
            }
            display_name = (settings.modules.hide_name && player !== room.waiting_for_player ? "********" : room.waiting_for_player.name);
nanahira's avatar
nanahira committed
3821
            ygopro.stoc_send_chat(player, `${room.waiting_for_player_time <= 9 ? ' ' : ''}${room.waiting_for_player_time}\${kick_count_down_arena_part1} ${display_name} \${kick_count_down_arena_part2}`, room.waiting_for_player_time <= 9 ? ygopro.constants.COLORS.RED : ygopro.constants.COLORS.LIGHTBLUE);
nanahira's avatar
fix  
nanahira committed
3822
          }
3823 3824
        }
      } else {
nanahira's avatar
nanahira committed
3825
        ygopro.stoc_send_chat_to_room(room, `${room.waiting_for_player.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
3826
        CLIENT_kick(room.waiting_for_player);
3827 3828 3829 3830 3831 3832 3833 3834
        if (room.waiting_for_player_interval) {
          clearInterval(room.waiting_for_player_interval);
          room.waiting_for_player_interval = null;
        }
      }
    }
  };

nanahira's avatar
nanahira committed
3835
  //tip
nanahira's avatar
nanahira committed
3836
  ygopro.stoc_send_random_tip = async function(client) {
mercury233's avatar
mercury233 committed
3837 3838
    if (settings.modules.tips.enabled && tips.tips.length) {
      ygopro.stoc_send_chat(client, "Tip: " + tips.tips[Math.floor(Math.random() * tips.tips.length)]);
神楽坂玲奈's avatar
神楽坂玲奈 committed
3839
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3840 3841
  };

nanahira's avatar
nanahira committed
3842
  ygopro.stoc_send_random_tip_to_room = async function(room) {
mercury233's avatar
mercury233 committed
3843 3844
    if (settings.modules.tips.enabled && tips.tips.length) {
      ygopro.stoc_send_chat_to_room(room, "Tip: " + tips.tips[Math.floor(Math.random() * tips.tips.length)]);
3845 3846 3847
    }
  };

nanahira's avatar
nanahira committed
3848
  load_tips = global.load_tips = async function(callback) {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3849
    request({
mercury233's avatar
mercury233 committed
3850
      url: settings.modules.tips.get,
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3851 3852
      json: true
    }, function(error, response, body) {
mercury233's avatar
mercury233 committed
3853 3854 3855 3856 3857
      if (_.isString(body)) {
        log.warn("tips bad json", body);
      } else if (error || !body) {
        log.warn('tips error', error, response);
      } else {
mercury233's avatar
mercury233 committed
3858 3859
        setting_change(tips, "tips", body);
        log.info("tips loaded", tips.tips.length);
mercury233's avatar
mercury233 committed
3860
      }
nanahira's avatar
nanahira committed
3861 3862 3863
      if (callback) {
        callback(error, body);
      }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3864
    });
mercury233's avatar
mercury233 committed
3865 3866
  };

3867
  if (settings.modules.tips.get) {
mercury233's avatar
mercury233 committed
3868 3869
    load_tips();
    setInterval(function() {
nanahira's avatar
nanahira committed
3870 3871 3872
      var len3, n, room;
      for (n = 0, len3 = ROOM_all.length; n < len3; n++) {
        room = ROOM_all[n];
3873
        if (room && room.established) {
nanahira's avatar
nanahira committed
3874
          if (room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING || room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) {
3875 3876
            ygopro.stoc_send_random_tip_to_room(room);
          }
mercury233's avatar
mercury233 committed
3877 3878 3879
        }
      }
    }, 30000);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3880
  }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3881

nanahira's avatar
nanahira committed
3882
  ygopro.stoc_follow('DUEL_START', false, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3883
    var deck_arena, deck_name, deck_text, len3, len4, n, o, player, ref3, ref4, room;
3884
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
3885
    if (!(room && !client.reconnecting)) {
3886 3887
      return;
    }
nanahira's avatar
nanahira committed
3888
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) { //first start
nanahira's avatar
nanahira committed
3889
      room.duel_stage = ygopro.constants.DUEL_STAGE.FINGER;
mercury233's avatar
mercury233 committed
3890
      room.start_time = moment().format();
nanahira's avatar
nanahira committed
3891
      room.turn = 0;
mercury233's avatar
mercury233 committed
3892
      if (!room.windbot && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
3893
        roomlist.start(room);
神楽坂玲奈's avatar
神楽坂玲奈 committed
3894
      }
nanahira's avatar
nanahira committed
3895
      //room.duels = []
3896
      room.dueling_players = [];
nanahira's avatar
nanahira committed
3897 3898 3899
      ref3 = room.players;
      for (n = 0, len3 = ref3.length; n < len3; n++) {
        player = ref3[n];
mercury233's avatar
mercury233 committed
3900 3901
        if (!(player.pos !== 7)) {
          continue;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3902
        }
3903
        room.dueling_players[player.pos] = player;
3904
        room.scores[player.name_vpass] = 0;
3905
        room.player_datas.push({
3906
          key: CLIENT_get_authorize_key(player),
mercury233's avatar
mercury233 committed
3907 3908
          name: player.name
        });
mercury233's avatar
mercury233 committed
3909
        if (room.random_type === 'T') {
nanahira's avatar
nanahira committed
3910
          // 双打房不记录匹配过
mercury233's avatar
mercury233 committed
3911 3912
          ROOM_players_oppentlist[player.ip] = null;
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3913
      }
3914
      if (room.hostinfo.auto_death) {
nanahira's avatar
nanahira committed
3915
        ygopro.stoc_send_chat_to_room(room, `\${auto_death_part1}${room.hostinfo.auto_death}\${auto_death_part2}`, ygopro.constants.COLORS.BABYBLUE);
3916
      }
nanahira's avatar
nanahira committed
3917
    } else if (room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING && client.pos < 4) { // side deck verified
nanahira's avatar
nanahira committed
3918 3919 3920 3921 3922 3923
      client.selected_preduel = true;
      if (client.side_tcount) {
        clearInterval(client.side_interval);
        client.side_interval = null;
        client.side_tcount = null;
      }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3924
    }
3925
    if (settings.modules.hide_name && room.duel_count === 0) {
nanahira's avatar
nanahira committed
3926 3927 3928
      ref4 = room.get_playing_player();
      for (o = 0, len4 = ref4.length; o < len4; o++) {
        player = ref4[o];
3929 3930 3931 3932 3933 3934 3935 3936
        if (player !== client) {
          ygopro.stoc_send(client, 'HS_PLAYER_ENTER', {
            name: player.name,
            pos: player.pos
          });
        }
      }
    }
mercury233's avatar
mercury233 committed
3937
    if (settings.modules.tips.enabled) {
mercury233's avatar
test3  
mercury233 committed
3938
      ygopro.stoc_send_random_tip(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3939
    }
nanahira's avatar
nanahira committed
3940 3941
    deck_text = null;
    if (client.main && client.main.length) {
mercury233's avatar
mercury233 committed
3942
      deck_text = '#ygopro-server deck log\n#main\n' + client.main.join('\n') + '\n!side\n' + client.side.join('\n') + '\n';
nanahira's avatar
nanahira committed
3943 3944 3945
      room.decks[client.name] = deck_text;
    }
    if (settings.modules.deck_log.enabled && deck_text && !client.deck_saved && !room.windbot) {
mercury233's avatar
mercury233 committed
3946 3947 3948 3949 3950 3951 3952 3953
      deck_arena = settings.modules.deck_log.arena + '-';
      if (room.arena) {
        deck_arena = deck_arena + room.arena;
      } else if (room.hostinfo.mode === 2) {
        deck_arena = deck_arena + 'tag';
      } else if (room.random_type === 'S') {
        deck_arena = deck_arena + 'entertain';
      } else if (room.random_type === 'M') {
mercury233's avatar
mercury233 committed
3954
        deck_arena = deck_arena + 'athletic';
mercury233's avatar
mercury233 committed
3955 3956 3957
      } else {
        deck_arena = deck_arena + 'custom';
      }
nanahira's avatar
nanahira committed
3958
      //log.info "DECK LOG START", client.name, room.arena
mercury233's avatar
mercury233 committed
3959
      if (settings.modules.deck_log.local) {
nanahira's avatar
nanahira committed
3960
        deck_name = moment().format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + client.ip.slice(7) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_');
mercury233's avatar
mercury233 committed
3961
        fs.writeFile(settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', function(err) {
mercury233's avatar
mercury233 committed
3962 3963 3964 3965 3966
          if (err) {
            return log.warn('DECK SAVE ERROR', err);
          }
        });
      }
mercury233's avatar
mercury233 committed
3967
      if (settings.modules.deck_log.post) {
mercury233's avatar
mercury233 committed
3968
        request.post({
mercury233's avatar
mercury233 committed
3969
          url: settings.modules.deck_log.post,
mercury233's avatar
mercury233 committed
3970
          form: {
mercury233's avatar
mercury233 committed
3971
            accesskey: settings.modules.deck_log.accesskey,
mercury233's avatar
mercury233 committed
3972 3973
            deck: deck_text,
            playername: client.name,
mercury233's avatar
mercury233 committed
3974
            arena: deck_arena
mercury233's avatar
mercury233 committed
3975 3976 3977
          }
        }, function(error, response, body) {
          if (error) {
mercury233's avatar
merge  
mercury233 committed
3978
            log.warn('DECK POST ERROR', error);
mercury233's avatar
mercury233 committed
3979 3980
          } else {
            if (response.statusCode !== 200) {
mercury233's avatar
merge  
mercury233 committed
3981
              log.warn('DECK POST FAIL', response.statusCode, client.name, body);
mercury233's avatar
mercury233 committed
3982 3983 3984 3985
            }
          }
        });
      }
nanahira's avatar
nanahira committed
3986 3987
      //else
      //log.info 'DECK POST OK', response.statusCode, client.name, body
mercury233's avatar
mercury233 committed
3988 3989
      client.deck_saved = true;
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3990 3991
  });

nanahira's avatar
nanahira committed
3992
  ygopro.ctos_follow('SURRENDER', true, async function(buffer, info, client, server, datas) {
3993 3994 3995 3996 3997
    var room;
    room = ROOM_all[client.rid];
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
3998
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || room.hostinfo.mode === 2) {
3999 4000
      return true;
    }
4001
    if (room.random_type && room.turn < 3 && !client.flee_free && !settings.modules.test_mode.surrender_anytime && !(room.random_type === 'M' && settings.modules.random_duel.record_match_scores)) {
4002 4003 4004 4005 4006 4007
      ygopro.stoc_send_chat(client, "${surrender_denied}", ygopro.constants.COLORS.BABYBLUE);
      return true;
    }
    return false;
  });

nanahira's avatar
nanahira committed
4008
  report_to_big_brother = global.report_to_big_brother = async function(roomname, sender, ip, level, content, match) {
mercury233's avatar
mercury233 committed
4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033
    if (!settings.modules.big_brother.enabled) {
      return;
    }
    request.post({
      url: settings.modules.big_brother.post,
      form: {
        accesskey: settings.modules.big_brother.accesskey,
        roomname: roomname,
        sender: sender,
        ip: ip,
        level: level,
        content: content,
        match: match
      }
    }, function(error, response, body) {
      if (error) {
        log.warn('BIG BROTHER ERROR', error);
      } else {
        if (response.statusCode !== 200) {
          log.warn('BIG BROTHER FAIL', response.statusCode, roomname, body);
        }
      }
    });
  };

nanahira's avatar
nanahira committed
4034 4035
  //else
  //log.info 'BIG BROTHER OK', response.statusCode, roomname, body
nanahira's avatar
nanahira committed
4036
  ygopro.ctos_follow('CHAT', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4037
    var cancel, ccolor, cip, cmd, cmsg, cname, color, cvalue, msg, name, oldmsg, ref3, room, struct, windbot;
4038 4039
    room = ROOM_all[client.rid];
    if (!room) {
mercury233's avatar
mercury233 committed
4040 4041
      return;
    }
mercury233's avatar
mercury233 committed
4042 4043
    msg = _.trim(info.msg);
    cancel = _.startsWith(msg, "/");
4044
    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)) {
4045
      room.last_active_time = moment();
4046
    }
mercury233's avatar
mercury233 committed
4047 4048
    cmd = msg.split(' ');
    switch (cmd[0]) {
mercury233's avatar
mercury233 committed
4049 4050
      case '/投降':
      case '/surrender':
nanahira's avatar
nanahira committed
4051
        if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || room.hostinfo.mode === 2) {
mercury233's avatar
mercury233 committed
4052 4053
          return cancel;
        }
4054
        if (room.random_type && room.turn < 3) {
mercury233's avatar
mercury233 committed
4055 4056 4057 4058 4059 4060 4061 4062 4063 4064
          ygopro.stoc_send_chat(client, "${surrender_denied}", ygopro.constants.COLORS.BABYBLUE);
          return cancel;
        }
        if (client.surrend_confirm) {
          ygopro.ctos_send(client.server, 'SURRENDER');
        } else {
          ygopro.stoc_send_chat(client, "${surrender_confirm}", ygopro.constants.COLORS.BABYBLUE);
          client.surrend_confirm = true;
        }
        break;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4065
      case '/help':
mercury233's avatar
mercury233 committed
4066 4067
        ygopro.stoc_send_chat(client, "${chat_order_main}");
        ygopro.stoc_send_chat(client, "${chat_order_help}");
mercury233's avatar
mercury233 committed
4068
        if (!settings.modules.mycard.enabled) {
mercury233's avatar
mercury233 committed
4069
          ygopro.stoc_send_chat(client, "${chat_order_roomname}");
mercury233's avatar
merge  
mercury233 committed
4070
        }
mercury233's avatar
mercury233 committed
4071
        if (settings.modules.windbot.enabled) {
mercury233's avatar
mercury233 committed
4072
          ygopro.stoc_send_chat(client, "${chat_order_windbot}");
mercury233's avatar
mercury233 committed
4073
        }
mercury233's avatar
mercury233 committed
4074
        if (settings.modules.tips.enabled) {
mercury233's avatar
mercury233 committed
4075
          ygopro.stoc_send_chat(client, "${chat_order_tip}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4076
        }
nanahira's avatar
nanahira committed
4077 4078 4079 4080 4081 4082
        if (settings.modules.chat_color.enabled) {
          ygopro.stoc_send_chat(client, "${chat_order_chatcolor_1}");
        }
        if (settings.modules.chat_color.enabled) {
          ygopro.stoc_send_chat(client, "${chat_order_chatcolor_2}");
        }
mercury233's avatar
mercury233 committed
4083
        break;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4084
      case '/tip':
mercury233's avatar
mercury233 committed
4085
        if (settings.modules.tips.enabled) {
mercury233's avatar
test3  
mercury233 committed
4086
          ygopro.stoc_send_random_tip(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4087
        }
mercury233's avatar
mercury233 committed
4088
        break;
mercury233's avatar
mercury233 committed
4089
      case '/ai':
4090
        if (settings.modules.windbot.enabled && client.is_host && !settings.modules.challonge.enabled && !room.arena && room.random_type !== 'M') {
4091 4092
          cmd.shift();
          if (name = cmd.join(' ')) {
mercury233's avatar
mercury233 committed
4093
            windbot = _.sample(_.filter(windbots, function(w) {
mercury233's avatar
mercury233 committed
4094 4095 4096
              return w.name === name || w.deck === name;
            }));
            if (!windbot) {
mercury233's avatar
mercury233 committed
4097
              ygopro.stoc_send_chat(client, "${windbot_deck_not_found}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4098 4099 4100
              return;
            }
          } else {
4101 4102 4103
            windbot = _.sample(_.filter(windbots, function(w) {
              return !w.hidden;
            }));
mercury233's avatar
mercury233 committed
4104
          }
mercury233's avatar
mercury233 committed
4105 4106 4107
          if (room.random_type) {
            ygopro.stoc_send_chat(client, "${windbot_disable_random_room} " + room.name, ygopro.constants.COLORS.BABYBLUE);
          }
mercury233's avatar
mercury233 committed
4108 4109 4110
          room.add_windbot(windbot);
        }
        break;
mercury233's avatar
mercury233 committed
4111
      case '/roomname':
4112
        if (room) {
mercury233's avatar
mercury233 committed
4113
          ygopro.stoc_send_chat(client, "${room_name} " + room.name, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
4114
        }
nanahira's avatar
nanahira committed
4115 4116 4117
        break;
      case '/color':
        if (settings.modules.chat_color.enabled) {
nanahira's avatar
nanahira committed
4118
          cip = CLIENT_get_authorize_key(client);
nanahira's avatar
nanahira committed
4119 4120 4121
          if (cmsg = cmd[1]) {
            if (cmsg.toLowerCase() === "help") {
              ygopro.stoc_send_chat(client, "${show_color_list}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
4122 4123 4124
              ref3 = ygopro.constants.COLORS;
              for (cname in ref3) {
                cvalue = ref3[cname];
nanahira's avatar
nanahira committed
4125 4126 4127 4128 4129
                if (cvalue > 10) {
                  ygopro.stoc_send_chat(client, cname, cvalue);
                }
              }
            } else if (cmsg.toLowerCase() === "default") {
nanahira's avatar
fix  
nanahira committed
4130 4131
              chat_color.save_list[cip] = false;
              setting_save(chat_color);
nanahira's avatar
nanahira committed
4132 4133 4134
              ygopro.stoc_send_chat(client, "${set_chat_color_default}", ygopro.constants.COLORS.BABYBLUE);
            } else {
              ccolor = cmsg.toUpperCase();
nanahira's avatar
fix  
nanahira committed
4135 4136 4137
              if (ygopro.constants.COLORS[ccolor] && ygopro.constants.COLORS[ccolor] > 10 && ygopro.constants.COLORS[ccolor] < 20) {
                chat_color.save_list[cip] = ccolor;
                setting_save(chat_color);
nanahira's avatar
nanahira committed
4138 4139 4140 4141 4142 4143
                ygopro.stoc_send_chat(client, "${set_chat_color_part1}" + ccolor + "${set_chat_color_part2}", ygopro.constants.COLORS.BABYBLUE);
              } else {
                ygopro.stoc_send_chat(client, "${color_not_found_part1}" + ccolor + "${color_not_found_part2}", ygopro.constants.COLORS.RED);
              }
            }
          } else {
nanahira's avatar
fix  
nanahira committed
4144
            if (color = chat_color.save_list[cip]) {
nanahira's avatar
nanahira committed
4145 4146 4147 4148 4149 4150
              ygopro.stoc_send_chat(client, "${get_chat_color_part1}" + color + "${get_chat_color_part2}", ygopro.constants.COLORS.BABYBLUE);
            } else {
              ygopro.stoc_send_chat(client, "${get_chat_color_default}", ygopro.constants.COLORS.BABYBLUE);
            }
          }
        }
神楽坂玲奈's avatar
神楽坂玲奈 committed
4151
    }
nanahira's avatar
nanahira committed
4152 4153
    //when '/test'
    //  ygopro.stoc_send_hint_card_to_room(room, 2333365)
mercury233's avatar
mercury233 committed
4154 4155 4156 4157 4158 4159 4160 4161
    if (msg.length > 100) {
      log.warn("SPAM WORD", client.name, client.ip, msg);
      if (client.abuse_count) {
        client.abuse_count = client.abuse_count + 2;
      }
      ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
      cancel = true;
    }
mercury233's avatar
mercury233 committed
4162
    if (!(room && (room.random_type || room.arena))) {
nanahira's avatar
nanahira committed
4163 4164 4165 4166
      if (!cancel && settings.modules.display_watchers && client.is_post_watcher) {
        ygopro.stoc_send_chat_to_room(room, `${client.name}: ${msg}`, 9);
        return true;
      }
mercury233's avatar
mercury233 committed
4167 4168
      return cancel;
    }
nanahira's avatar
nanahira committed
4169
    if (client.abuse_count >= 5 || CLIENT_is_banned_by_mc(client)) {
mercury233's avatar
mercury233 committed
4170
      log.warn("BANNED CHAT", client.name, client.ip, msg);
nanahira's avatar
fix  
nanahira committed
4171
      ygopro.stoc_send_chat(client, "${banned_chat_tip}" + (client.ban_mc && client.ban_mc.message ? ": " + client.ban_mc.message : ""), ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4172 4173
      return true;
    }
mercury233's avatar
mercury233 committed
4174
    oldmsg = msg;
mercury233's avatar
mercury233 committed
4175
    if (_.any(badwords.level3, function(badword) {
mercury233's avatar
mercury233 committed
4176
      var regexp;
mercury233's avatar
fix  
mercury233 committed
4177
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
4178 4179
      return msg.match(regexp);
    }, msg)) {
mercury233's avatar
mercury233 committed
4180 4181
      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);
mercury233's avatar
mercury233 committed
4182
      cancel = true;
mercury233's avatar
mercury233 committed
4183
      if (client.abuse_count > 0) {
mercury233's avatar
mercury233 committed
4184 4185 4186
        ygopro.stoc_send_chat(client, "${banned_duel_tip}", ygopro.constants.COLORS.RED);
        ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}");
        ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}", 3);
nanahira's avatar
nanahira committed
4187
        CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
4188
        CLIENT_kick(client);
mercury233's avatar
mercury233 committed
4189 4190 4191
        return true;
      } else {
        client.abuse_count = client.abuse_count + 4;
mercury233's avatar
mercury233 committed
4192
        ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4193
      }
nanahira's avatar
nanahira committed
4194
    } else if (client.rag && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
mercury233's avatar
mercury233 committed
4195
      client.rag = false;
nanahira's avatar
nanahira committed
4196
      //ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED)
mercury233's avatar
mercury233 committed
4197 4198 4199 4200 4201 4202
      cancel = true;
    } else if (_.any(settings.ban.spam_word, function(badword) {
      var regexp;
      regexp = new RegExp(badword, 'i');
      return msg.match(regexp);
    }, msg)) {
nanahira's avatar
nanahira committed
4203
      //log.warn "SPAM WORD", client.name, client.ip, oldmsg
mercury233's avatar
mercury233 committed
4204
      client.abuse_count = client.abuse_count + 2;
mercury233's avatar
mercury233 committed
4205
      ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4206
      cancel = true;
mercury233's avatar
mercury233 committed
4207
    } else if (_.any(badwords.level2, function(badword) {
mercury233's avatar
mercury233 committed
4208
      var regexp;
mercury233's avatar
fix  
mercury233 committed
4209
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
4210 4211
      return msg.match(regexp);
    }, msg)) {
mercury233's avatar
mercury233 committed
4212 4213
      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);
mercury233's avatar
mercury233 committed
4214
      client.abuse_count = client.abuse_count + 3;
mercury233's avatar
mercury233 committed
4215
      ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4216 4217
      cancel = true;
    } else {
mercury233's avatar
mercury233 committed
4218
      _.each(badwords.level1, function(badword) {
mercury233's avatar
mercury233 committed
4219
        var regexp;
nanahira's avatar
nanahira committed
4220
        //log.info msg
mercury233's avatar
fix  
mercury233 committed
4221
        regexp = new RegExp(badword, "ig");
mercury233's avatar
mercury233 committed
4222 4223 4224
        msg = msg.replace(regexp, "**");
      }, msg);
      if (oldmsg !== msg) {
mercury233's avatar
mercury233 committed
4225 4226
        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);
mercury233's avatar
mercury233 committed
4227
        client.abuse_count = client.abuse_count + 1;
mercury233's avatar
mercury233 committed
4228
        ygopro.stoc_send_chat(client, "${chat_warn_level1}");
4229
        struct = ygopro.structs.get("chat");
mercury233's avatar
mercury233 committed
4230 4231 4232
        struct._setBuff(buffer);
        struct.set("msg", msg);
        buffer = struct.buffer;
mercury233's avatar
mercury233 committed
4233
      } else if (_.any(badwords.level0, function(badword) {
mercury233's avatar
mercury233 committed
4234 4235 4236 4237
        var regexp;
        regexp = new RegExp(badword, 'i');
        return msg.match(regexp);
      }, msg)) {
mercury233's avatar
mercury233 committed
4238 4239
        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);
mercury233's avatar
mercury233 committed
4240 4241
      }
    }
mercury233's avatar
mercury233 committed
4242 4243 4244
    if (client.abuse_count >= 2) {
      ROOM_unwelcome(room, client, "${random_ban_reason_abuse}");
    }
mercury233's avatar
mercury233 committed
4245
    if (client.abuse_count >= 5) {
nanahira's avatar
nanahira committed
4246
      ygopro.stoc_send_chat_to_room(room, `${client.name} \${chat_banned}`, ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4247
      ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}");
mercury233's avatar
mercury233 committed
4248
    }
nanahira's avatar
nanahira committed
4249 4250 4251 4252
    if (!cancel && settings.modules.display_watchers && client.is_post_watcher) {
      ygopro.stoc_send_chat_to_room(room, `${client.name}: ${msg}`, 9);
      return true;
    }
4253
    return cancel;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4254 4255
  });

nanahira's avatar
nanahira committed
4256
  ygopro.ctos_follow('UPDATE_DECK', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4257
    var buff_main, buff_side, card, current_deck, deck, deck_array, deck_main, deck_side, deck_text, deckbuf, decks, found_deck, i, len3, len4, line, n, o, oppo_pos, recover_player_data, room, struct, win_pos;
nanahira's avatar
nanahira committed
4258
    if (settings.modules.reconnect.enabled && client.pre_reconnecting) {
nanahira's avatar
nanahira committed
4259 4260 4261 4262
      if (!CLIENT_is_able_to_reconnect(client) && !CLIENT_is_able_to_kick_reconnect(client)) {
        ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED);
        CLIENT_kick(client);
      } else if (CLIENT_is_able_to_reconnect(client, buffer)) {
nanahira's avatar
nanahira committed
4263
        CLIENT_reconnect(client);
nanahira's avatar
nanahira committed
4264 4265
      } else if (CLIENT_is_able_to_kick_reconnect(client, buffer)) {
        CLIENT_kick_reconnect(client, buffer);
nanahira's avatar
nanahira committed
4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277
      } else {
        ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED);
        ygopro.stoc_send(client, 'ERROR_MSG', {
          msg: 2,
          code: 0
        });
        ygopro.stoc_send(client, 'HS_PLAYER_CHANGE', {
          status: (client.pos << 4) | 0xa
        });
      }
      return true;
    }
mercury233's avatar
mercury233 committed
4278 4279 4280 4281
    room = ROOM_all[client.rid];
    if (!room) {
      return false;
    }
nanahira's avatar
nanahira committed
4282 4283
    //log.info info
    if (info.mainc > 256 || info.sidec > 256) { // Prevent attack, see https://github.com/Fluorohydride/ygopro/issues/2174
nanahira's avatar
nanahira committed
4284 4285 4286
      CLIENT_kick(client);
      return true;
    }
mercury233's avatar
mercury233 committed
4287
    buff_main = (function() {
nanahira's avatar
nanahira committed
4288
      var n, ref3, results;
4289
      results = [];
nanahira's avatar
nanahira committed
4290
      for (i = n = 0, ref3 = info.mainc; (0 <= ref3 ? n < ref3 : n > ref3); i = 0 <= ref3 ? ++n : --n) {
4291
        results.push(info.deckbuf[i]);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4292
      }
4293
      return results;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4294
    })();
mercury233's avatar
mercury233 committed
4295
    buff_side = (function() {
nanahira's avatar
nanahira committed
4296
      var n, ref3, ref4, results;
4297
      results = [];
nanahira's avatar
nanahira committed
4298
      for (i = n = ref3 = info.mainc, ref4 = info.mainc + info.sidec; (ref3 <= ref4 ? n < ref4 : n > ref4); i = ref3 <= ref4 ? ++n : --n) {
4299
        results.push(info.deckbuf[i]);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4300
      }
4301
      return results;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4302
    })();
mercury233's avatar
mercury233 committed
4303 4304
    client.main = buff_main;
    client.side = buff_side;
nanahira's avatar
nanahira committed
4305
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
fix  
nanahira committed
4306
      client.start_deckbuf = Buffer.from(buffer);
nanahira's avatar
nanahira committed
4307
    }
nanahira's avatar
nanahira committed
4308
    oppo_pos = room.hostinfo.mode === 2 ? 2 : 1;
nanahira's avatar
nanahira committed
4309
    if (settings.modules.http.quick_death_rule >= 2 && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.death && room.scores[room.dueling_players[0].name_vpass] !== room.scores[room.dueling_players[oppo_pos].name_vpass]) {
4310
      win_pos = room.scores[room.dueling_players[0].name_vpass] > room.scores[room.dueling_players[oppo_pos].name_vpass] ? 0 : oppo_pos;
nanahira's avatar
nanahira committed
4311
      room.finished_by_death = true;
nanahira's avatar
nanahira committed
4312
      ygopro.stoc_send_chat_to_room(room, "${death2_finish_part1}" + room.dueling_players[win_pos].name + "${death2_finish_part2}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
4313 4314 4315
      if (room.hostinfo.mode === 1) {
        CLIENT_send_replays(room.dueling_players[oppo_pos - win_pos], room);
      }
nanahira's avatar
nanahira committed
4316 4317 4318 4319
      ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos], 'DUEL_END');
      if (room.hostinfo.mode === 2) {
        ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos + 1], 'DUEL_END');
      }
4320
      room.scores[room.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
nanahira's avatar
nanahira committed
4321
      CLIENT_kick(room.dueling_players[oppo_pos - win_pos]);
nanahira's avatar
nanahira committed
4322
      if (room.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
4323
        CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]);
nanahira's avatar
nanahira committed
4324
      }
nanahira's avatar
nanahira committed
4325 4326
      return true;
    }
4327
    struct = ygopro.structs.get("deck");
nanahira's avatar
nanahira committed
4328
    struct._setBuff(buffer);
4329
    if (room.random_type || room.arena) {
nanahira's avatar
nanahira committed
4330
      if (client.pos === 0) {
mercury233's avatar
mercury233 committed
4331 4332 4333
        room.waiting_for_player = room.waiting_for_player2;
      }
      room.last_active_time = moment();
nanahira's avatar
nanahira committed
4334 4335 4336
    }
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.recovering) {
      recover_player_data = _.find(room.recover_duel_log.players, function(player) {
nanahira's avatar
nanahira committed
4337
        return player.real_name === client.name_vpass && _.isEqual(buffer, Buffer.from(player.deckbuf, "base64"));
nanahira's avatar
nanahira committed
4338
      });
nanahira's avatar
nanahira committed
4339
      if (recover_player_data) {
nanahira's avatar
nanahira committed
4340 4341 4342
        struct.set("mainc", recover_player_data.deck.main.length);
        struct.set("sidec", recover_player_data.deck.side.length);
        struct.set("deckbuf", recover_player_data.deck.main.concat(recover_player_data.deck.side));
nanahira's avatar
nanahira committed
4343 4344 4345 4346 4347 4348 4349 4350 4351
        if (recover_player_data.is_first) {
          room.determine_firstgo = client;
        }
      } else {
        struct.set("mainc", 1);
        struct.set("sidec", 1);
        struct.set("deckbuf", [4392470, 4392470]);
        ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED);
      }
nanahira's avatar
nanahira committed
4352
    } else if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.hostinfo.mode === 1 && settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.deck_check && fs.readdirSync(settings.modules.tournament_mode.deck_path).length) {
mercury233's avatar
mercury233 committed
4353 4354 4355 4356 4357 4358
      struct.set("mainc", 1);
      struct.set("sidec", 1);
      struct.set("deckbuf", [4392470, 4392470]);
      buffer = struct.buffer;
      found_deck = false;
      decks = fs.readdirSync(settings.modules.tournament_mode.deck_path);
nanahira's avatar
nanahira committed
4359 4360
      for (n = 0, len3 = decks.length; n < len3; n++) {
        deck = decks[n];
Yuzurisa's avatar
Yuzurisa committed
4361
        if (deck_name_match(deck, client.name)) {
mercury233's avatar
fix  
mercury233 committed
4362 4363
          found_deck = deck;
        }
mercury233's avatar
mercury233 committed
4364 4365
      }
      if (found_deck) {
mercury233's avatar
mercury233 committed
4366
        deck_text = fs.readFileSync(settings.modules.tournament_mode.deck_path + found_deck, {
mercury233's avatar
mercury233 committed
4367 4368 4369 4370 4371 4372
          encoding: "ASCII"
        });
        deck_array = deck_text.split("\n");
        deck_main = [];
        deck_side = [];
        current_deck = deck_main;
nanahira's avatar
nanahira committed
4373 4374
        for (o = 0, len4 = deck_array.length; o < len4; o++) {
          line = deck_array[o];
mercury233's avatar
mercury233 committed
4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388
          if (line.indexOf("!side") >= 0) {
            current_deck = deck_side;
          }
          card = parseInt(line);
          if (!isNaN(card)) {
            current_deck.push(card);
          }
        }
        if (_.isEqual(buff_main, deck_main) && _.isEqual(buff_side, deck_side)) {
          deckbuf = deck_main.concat(deck_side);
          struct.set("mainc", deck_main.length);
          struct.set("sidec", deck_side.length);
          struct.set("deckbuf", deckbuf);
          buffer = struct.buffer;
nanahira's avatar
nanahira committed
4389 4390
          //log.info("deck ok: " + client.name)
          ygopro.stoc_send_chat(client, `\${deck_correct_part1} ${found_deck} \${deck_correct_part2}`, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
4391
        } else {
nanahira's avatar
nanahira committed
4392 4393
          //log.info("bad deck: " + client.name + " / " + buff_main + " / " + buff_side)
          ygopro.stoc_send_chat(client, `\${deck_incorrect_part1} ${found_deck} \${deck_incorrect_part2}`, ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4394 4395
        }
      } else {
nanahira's avatar
nanahira committed
4396 4397
        //log.info("player deck not found: " + client.name)
        ygopro.stoc_send_chat(client, `${client.name}\${deck_not_found}`, ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4398
      }
mercury233's avatar
mercury233 committed
4399
    }
mercury233's avatar
mercury233 committed
4400
    return false;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4401 4402
  });

nanahira's avatar
nanahira committed
4403
  ygopro.ctos_follow('RESPONSE', false, async function(buffer, info, client, server, datas) {
4404 4405
    var room;
    room = ROOM_all[client.rid];
4406
    if (!(room && (room.random_type || room.arena))) {
4407 4408
      return;
    }
4409
    room.last_active_time = moment();
4410 4411
  });

nanahira's avatar
nanahira committed
4412
  ygopro.stoc_follow('TIME_LIMIT', true, async function(buffer, info, client, server, datas) {
4413
    var check, cur_players, room;
nanahira's avatar
nanahira committed
4414
    room = ROOM_all[client.rid];
nanahira's avatar
js  
nanahira committed
4415 4416 4417
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445
    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];
    }
nanahira's avatar
nanahira committed
4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462
    if (room.recovering) {
      if (check) {
        ygopro.ctos_send(server, 'TIME_CONFIRM');
      }
      return true;
    }
    if (settings.modules.reconnect.enabled) {
      if (client.closed) {
        ygopro.ctos_send(server, 'TIME_CONFIRM');
        return true;
      } else {
        client.time_confirm_required = true;
      }
    }
    if (!(settings.modules.heartbeat_detection.enabled && room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING && !room.windbot)) {
      return;
    }
nanahira's avatar
nanahira committed
4463
    if (check) {
4464
      CLIENT_heartbeat_register(client, false);
nanahira's avatar
nanahira committed
4465
    }
nanahira's avatar
js  
nanahira committed
4466
    return false;
nanahira's avatar
nanahira committed
4467 4468
  });

nanahira's avatar
nanahira committed
4469
  ygopro.ctos_follow('TIME_CONFIRM', false, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4470 4471
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4472
    if (!room) {
nanahira's avatar
nanahira committed
4473 4474
      return;
    }
nanahira's avatar
nanahira committed
4475 4476 4477
    if (room.recovered) {
      room.recovered = false;
    }
nanahira's avatar
nanahira committed
4478
    if (settings.modules.reconnect.enabled) {
4479 4480 4481 4482 4483 4484 4485 4486 4487
      if (client.waiting_for_last) {
        client.waiting_for_last = false;
        if (client.last_game_msg && client.last_game_msg_title !== 'WAITING') {
          if (client.last_hint_msg) {
            ygopro.stoc_send(client, 'GAME_MSG', client.last_hint_msg);
          }
          ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg);
        }
      }
nanahira's avatar
nanahira committed
4488 4489
      client.time_confirm_required = false;
    }
4490 4491 4492 4493
    if (settings.modules.heartbeat_detection.enabled) {
      client.heartbeat_protected = false;
      client.heartbeat_responsed = true;
      CLIENT_heartbeat_unregister(client);
nanahira's avatar
typo  
nanahira committed
4494
    }
nanahira's avatar
nanahira committed
4495 4496
  });

nanahira's avatar
nanahira committed
4497
  ygopro.ctos_follow('HAND_RESULT', false, async function(buffer, info, client, server, datas) {
4498 4499
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4500 4501 4502 4503
    if (!room) {
      return;
    }
    client.selected_preduel = true;
nanahira's avatar
nanahira committed
4504 4505 4506 4507 4508
    if (room.random_type || 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');
4509 4510 4511
    }
  });

nanahira's avatar
nanahira committed
4512
  ygopro.ctos_follow('TP_RESULT', false, async function(buffer, info, client, server, datas) {
4513 4514
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4515 4516 4517 4518
    if (!room) {
      return;
    }
    client.selected_preduel = true;
nanahira's avatar
nanahira committed
4519
    // room.selecting_tp = false
nanahira's avatar
nanahira committed
4520
    if (!(room.random_type || room.arena)) {
4521 4522
      return;
    }
4523
    room.last_active_time = moment();
4524 4525
  });

nanahira's avatar
nanahira committed
4526
  ygopro.stoc_follow('CHAT', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4527
    var len3, n, pid, player, ref3, room, tcolor, tplayer;
nanahira's avatar
nanahira committed
4528 4529
    room = ROOM_all[client.rid];
    pid = info.player;
nanahira's avatar
nanahira committed
4530
    if (!(room && pid < 4 && settings.modules.chat_color.enabled && (!settings.modules.hide_name || room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN))) {
nanahira's avatar
nanahira committed
4531 4532
      return;
    }
nanahira's avatar
nanahira committed
4533
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING && !room.dueling_players[0].is_first) {
nanahira's avatar
fix  
nanahira committed
4534
      if (room.hostinfo.mode === 2) {
nanahira's avatar
fix  
nanahira committed
4535 4536 4537 4538 4539 4540
        pid = {
          0: 2,
          1: 3,
          2: 0,
          3: 1
        }[pid];
nanahira's avatar
fix  
nanahira committed
4541 4542 4543 4544
      } else {
        pid = 1 - pid;
      }
    }
nanahira's avatar
nanahira committed
4545 4546 4547
    ref3 = room.players;
    for (n = 0, len3 = ref3.length; n < len3; n++) {
      player = ref3[n];
nanahira's avatar
nanahira committed
4548 4549 4550 4551 4552 4553 4554
      if (player && player.pos === pid) {
        tplayer = player;
      }
    }
    if (!tplayer) {
      return;
    }
nanahira's avatar
fi  
nanahira committed
4555
    tcolor = chat_color.save_list[CLIENT_get_authorize_key(tplayer)];
nanahira's avatar
nanahira committed
4556 4557 4558 4559 4560 4561 4562 4563 4564
    if (tcolor) {
      ygopro.stoc_send(client, 'CHAT', {
        player: ygopro.constants.COLORS[tcolor],
        msg: tplayer.name + ": " + info.msg
      });
      return true;
    }
  });

nanahira's avatar
nanahira committed
4565
  ygopro.stoc_follow('SELECT_HAND', true, async function(buffer, info, client, server, datas) {
4566 4567
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4568
    if (!room) {
nanahira's avatar
nanahira committed
4569
      return false;
nanahira's avatar
nanahira committed
4570 4571
    }
    if (client.pos === 0) {
nanahira's avatar
nanahira committed
4572
      room.duel_stage = ygopro.constants.DUEL_STAGE.FINGER;
nanahira's avatar
nanahira committed
4573
    }
nanahira's avatar
nanahira committed
4574 4575 4576 4577 4578 4579 4580
    if (room.random_type || room.arena) {
      if (client.pos === 0) {
        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');
4581
    }
nanahira's avatar
nanahira committed
4582 4583 4584 4585 4586
    if (room.determine_firstgo) {
      ygopro.ctos_send(server, "HAND_RESULT", {
        res: client.pos === 0 ? 2 : 1
      });
      return true;
4587
    } else {
nanahira's avatar
nanahira committed
4588
      client.selected_preduel = false;
4589
    }
nanahira's avatar
nanahira committed
4590
    return false;
4591 4592
  });

nanahira's avatar
nanahira committed
4593
  ygopro.stoc_follow('HAND_RESULT', true, async function(buffer, info, client, server, datas) {
4594 4595
    var room;
    room = ROOM_all[client.rid];
4596
    if (!room) {
nanahira's avatar
nanahira committed
4597 4598 4599 4600 4601
      return false;
    }
    return room.determine_firstgo;
  });

nanahira's avatar
nanahira committed
4602
  ygopro.stoc_follow('SELECT_TP', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4603 4604 4605 4606
    var room;
    room = ROOM_all[client.rid];
    if (!room) {
      return false;
4607
    }
nanahira's avatar
nanahira committed
4608
    room.duel_stage = ygopro.constants.DUEL_STAGE.FIRSTGO;
mercury233's avatar
fix  
mercury233 committed
4609
    if (room.random_type || room.arena) {
4610 4611 4612
      room.waiting_for_player = client;
      room.last_active_time = moment();
    }
nanahira's avatar
nanahira committed
4613 4614 4615 4616 4617 4618 4619 4620 4621 4622
    if (room.determine_firstgo) {
      ygopro.ctos_send(server, "TP_RESULT", {
        res: room.determine_firstgo === client ? 1 : 0
      });
      return true;
    } else {
      client.selected_preduel = false;
      room.selecting_tp = client;
    }
    return false;
4623 4624
  });

nanahira's avatar
nanahira committed
4625
  ygopro.stoc_follow('CHANGE_SIDE', false, async function(buffer, info, client, server, datas) {
nanahira's avatar
js  
nanahira committed
4626
    var room, room_name, sinterval, temp_log;
4627
    room = ROOM_all[client.rid];
4628
    if (!room) {
mercury233's avatar
mercury233 committed
4629 4630
      return;
    }
nanahira's avatar
nanahira committed
4631 4632 4633
    if (client.pos === 0) {
      room.duel_stage = ygopro.constants.DUEL_STAGE.SIDING;
    }
nanahira's avatar
nanahira committed
4634
    client.selected_preduel = false;
nanahira's avatar
nanahira committed
4635 4636
    if (settings.modules.side_timeout) {
      client.side_tcount = settings.modules.side_timeout;
nanahira's avatar
nanahira committed
4637
      ygopro.stoc_send_chat(client, `\${side_timeout_part1}${settings.modules.side_timeout}\${side_timeout_part2}`, ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
4638
      sinterval = setInterval(function() {
nanahira's avatar
nanahira committed
4639
        if (!(room && client && client.side_tcount && room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING)) {
nanahira's avatar
nanahira committed
4640 4641 4642 4643
          clearInterval(sinterval);
          return;
        }
        if (client.side_tcount === 1) {
nanahira's avatar
fix  
nanahira committed
4644
          ygopro.stoc_send_chat_to_room(room, client.name + "${side_overtime_room}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
4645
          ygopro.stoc_send_chat(client, "${side_overtime}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
4646
          //room.scores[client.name_vpass] = -9
nanahira's avatar
nanahira committed
4647
          CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
4648
          CLIENT_kick(client);
nanahira's avatar
nanahira committed
4649 4650 4651
          return clearInterval(sinterval);
        } else {
          client.side_tcount = client.side_tcount - 1;
nanahira's avatar
nanahira committed
4652
          return ygopro.stoc_send_chat(client, `\${side_remain_part1}${client.side_tcount}\${side_remain_part2}`, ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
4653 4654 4655 4656
        }
      }, 60000);
      client.side_interval = sinterval;
    }
nanahira's avatar
js  
nanahira committed
4657
    if (settings.modules.challonge.enabled && settings.modules.challonge.post_score_midduel && room.hostinfo.mode !== 2 && client.pos === 0) {
nanahira's avatar
nanahira committed
4658
      temp_log = JSON.parse(JSON.stringify(room.get_challonge_score()));
nanahira's avatar
nanahira committed
4659
      delete temp_log.winnerId;
nanahira's avatar
js  
nanahira committed
4660
      room_name = room.name;
nanahira's avatar
nanahira committed
4661
      challonge.matches._update({
4662
        id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
4663 4664 4665 4666
        matchId: room.challonge_info.id,
        match: temp_log,
        callback: function(err, data) {
          if (err) {
nanahira's avatar
js  
nanahira committed
4667
            log.warn("Errored pushing scores to Challonge.", room_name, err);
nanahira's avatar
nanahira committed
4668 4669
          } else {
            refresh_challonge_cache();
nanahira's avatar
nanahira committed
4670 4671 4672 4673
          }
        }
      });
    }
4674
    if (room.random_type || room.arena) {
nanahira's avatar
nanahira committed
4675
      if (client.pos === 0) {
4676 4677 4678 4679 4680
        room.waiting_for_player = client;
      } else {
        room.waiting_for_player2 = client;
      }
      room.last_active_time = moment();
mercury233's avatar
mercury233 committed
4681 4682 4683
    }
  });

nanahira's avatar
nanahira committed
4684
  ygopro.stoc_follow('REPLAY', true, async function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4685
    var duellog, dueltime, i, len3, len4, n, o, player, ref3, ref4, replay_filename, room;
4686 4687
    room = ROOM_all[client.rid];
    if (!room) {
4688
      return settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.block_replay_to_player || settings.modules.replay_delay;
4689
    }
mercury233's avatar
mercury233 committed
4690
    if (settings.modules.cloud_replay.enabled && room.random_type) {
mercury233's avatar
fix  
mercury233 committed
4691 4692
      Cloud_replay_ids.push(room.cloud_replay_id);
    }
nanahira's avatar
nanahira committed
4693
    if (!room.replays[room.duel_count - 1]) {
nanahira's avatar
nanahira committed
4694
      // console.log("Replay saved: ", room.duel_count - 1, client.pos)
4695
      room.replays[room.duel_count - 1] = buffer;
nanahira's avatar
nanahira committed
4696
    }
4697
    if (settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe || settings.modules.tournament_mode.enable_recover) {
nanahira's avatar
nanahira committed
4698
      if (client.pos === 0) {
nanahira's avatar
nanahira committed
4699
        dueltime = moment().format('YYYY-MM-DD HH-mm-ss');
mercury233's avatar
mercury233 committed
4700
        replay_filename = dueltime;
nanahira's avatar
fix  
nanahira committed
4701
        if (room.hostinfo.mode !== 2) {
nanahira's avatar
nanahira committed
4702
          ref3 = room.dueling_players;
nanahira's avatar
nanahira committed
4703
          for (i = n = 0, len3 = ref3.length; n < len3; i = ++n) {
nanahira's avatar
nanahira committed
4704
            player = ref3[i];
nanahira's avatar
nanahira committed
4705 4706 4707 4708 4709 4710
            replay_filename = replay_filename + (i > 0 ? " VS " : " ") + player.name;
          }
        } else {
          ref4 = room.dueling_players;
          for (i = o = 0, len4 = ref4.length; o < len4; i = ++o) {
            player = ref4[i];
nanahira's avatar
nanahira committed
4711 4712
            replay_filename = replay_filename + (i > 0 ? (i === 2 ? " VS " : " & ") : " ") + player.name;
          }
mercury233's avatar
mercury233 committed
4713 4714
        }
        replay_filename = replay_filename.replace(/[\/\\\?\*]/g, '_') + ".yrp";
mercury233's avatar
mercury233 committed
4715
        duellog = {
nanahira's avatar
nanahira committed
4716
          id: duel_log.duel_log.length + 1,
mercury233's avatar
mercury233 committed
4717
          time: dueltime,
4718
          name: room.name + (settings.modules.tournament_mode.show_info ? " (Duel:" + room.duel_count + ")" : ""),
nanahira's avatar
nanahira committed
4719
          roomid: room.process_pid.toString(),
mercury233's avatar
mercury233 committed
4720
          cloud_replay_id: "R#" + room.cloud_replay_id,
mercury233's avatar
mercury233 committed
4721
          replay_filename: replay_filename,
nanahira's avatar
nanahira committed
4722
          roommode: room.hostinfo.mode,
mercury233's avatar
mercury233 committed
4723
          players: (function() {
nanahira's avatar
nanahira committed
4724 4725
            var len5, p, ref5, results;
            ref5 = room.dueling_players;
mercury233's avatar
mercury233 committed
4726
            results = [];
nanahira's avatar
nanahira committed
4727 4728
            for (p = 0, len5 = ref5.length; p < len5; p++) {
              player = ref5[p];
mercury233's avatar
mercury233 committed
4729
              results.push({
nanahira's avatar
nanahira committed
4730 4731
                real_name: player.name_vpass,
                deckbuf: player.start_deckbuf.toString("base64"),
nanahira's avatar
nanahira committed
4732 4733 4734 4735
                deck: {
                  main: player.main,
                  side: player.side
                },
nanahira's avatar
nanahira committed
4736
                pos: player.pos,
nanahira's avatar
nanahira committed
4737
                is_first: player.is_first,
4738
                name: player.name + (settings.modules.tournament_mode.show_ip && !player.is_local ? " (IP: " + player.ip.slice(7) + ")" : "") + (settings.modules.tournament_mode.show_info && !(room.hostinfo.mode === 2 && player.pos % 2 > 0) ? " (Score:" + room.scores[player.name_vpass] + " LP:" + (player.lp != null ? player.lp : room.hostinfo.start_lp) + (room.hostinfo.mode !== 2 ? " Cards:" + (player.card_count != null ? player.card_count : room.hostinfo.start_hand) : "") + ")" : ""),
mercury233's avatar
mercury233 committed
4739 4740 4741 4742 4743 4744
                winner: player.pos === room.winner
              });
            }
            return results;
          })()
        };
mercury233's avatar
mercury233 committed
4745 4746
        duel_log.duel_log.unshift(duellog);
        setting_save(duel_log);
mercury233's avatar
mercury233 committed
4747 4748 4749 4750 4751
        fs.writeFile(settings.modules.tournament_mode.replay_path + replay_filename, buffer, function(err) {
          if (err) {
            return log.warn("SAVE REPLAY ERROR", replay_filename, err);
          }
        });
mercury233's avatar
mercury233 committed
4752
      }
nanahira's avatar
fix  
nanahira committed
4753
      if (settings.modules.cloud_replay.enabled && settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe) {
nanahira's avatar
nanahira committed
4754
        ygopro.stoc_send_chat(client, `\${cloud_replay_delay_part1}R#${room.cloud_replay_id}\${cloud_replay_delay_part2}`, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
4755
      }
nanahira's avatar
js  
nanahira committed
4756
      return settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.block_replay_to_player || settings.modules.replay_delay && room.hostinfo.mode === 1;
4757
    } else {
nanahira's avatar
nanahira committed
4758
      return settings.modules.replay_delay && room.hostinfo.mode === 1;
4759 4760 4761
    }
  });

mercury233's avatar
mercury233 committed
4762
  if (settings.modules.random_duel.enabled) {
mercury233's avatar
mercury233 committed
4763
    setInterval(function() {
nanahira's avatar
nanahira committed
4764
      _async.each(ROOM_all, function(room, done) {
nanahira's avatar
nanahira committed
4765
        var time_passed;
nanahira's avatar
nanahira committed
4766
        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)) {
nanahira's avatar
nanahira committed
4767 4768 4769
          done();
          return;
        }
mercury233's avatar
mercury233 committed
4770
        time_passed = Math.floor((moment() - room.last_active_time) / 1000);
nanahira's avatar
nanahira committed
4771
        //log.info time_passed
4772
        if (time_passed >= settings.modules.random_duel.hang_timeout) {
mercury233's avatar
mercury233 committed
4773
          room.last_active_time = moment();
mercury233's avatar
mercury233 committed
4774
          ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}");
4775
          room.scores[room.waiting_for_player.name_vpass] = -9;
nanahira's avatar
nanahira committed
4776 4777
          //log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
          ygopro.stoc_send_chat_to_room(room, `${room.waiting_for_player.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
4778
          CLIENT_send_replays(room.waiting_for_player, room);
nanahira's avatar
nanahira committed
4779
          CLIENT_kick(room.waiting_for_player);
4780
        } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
nanahira's avatar
nanahira committed
4781
          ygopro.stoc_send_chat_to_room(room, `${room.waiting_for_player.name} \${afk_warn_part1}${settings.modules.random_duel.hang_timeout - time_passed}\${afk_warn_part2}`, ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
4782
          ROOM_unwelcome(room, room.waiting_for_player, "${random_ban_reason_AFK}");
mercury233's avatar
mercury233 committed
4783
        }
nanahira's avatar
nanahira committed
4784
        done();
nanahira's avatar
nanahira committed
4785
      });
mercury233's avatar
mercury233 committed
4786 4787 4788
    }, 1000);
  }

4789 4790
  if (settings.modules.mycard.enabled) {
    setInterval(function() {
nanahira's avatar
nanahira committed
4791
      _async.each(ROOM_all, function(room, done) {
nanahira's avatar
nanahira committed
4792
        var time_passed;
nanahira's avatar
nanahira committed
4793
        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)) {
nanahira's avatar
nanahira committed
4794 4795 4796
          done();
          return;
        }
4797
        time_passed = Math.floor((moment() - room.last_active_time) / 1000);
nanahira's avatar
nanahira committed
4798
        //log.info time_passed
4799
        if (time_passed >= settings.modules.random_duel.hang_timeout) {
4800
          room.last_active_time = moment();
nanahira's avatar
nanahira committed
4801
          ygopro.stoc_send_chat_to_room(room, `${room.waiting_for_player.name} \${kicked_by_system}`, ygopro.constants.COLORS.RED);
4802
          room.scores[room.waiting_for_player.name_vpass] = -9;
nanahira's avatar
nanahira committed
4803
          //log.info room.waiting_for_player.name, room.scores[room.waiting_for_player.name_vpass]
nanahira's avatar
nanahira committed
4804
          CLIENT_send_replays(room.waiting_for_player, room);
nanahira's avatar
js  
nanahira committed
4805
          CLIENT_kick(room.waiting_for_player);
4806
        } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
nanahira's avatar
nanahira committed
4807
          ygopro.stoc_send_chat_to_room(room, `${room.waiting_for_player.name} \${afk_warn_part1}${settings.modules.random_duel.hang_timeout - time_passed}\${afk_warn_part2}`, ygopro.constants.COLORS.RED);
4808
        }
nanahira's avatar
nanahira committed
4809 4810
        done();
      });
nanahira's avatar
nanahira committed
4811
      if (true) { // settings.modules.arena_mode.punish_quit_before_match
nanahira's avatar
nanahira committed
4812
        _async.each(ROOM_all, function(room, done) {
nanahira's avatar
nanahira committed
4813
          var player, waited_time;
nanahira's avatar
nanahira committed
4814 4815 4816 4817
          if (!(room && room.arena && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.get_playing_player().length < 2)) {
            done();
            return;
          }
4818 4819 4820 4821 4822 4823 4824 4825 4826
          player = room.get_playing_player()[0];
          if (player && player.join_time && !player.arena_quit_free) {
            waited_time = moment() - player.join_time;
            if (waited_time >= 30000) {
              ygopro.stoc_send_chat(player, "${arena_wait_timeout}", ygopro.constants.COLORS.BABYBLUE);
              player.arena_quit_free = true;
            } else if (waited_time >= 5000 && waited_time < 6000) {
              ygopro.stoc_send_chat(player, "${arena_wait_hint}", ygopro.constants.COLORS.BABYBLUE);
            }
nanahira's avatar
nanahira committed
4827
          }
nanahira's avatar
nanahira committed
4828 4829
          done();
        });
nanahira's avatar
nanahira committed
4830
      }
4831 4832 4833
    }, 1000);
  }

nanahira's avatar
nanahira committed
4834 4835
  if (settings.modules.heartbeat_detection.enabled) {
    setInterval(function() {
nanahira's avatar
nanahira committed
4836
      _async.each(ROOM_all, function(room, done) {
nanahira's avatar
nanahira committed
4837
        if (room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && (room.hostinfo.time_limit === 0 || room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING) && !room.windbot) {
nanahira's avatar
nanahira committed
4838
          return _async.each(room.get_playing_player(), function(player, _done) {
nanahira's avatar
nanahira committed
4839
            if (player && (room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING || player.selected_preduel)) {
nanahira's avatar
nanahira committed
4840 4841
              CLIENT_heartbeat_register(player, true);
            }
nanahira's avatar
nanahira committed
4842 4843 4844 4845
            return _done();
          }, done);
        } else {
          return done();
nanahira's avatar
nanahira committed
4846
        }
nanahira's avatar
nanahira committed
4847
      });
nanahira's avatar
nanahira committed
4848 4849 4850
    }, settings.modules.heartbeat_detection.interval);
  }

nanahira's avatar
nanahira committed
4851
  setInterval(function() {
nanahira's avatar
nanahira committed
4852
    var current_time;
nanahira's avatar
nanahira committed
4853
    current_time = moment();
nanahira's avatar
nanahira committed
4854 4855 4856 4857
    return _async.each(ROOM_all, function(room, done) {
      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) {
        room.auto_death_triggered = true;
        room.start_death();
nanahira's avatar
nanahira committed
4858
      }
nanahira's avatar
nanahira committed
4859 4860
      return done();
    });
nanahira's avatar
nanahira committed
4861 4862
  }, 1000);

nanahira's avatar
nanahira committed
4863
  // spawn windbot
nanahira's avatar
nanahira committed
4864 4865
  windbot_looplimit = 0;

nanahira's avatar
nanahira committed
4866
  windbot_process = global.windbot_process = null;
nanahira's avatar
nanahira committed
4867

nanahira's avatar
nanahira committed
4868
  spawn_windbot = global.spawn_windbot = function() {
nanahira's avatar
nanahira committed
4869
    var windbot_bin, windbot_parameters;
mercury233's avatar
mercury233 committed
4870 4871 4872 4873 4874 4875 4876 4877 4878 4879
    if (/^win/.test(process.platform)) {
      windbot_bin = 'WindBot.exe';
      windbot_parameters = [];
    } else {
      windbot_bin = 'mono';
      windbot_parameters = ['WindBot.exe'];
    }
    windbot_parameters.push('ServerMode=true');
    windbot_parameters.push('ServerPort=' + settings.modules.windbot.port);
    windbot_process = spawn(windbot_bin, windbot_parameters, {
mercury233's avatar
mercury233 committed
4880 4881 4882 4883
      cwd: 'windbot'
    });
    windbot_process.on('error', function(err) {
      log.warn('WindBot ERROR', err);
nanahira's avatar
nanahira committed
4884
      if (windbot_looplimit < 1000 && !global.rebooted) {
nanahira's avatar
nanahira committed
4885 4886 4887
        windbot_looplimit++;
        spawn_windbot();
      }
mercury233's avatar
mercury233 committed
4888 4889 4890
    });
    windbot_process.on('exit', function(code) {
      log.warn('WindBot EXIT', code);
nanahira's avatar
nanahira committed
4891
      if (windbot_looplimit < 1000 && !global.rebooted) {
nanahira's avatar
nanahira committed
4892 4893 4894
        windbot_looplimit++;
        spawn_windbot();
      }
mercury233's avatar
mercury233 committed
4895 4896 4897 4898 4899
    });
    windbot_process.stdout.setEncoding('utf8');
    windbot_process.stdout.on('data', function(data) {
      log.info('WindBot:', data);
    });
mercury233's avatar
fix  
mercury233 committed
4900
    windbot_process.stderr.setEncoding('utf8');
nanahira's avatar
nanahira committed
4901
    windbot_process.stderr.on('data', function(data) {
mercury233's avatar
mercury233 committed
4902 4903
      log.warn('WindBot Error:', data);
    });
nanahira's avatar
nanahira committed
4904 4905 4906 4907
  };

  if (settings.modules.windbot.enabled && settings.modules.windbot.spawn) {
    spawn_windbot();
mercury233's avatar
mercury233 committed
4908
  }
4909

nanahira's avatar
nanahira committed
4910
  global.rebooted = false;
nanahira's avatar
nanahira committed
4911

nanahira's avatar
nanahira committed
4912
  //http
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4913
  if (settings.modules.http) {
mercury233's avatar
mercury233 committed
4914 4915 4916 4917 4918 4919
    addCallback = function(callback, text) {
      if (!callback) {
        return text;
      }
      return callback + "( " + text + " );";
    };
nanahira's avatar
nanahira committed
4920
    requestListener = async function(request, response) {
nanahira's avatar
nanahira committed
4921
      var archive_args, archive_name, archive_process, check, death_room_found, duellog, err, error, filename, getpath, len3, n, parseQueryString, pass_validated, ref3, replay, roomsjson, u;
4922 4923
      parseQueryString = true;
      u = url.parse(request.url, parseQueryString);
nanahira's avatar
nanahira committed
4924 4925 4926
      //pass_validated = u.query.pass == settings.modules.http.password

      //console.log(u.query.username, u.query.pass)
4927
      if (u.pathname === '/api/getrooms') {
nanahira's avatar
nanahira committed
4928
        pass_validated = (await auth.auth(u.query.username, u.query.pass, "get_rooms", "get_rooms", true));
nanahira's avatar
fix  
nanahira committed
4929
        if (!settings.modules.http.public_roomlist && !pass_validated) {
4930
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4931
          response.end(addCallback(u.query.callback, '{"rooms":[{"roomid":"0","roomname":"密码错误","needpass":"true"}]}'));
4932
        } else {
nanahira's avatar
nanahira committed
4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945
          roomsjson = [];
          _async.each(ROOM_all, function(room, done) {
            var player;
            if (!(room && room.established)) {
              done();
              return;
            }
            roomsjson.push({
              roomid: room.process_pid.toString(),
              roomname: pass_validated ? room.name : room.name.split('$', 2)[0],
              roommode: room.hostinfo.mode,
              needpass: (room.name.indexOf('$') !== -1).toString(),
              users: _.sortBy((function() {
nanahira's avatar
nanahira committed
4946 4947
                var len3, n, ref3, results;
                ref3 = room.players;
nanahira's avatar
nanahira committed
4948
                results = [];
nanahira's avatar
nanahira committed
4949 4950
                for (n = 0, len3 = ref3.length; n < len3; n++) {
                  player = ref3[n];
nanahira's avatar
nanahira committed
4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963
                  if (player.pos != null) {
                    results.push({
                      id: (-1).toString(),
                      name: player.name,
                      ip: settings.modules.http.show_ip && pass_validated && !player.is_local ? player.ip.slice(7) : null,
                      status: settings.modules.http.show_info && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && player.pos !== 7 ? {
                        score: room.scores[player.name_vpass],
                        lp: player.lp != null ? player.lp : room.hostinfo.start_lp,
                        cards: room.hostinfo.mode !== 2 ? (player.card_count != null ? player.card_count : room.hostinfo.start_hand) : null
                      } : null,
                      pos: player.pos
                    });
                  }
4964
                }
nanahira's avatar
nanahira committed
4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975
                return results;
              })(), "pos"),
              istart: room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN ? (settings.modules.http.show_info ? "Duel:" + room.duel_count + " " + (room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING ? "Siding" : "Turn:" + (room.turn != null ? room.turn : 0) + (room.death ? "/" + (room.death > 0 ? room.death - 1 : "Death") : "")) : 'start') : 'wait'
            });
            return done();
          }, function() {
            response.writeHead(200);
            return response.end(addCallback(u.query.callback, JSON.stringify({
              rooms: roomsjson
            })));
          });
4976
        }
mercury233's avatar
mercury233 committed
4977
      } else if (u.pathname === '/api/duellog' && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4978
        if (!(await auth.auth(u.query.username, u.query.pass, "duel_log", "duel_log"))) {
mercury233's avatar
mercury233 committed
4979
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4980
          response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"));
mercury233's avatar
mercury233 committed
4981 4982 4983
          return;
        } else {
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4984
          duellog = JSON.stringify(duel_log.duel_log, null, 2);
mercury233's avatar
mercury233 committed
4985
          response.end(addCallback(u.query.callback, duellog));
mercury233's avatar
mercury233 committed
4986
        }
nanahira's avatar
nanahira committed
4987
      } else if (u.pathname === '/api/archive.zip' && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4988
        if (!(await auth.auth(u.query.username, u.query.pass, "download_replay", "download_replay_archive"))) {
nanahira's avatar
nanahira committed
4989 4990 4991 4992 4993
          response.writeHead(403);
          response.end("Invalid password.");
          return;
        } else {
          try {
nanahira's avatar
nanahira committed
4994
            archive_name = moment().format('YYYY-MM-DD HH-mm-ss') + ".zip";
nanahira's avatar
nanahira committed
4995
            archive_args = ["a", "-mx0", "-y", archive_name];
nanahira's avatar
fix  
nanahira committed
4996
            check = false;
nanahira's avatar
nanahira committed
4997 4998 4999
            ref3 = duel_log.duel_log;
            for (n = 0, len3 = ref3.length; n < len3; n++) {
              replay = ref3[n];
nanahira's avatar
fix  
nanahira committed
5000
              check = true;
nanahira's avatar
nanahira committed
5001 5002
              archive_args.push(replay.replay_filename);
            }
nanahira's avatar
fix  
nanahira committed
5003 5004 5005 5006 5007
            if (!check) {
              response.writeHead(403);
              response.end("Duel logs not found.");
              return;
            }
nanahira's avatar
nanahira committed
5008 5009 5010
            archive_process = spawn(settings.modules.tournament_mode.replay_archive_tool, archive_args, {
              cwd: settings.modules.tournament_mode.replay_path
            });
nanahira's avatar
nanahira committed
5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028
            archive_process.on('error', (err) => {
              response.writeHead(403);
              response.end("Failed packing replays. " + err);
            });
            archive_process.on('exit', (code) => {
              return fs.readFile(settings.modules.tournament_mode.replay_path + archive_name, function(error, buffer) {
                if (error) {
                  response.writeHead(403);
                  response.end("Failed sending replays. " + error);
                } else {
                  response.writeHead(200, {
                    "Content-Type": "application/octet-stream",
                    "Content-Disposition": "attachment"
                  });
                  response.end(buffer);
                }
              });
            });
nanahira's avatar
nanahira committed
5029
            archive_process.stdout.setEncoding('utf8');
nanahira's avatar
nanahira committed
5030 5031 5032
            archive_process.stdout.on('data', (data) => {
              return log.info("archive process: " + data);
            });
nanahira's avatar
nanahira committed
5033
            archive_process.stderr.setEncoding('utf8');
nanahira's avatar
nanahira committed
5034 5035 5036
            archive_process.stderr.on('data', (data) => {
              return log.warn("archive error: " + data);
            });
nanahira's avatar
nanahira committed
5037 5038 5039 5040 5041 5042
          } catch (error1) {
            error = error1;
            response.writeHead(403);
            response.end("Failed reading replays. " + error);
          }
        }
nanahira's avatar
nanahira committed
5043
      } else if (u.pathname === '/api/clearlog' && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
5044
        if (!(await auth.auth(u.query.username, u.query.pass, "clear_duel_log", "clear_duel_log"))) {
nanahira's avatar
nanahira committed
5045 5046 5047 5048 5049
          response.writeHead(200);
          response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"));
          return;
        } else {
          response.writeHead(200);
5050 5051 5052 5053 5054 5055 5056
          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(duel_log, null, 2), function(err) {
              if (err) {
                return log.warn('DUEL LOG SAVE ERROR', err);
              }
            });
          }
5057 5058
          duel_log.duel_log = [];
          setting_save(duel_log);
nanahira's avatar
nanahira committed
5059 5060
          response.end(addCallback(u.query.callback, "[{name:'Success'}]"));
        }
mercury233's avatar
mercury233 committed
5061
      } else if (_.startsWith(u.pathname, '/api/replay') && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
5062
        if (!(await auth.auth(u.query.username, u.query.pass, "download_replay", "download_replay"))) {
mercury233's avatar
mercury233 committed
5063 5064 5065 5066
          response.writeHead(403);
          response.end("密码错误");
          return;
        } else {
nanahira's avatar
nanahira committed
5067 5068 5069 5070 5071 5072 5073 5074 5075 5076
          getpath = null;
          filename = null;
          try {
            getpath = u.pathname.split("/");
            filename = path.basename(decodeURIComponent(getpath.pop()));
          } catch (error1) {
            response.writeHead(404);
            response.end("bad filename");
            return;
          }
mercury233's avatar
mercury233 committed
5077 5078 5079
          fs.readFile(settings.modules.tournament_mode.replay_path + filename, function(error, buffer) {
            if (error) {
              response.writeHead(404);
mercury233's avatar
fix  
mercury233 committed
5080
              response.end("未找到文件 " + filename);
mercury233's avatar
mercury233 committed
5081 5082 5083 5084 5085
            } else {
              response.writeHead(200, {
                "Content-Type": "application/octet-stream",
                "Content-Disposition": "attachment"
              });
mercury233's avatar
fix  
mercury233 committed
5086
              response.end(buffer);
mercury233's avatar
mercury233 committed
5087 5088 5089
            }
          });
        }
5090
      } else if (u.pathname === '/api/message') {
nanahira's avatar
nanahira committed
5091 5092 5093 5094
        //if !pass_validated
        //  response.writeHead(200)
        //  response.end(addCallback(u.query.callback, "['密码错误', 0]"))
        //  return
5095
        if (u.query.shout) {
nanahira's avatar
nanahira committed
5096
          if (!(await auth.auth(u.query.username, u.query.pass, "shout", "shout"))) {
nanahira's avatar
nanahira committed
5097 5098 5099 5100
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
5101
          _async.each(ROOM_all, function(room) {
5102
            if (room && room.established) {
nanahira's avatar
nanahira committed
5103
              return ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW);
5104
            }
nanahira's avatar
nanahira committed
5105
          });
5106
          response.writeHead(200);
mercury233's avatar
mercury233 committed
5107
          response.end(addCallback(u.query.callback, "['shout ok', '" + u.query.shout + "']"));
5108
        } else if (u.query.stop) {
nanahira's avatar
nanahira committed
5109
          if (!(await auth.auth(u.query.username, u.query.pass, "stop", "stop"))) {
nanahira's avatar
nanahira committed
5110 5111 5112 5113
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
5114 5115 5116
          if (u.query.stop === 'false') {
            u.query.stop = false;
          }
nanahira's avatar
nanahira committed
5117 5118
          response.writeHead(200);
          try {
nanahira's avatar
typo  
nanahira committed
5119
            await util.promisify(setting_change)(settings, 'modules:stop', u.query.stop);
nanahira's avatar
nanahira committed
5120 5121 5122 5123 5124
            response.end(addCallback(u.query.callback, "['stop ok', '" + u.query.stop + "']"));
          } catch (error1) {
            err = error1;
            response.end(addCallback(u.query.callback, "['stop fail', '" + u.query.stop + "']"));
          }
5125
        } else if (u.query.welcome) {
nanahira's avatar
nanahira committed
5126
          if (!(await auth.auth(u.query.username, u.query.pass, "change_settings", "change_welcome"))) {
nanahira's avatar
nanahira committed
5127 5128 5129 5130
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
5131
          try {
mercury233's avatar
mercury233 committed
5132
            await util.promisify(setting_change)(settings, 'modules:welcome', u.query.welcome);
nanahira's avatar
nanahira committed
5133 5134 5135 5136 5137
            response.end(addCallback(u.query.callback, "['welcome ok', '" + u.query.welcome + "']"));
          } catch (error1) {
            err = error1;
            response.end(addCallback(u.query.callback, "['welcome fail', '" + u.query.welcome + "']"));
          }
mercury233's avatar
mercury233 committed
5138
        } else if (u.query.getwelcome) {
nanahira's avatar
nanahira committed
5139
          if (!(await auth.auth(u.query.username, u.query.pass, "change_settings", "get_welcome"))) {
nanahira's avatar
nanahira committed
5140 5141 5142 5143
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
5144
          response.writeHead(200);
mercury233's avatar
mercury233 committed
5145
          response.end(addCallback(u.query.callback, "['get ok', '" + settings.modules.welcome + "']"));
mercury233's avatar
mercury233 committed
5146
        } else if (u.query.loadtips) {
nanahira's avatar
nanahira committed
5147
          if (!(await auth.auth(u.query.username, u.query.pass, "change_settings", "change_tips"))) {
nanahira's avatar
nanahira committed
5148 5149 5150 5151
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
5152 5153 5154
          load_tips(function(err) {
            response.writeHead(200);
            if (err) {
nanahira's avatar
nanahira committed
5155
              return response.end(addCallback(u.query.callback, "['tip fail', '" + settings.modules.tips.get + "']"));
nanahira's avatar
nanahira committed
5156
            } else {
nanahira's avatar
nanahira committed
5157
              return response.end(addCallback(u.query.callback, "['tip ok', '" + settings.modules.tips.get + "']"));
nanahira's avatar
nanahira committed
5158 5159
            }
          });
mercury233's avatar
mercury233 committed
5160
        } else if (u.query.loaddialogues) {
nanahira's avatar
nanahira committed
5161
          if (!(await auth.auth(u.query.username, u.query.pass, "change_settings", "change_dialogues"))) {
nanahira's avatar
nanahira committed
5162 5163 5164 5165
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
5166 5167 5168
          load_dialogues(function(err) {
            response.writeHead(200);
            if (err) {
nanahira's avatar
nanahira committed
5169
              return response.end(addCallback(u.query.callback, "['dialogues fail', '" + settings.modules.dialogues.get + "']"));
nanahira's avatar
nanahira committed
5170
            } else {
nanahira's avatar
nanahira committed
5171
              return response.end(addCallback(u.query.callback, "['dialogues ok', '" + settings.modules.dialogues.get + "']"));
nanahira's avatar
nanahira committed
5172 5173
            }
          });
mercury233's avatar
mercury233 committed
5174
        } else if (u.query.ban) {
nanahira's avatar
nanahira committed
5175
          if (!(await auth.auth(u.query.username, u.query.pass, "ban_user", "ban_user"))) {
nanahira's avatar
nanahira committed
5176 5177 5178 5179
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
5180 5181 5182 5183 5184 5185 5186 5187
          ban_user(u.query.ban, function(err) {
            response.writeHead(200);
            if (err) {
              return response.end(addCallback(u.query.callback, "['ban fail', '" + u.query.ban + "']"));
            } else {
              return response.end(addCallback(u.query.callback, "['ban ok', '" + u.query.ban + "']"));
            }
          });
nanahira's avatar
nanahira committed
5188
        } else if (u.query.kick) {
nanahira's avatar
nanahira committed
5189
          if (!(await auth.auth(u.query.username, u.query.pass, "kick_user", "kick_user"))) {
nanahira's avatar
nanahira committed
5190 5191 5192 5193
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
5194 5195 5196 5197 5198 5199 5200 5201
          ROOM_kick(u.query.kick, function(err, found) {
            response.writeHead(200);
            if (err) {
              return response.end(addCallback(u.query.callback, "['kick fail', '" + u.query.kick + "']"));
            } else if (found) {
              return response.end(addCallback(u.query.callback, "['kick ok', '" + u.query.kick + "']"));
            } else {
              return response.end(addCallback(u.query.callback, "['room not found', '" + u.query.kick + "']"));
nanahira's avatar
nanahira committed
5202
            }
nanahira's avatar
nanahira committed
5203
          });
nanahira's avatar
nanahira committed
5204
        } else if (u.query.death) {
nanahira's avatar
nanahira committed
5205
          if (!(await auth.auth(u.query.username, u.query.pass, "start_death", "start_death"))) {
nanahira's avatar
nanahira committed
5206 5207 5208 5209
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
5210
          death_room_found = false;
nanahira's avatar
nanahira committed
5211 5212 5213 5214 5215
          _async.each(ROOM_all, function(room, done) {
            if (!(room && (u.query.death === "all" || u.query.death === room.process_pid.toString() || u.query.death === room.name))) {
              done();
              return;
            }
nanahira's avatar
nanahira committed
5216 5217
            if (room.start_death()) {
              death_room_found = true;
nanahira's avatar
nanahira committed
5218
            }
nanahira's avatar
nanahira committed
5219
            done();
nanahira's avatar
nanahira committed
5220 5221 5222 5223 5224 5225 5226 5227
          }, function() {
            response.writeHead(200);
            if (death_room_found) {
              return response.end(addCallback(u.query.callback, "['death ok', '" + u.query.death + "']"));
            } else {
              return response.end(addCallback(u.query.callback, "['room not found', '" + u.query.death + "']"));
            }
          });
nanahira's avatar
nanahira committed
5228
        } else if (u.query.deathcancel) {
nanahira's avatar
nanahira committed
5229
          if (!(await auth.auth(u.query.username, u.query.pass, "start_death", "cancel_death"))) {
nanahira's avatar
nanahira committed
5230 5231 5232 5233
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
5234
          death_room_found = false;
nanahira's avatar
nanahira committed
5235
          _async.each(rooms, function(room, done) {
nanahira's avatar
nanahira committed
5236 5237 5238 5239
            if (!(room && (u.query.deathcancel === "all" || u.query.deathcancel === room.process_pid.toString() || u.query.deathcancel === room.name))) {
              done();
              return;
            }
nanahira's avatar
nanahira committed
5240 5241
            if (room.cancel_death()) {
              death_room_found = true;
nanahira's avatar
nanahira committed
5242
            }
nanahira's avatar
nanahira committed
5243 5244 5245 5246 5247 5248 5249 5250 5251
            return done();
          }, function() {
            response.writeHead(200);
            if (death_room_found) {
              return response.end(addCallback(u.query.callback, "['death cancel ok', '" + u.query.deathcancel + "']"));
            } else {
              return response.end(addCallback(u.query.callback, "['room not found', '" + u.query.deathcancel + "']"));
            }
          });
nanahira's avatar
nanahira committed
5252
        } else if (u.query.reboot) {
nanahira's avatar
nanahira committed
5253
          if (!(await auth.auth(u.query.username, u.query.pass, "stop", "reboot"))) {
nanahira's avatar
nanahira committed
5254 5255 5256 5257
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
5258 5259 5260 5261
          ROOM_kick("all", function(err, found) {
            global.rebooted = true;
            if (windbot_process) {
              windbot_process.kill();
nanahira's avatar
nanahira committed
5262
            }
nanahira's avatar
nanahira committed
5263 5264 5265 5266
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['reboot ok', '" + u.query.reboot + "']"));
            return process.exit();
          });
5267
        } else {
mercury233's avatar
mercury233 committed
5268
          response.writeHead(400);
5269
          response.end();
5270
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
5271
      } else {
mercury233's avatar
mercury233 committed
5272
        response.writeHead(400);
mercury233's avatar
test3  
mercury233 committed
5273
        response.end();
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
5274
      }
5275 5276
    };
    http_server = http.createServer(requestListener);
神楽坂玲奈's avatar
神楽坂玲奈 committed
5277
    http_server.listen(settings.modules.http.port);
mercury233's avatar
mercury233 committed
5278
    if (settings.modules.http.ssl.enabled) {
5279 5280 5281 5282 5283 5284
      https = require('https');
      options = {
        cert: fs.readFileSync(settings.modules.http.ssl.cert),
        key: fs.readFileSync(settings.modules.http.ssl.key)
      };
      https_server = https.createServer(options, requestListener);
nanahira's avatar
fix  
nanahira committed
5285 5286 5287
      if (settings.modules.http.websocket_roomlist && roomlist) {
        roomlist.init(https_server, ROOM_all);
      }
5288 5289
      https_server.listen(settings.modules.http.ssl.port);
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
5290
  }
神楽坂玲奈's avatar
神楽坂玲奈 committed
5291

nanahira's avatar
nanahira committed
5292 5293 5294 5295 5296 5297
  if (!fs.existsSync('./plugins')) {
    fs.mkdirSync('./plugins');
  }

  plugin_list = fs.readdirSync("./plugins");

nanahira's avatar
nanahira committed
5298 5299
  for (n = 0, len3 = plugin_list.length; n < len3; n++) {
    plugin_filename = plugin_list[n];
nanahira's avatar
nanahira committed
5300
    plugin_path = process.cwd() + "/plugins/" + plugin_filename;
nanahira's avatar
nanahira committed
5301
    require(plugin_path);
nanahira's avatar
nanahira committed
5302
    log.info("Plugin loaded:", plugin_filename);
nanahira's avatar
nanahira committed
5303 5304
  }

神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
5305
}).call(this);