ygopro-server.js 83.3 KB
Newer Older
mercury233's avatar
mercury233 committed
1
// Generated by CoffeeScript 1.12.2
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2
(function() {
mercury233's avatar
mercury233 committed
3
  var Cloud_replay_ids, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_port, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_players_banned, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, Room, _, addCallback, ban_user, bunyan, cppversion, crypto, date, defaultconfig, execFile, fs, geoip, get_memory_usage, http, http_server, https, https_server, list, load_dialogues, load_tips, log, moment, nconf, net, options, os, path, pgClient, pg_client, pg_query, redis, redisdb, request, requestListener, roomlist, settings, spawn, spawnSync, url, users_cache, wait_room_start, windbot_process, ygopro, zlib;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
4

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

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

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

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

  fs = require('fs');

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

17 18
  crypto = require('crypto');

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

mercury233's avatar
mercury233 committed
21 22 23 24
  spawn = require('child_process').spawn;

  spawnSync = require('child_process').spawnSync;

神楽坂玲奈's avatar
神楽坂玲奈 committed
25 26
  _ = require('underscore');

神楽坂玲奈's avatar
tip  
神楽坂玲奈 committed
27 28 29 30 31 32
  _.str = require('underscore.string');

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

  request = require('request');

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

mercury233's avatar
mercury233 committed
35 36 37 38
  log = bunyan.createLogger({
    name: "mycard"
  });

39 40
  moment = require('moment');

mercury233's avatar
mercury233 committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
  moment.locale('zh-cn', {
    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年'
    }
  });

mercury233's avatar
mercury233 committed
59 60
  nconf = require('nconf');

mercury233's avatar
mercury233 committed
61
  nconf.file('./config.user.json');
mercury233's avatar
mercury233 committed
62 63 64 65 66 67 68 69 70 71

  defaultconfig = require('./config.json');

  nconf.defaults(defaultconfig);

  settings = global.settings = nconf.get();

  nconf.myset = function(settings, path, val) {
    var key, target;
    nconf.set(path, val);
mercury233's avatar
mercury233 committed
72 73 74 75
    nconf.save();
    if (_.isString(val)) {
      log.info("setting changed", path, val);
    }
mercury233's avatar
mercury233 committed
76 77 78 79 80 81 82 83 84 85 86 87 88
    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;
    }
  };
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
89

90
  try {
mercury233's avatar
mercury233 committed
91 92
    cppversion = parseInt(fs.readFileSync('ygopro/gframe/game.cpp', 'utf8').match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16');
    nconf.myset(settings, "version", cppversion);
mercury233's avatar
fix  
mercury233 committed
93
    log.info("ygopro version 0x" + settings.version.toString(16), "(from source code)");
94
  } catch (error1) {
mercury233's avatar
fix  
mercury233 committed
95
    log.info("ygopro version 0x" + settings.version.toString(16), "(from config)");
96
  }
97

神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
98
  settings.lflist = (function() {
mercury233's avatar
mercury233 committed
99
    var j, len, ref, results;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
100
    ref = fs.readFileSync('ygopro/lflist.conf', 'utf8').match(/!.*/g);
神楽坂玲奈's avatar
神楽坂玲奈 committed
101
    results = [];
mercury233's avatar
mercury233 committed
102 103
    for (j = 0, len = ref.length; j < len; j++) {
      list = ref[j];
mercury233's avatar
mercury233 committed
104 105 106 107
      date = list.match(/!([\d\.]+)/);
      if (!date) {
        continue;
      }
神楽坂玲奈's avatar
神楽坂玲奈 committed
108
      results.push({
神楽坂玲奈's avatar
神楽坂玲奈 committed
109
        date: moment(list.match(/!([\d\.]+)/)[1], 'YYYY.MM.DD').utcOffset("-08:00"),
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
110
        tcg: list.indexOf('TCG') !== -1
神楽坂玲奈's avatar
神楽坂玲奈 committed
111 112 113 114 115
      });
    }
    return results;
  })();

mercury233's avatar
mercury233 committed
116
  if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
117 118 119 120
    redis = require('redis');
    zlib = require('zlib');
    redisdb = redis.createClient({
      host: "127.0.0.1",
mercury233's avatar
mercury233 committed
121
      port: settings.modules.cloud_replay.redis_port
mercury233's avatar
mercury233 committed
122
    });
mercury233's avatar
mercury233 committed
123 124 125
    redisdb.on('error', function(err) {
      log.warn(err);
    });
mercury233's avatar
mercury233 committed
126 127
  }

mercury233's avatar
mercury233 committed
128 129
  if (settings.modules.windbot.enabled) {
    settings.modules.windbots = require(settings.modules.windbot.botlist).windbots;
mercury233's avatar
mercury233 committed
130 131
  }

神楽坂玲奈's avatar
神楽坂玲奈 committed
132
  ygopro = require('./ygopro.js');
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
133

mercury233's avatar
mercury233 committed
134
  if (settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
135 136
    roomlist = require('./roomlist.js');
  }
神楽坂玲奈's avatar
神楽坂玲奈 committed
137

mercury233's avatar
mercury233 committed
138 139 140 141
  if (settings.modules.i18n.auto_pick) {
    geoip = require('geoip-country-lite');
  }

神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
142 143
  users_cache = {};

mercury233's avatar
mercury233 committed
144
  if (settings.modules.mycard.enabled) {
mercury233's avatar
merge  
mercury233 committed
145
    pgClient = require('pg').Client;
mercury233's avatar
mercury233 committed
146
    pg_client = new pgClient(settings.modules.mycard.auth_database);
mercury233's avatar
fix  
mercury233 committed
147 148 149
    pg_client.on('error', function(err) {
      log.warn("PostgreSQL ERROR: ", err);
    });
mercury233's avatar
merge  
mercury233 committed
150
    pg_query = pg_client.query('SELECT username, id from users');
mercury233's avatar
fix  
mercury233 committed
151 152 153
    pg_query.on('error', function(err) {
      log.warn("PostgreSQL Query ERROR: ", err);
    });
mercury233's avatar
merge  
mercury233 committed
154 155 156 157 158 159 160 161 162 163 164
    pg_query.on('row', function(row) {
      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();
  }

mercury233's avatar
mercury233 committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
  get_memory_usage = function() {
    var actualFree, buffers, cached, free, line, lines, percentUsed, prc_free, total;
    prc_free = spawnSync("free", []);
    if (prc_free.stdout) {
      lines = prc_free.stdout.toString().split(/\n/g);
      line = lines[1].split(/\s+/);
      total = parseInt(line[1], 10);
      free = parseInt(line[3], 10);
      buffers = parseInt(line[5], 10);
      cached = parseInt(line[6], 10);
      actualFree = free + buffers + cached;
      percentUsed = parseFloat(((1 - (actualFree / total)) * 100).toFixed(2));
    } else {
      percentUsed = 0;
    }
    return percentUsed;
  };

mercury233's avatar
mercury233 committed
183 184
  Cloud_replay_ids = [];

mercury233's avatar
mercury233 committed
185 186 187 188 189 190
  ROOM_all = [];

  ROOM_players_oppentlist = {};

  ROOM_players_banned = [];

mercury233's avatar
mercury233 committed
191 192 193 194
  ROOM_connected_ip = {};

  ROOM_bad_ip = {};

mercury233's avatar
mercury233 committed
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
  ban_user = function(name) {
    var bad_ip, j, k, len, len1, player, ref, room;
    settings.ban.banned_user.push(name);
    nconf.myset(settings, "ban:banned_user", settings.ban.banned_user);
    bad_ip = 0;
    for (j = 0, len = ROOM_all.length; j < len; j++) {
      room = ROOM_all[j];
      if (room && room.established) {
        ref = room.players;
        for (k = 0, len1 = ref.length; k < len1; k++) {
          player = ref[k];
          if (player && (player.name === name || player.ip === bad_ip)) {
            bad_ip = player.ip;
            ROOM_bad_ip[bad_ip] = 99;
            settings.ban.banned_ip.push(player.ip);
            ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
            player.destroy();
            continue;
          }
        }
      }
    }
  };

mercury233's avatar
mercury233 committed
219
  ROOM_ban_player = function(name, ip, reason, countadd) {
mercury233's avatar
mercury233 committed
220
    var bannedplayer, bantime;
mercury233's avatar
mercury233 committed
221 222 223
    if (countadd == null) {
      countadd = 1;
    }
mercury233's avatar
mercury233 committed
224 225 226 227
    bannedplayer = _.find(ROOM_players_banned, function(bannedplayer) {
      return ip === bannedplayer.ip;
    });
    if (bannedplayer) {
mercury233's avatar
mercury233 committed
228
      bannedplayer.count = bannedplayer.count + countadd;
mercury233's avatar
mercury233 committed
229 230 231 232 233 234 235 236 237 238 239 240
      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
241
        "count": countadd,
mercury233's avatar
mercury233 committed
242 243 244 245 246 247 248 249
        "reasons": [reason],
        "need_tip": true
      };
      ROOM_players_banned.push(bannedplayer);
    }
  };

  ROOM_find_or_create_by_name = function(name, player_ip) {
mercury233's avatar
mercury233 committed
250 251
    var room, uname;
    uname = name.toUpperCase();
mercury233's avatar
mercury233 committed
252
    if (settings.modules.windbot.enabled && (uname.slice(0, 2) === 'AI' || (!settings.modules.random_duel.enabled && uname === ''))) {
mercury233's avatar
mercury233 committed
253 254
      return ROOM_find_or_create_ai(name);
    }
mercury233's avatar
mercury233 committed
255
    if (settings.modules.random_duel.enabled && (uname === '' || uname === 'S' || uname === 'M' || uname === 'T')) {
mercury233's avatar
mercury233 committed
256
      return ROOM_find_or_create_random(uname, player_ip);
mercury233's avatar
mercury233 committed
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    }
    if (room = ROOM_find_by_name(name)) {
      return room;
    } else if (get_memory_usage() >= 90) {
      return null;
    } else {
      return new Room(name);
    }
  };

  ROOM_find_or_create_random = function(type, player_ip) {
    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 {
mercury233's avatar
mercury233 committed
275
          "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
276 277 278 279 280
        };
      }
      if (bannedplayer.count > 3 && moment() < bannedplayer.time && bannedplayer.need_tip) {
        bannedplayer.need_tip = false;
        return {
mercury233's avatar
mercury233 committed
281
          "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
282 283 284 285
        };
      } else if (bannedplayer.need_tip) {
        bannedplayer.need_tip = false;
        return {
mercury233's avatar
mercury233 committed
286
          "error": "${random_warn_part1}" + (bannedplayer.reasons.join('${random_ban_reason_separator}')) + "${random_warn_part2}"
mercury233's avatar
mercury233 committed
287 288 289 290 291 292 293 294
        };
      } 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) {
mercury233's avatar
mercury233 committed
295
      return room && room.random_type !== '' && !room.started && ((type === '' && room.random_type !== 'T') || room.random_type === type) && room.get_playing_player().length < max_player && (room.get_host() === null || room.get_host().ip !== ROOM_players_oppentlist[player_ip]) && (playerbanned === room.deprecated);
mercury233's avatar
mercury233 committed
296 297
    });
    if (result) {
mercury233's avatar
mercury233 committed
298
      result.welcome = '${random_duel_enter_room_waiting}';
mercury233's avatar
mercury233 committed
299
    } else if (get_memory_usage() < 90) {
mercury233's avatar
mercury233 committed
300 301 302 303 304
      type = type ? type : 'S';
      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
305
      result.welcome = '${random_duel_enter_room_new}';
mercury233's avatar
mercury233 committed
306
      result.deprecated = playerbanned;
mercury233's avatar
mercury233 committed
307 308
    } else {
      return null;
mercury233's avatar
mercury233 committed
309 310
    }
    if (result.random_type === 'M') {
mercury233's avatar
mercury233 committed
311
      result.welcome = result.welcome + '\n${random_duel_enter_room_match}';
mercury233's avatar
mercury233 committed
312 313 314 315
    }
    return result;
  };

mercury233's avatar
mercury233 committed
316
  ROOM_find_or_create_ai = function(name) {
mercury233's avatar
mercury233 committed
317
    var ainame, namea, result, room, windbot;
mercury233's avatar
mercury233 committed
318 319 320
    if (name === '') {
      name = 'AI';
    }
mercury233's avatar
mercury233 committed
321
    namea = name.split('#');
mercury233's avatar
mercury233 committed
322 323 324 325 326
    if (room = ROOM_find_by_name(name)) {
      return room;
    } else if (name === 'AI') {
      windbot = _.sample(settings.modules.windbots);
      name = 'AI#' + Math.floor(Math.random() * 100000);
mercury233's avatar
mercury233 committed
327 328
    } else if (namea.length > 1) {
      ainame = namea[namea.length - 1];
mercury233's avatar
mercury233 committed
329 330 331 332 333
      windbot = _.sample(_.filter(settings.modules.windbots, function(w) {
        return w.name === ainame || w.deck === ainame;
      }));
      if (!windbot) {
        return {
mercury233's avatar
mercury233 committed
334
          "error": "${windbot_deck_not_found}"
mercury233's avatar
mercury233 committed
335 336 337 338 339 340 341
        };
      }
      name = name + ',' + Math.floor(Math.random() * 100000);
    } else {
      windbot = _.sample(settings.modules.windbots);
      name = name + '#' + Math.floor(Math.random() * 100000);
    }
mercury233's avatar
mercury233 committed
342 343 344
    if (name.replace(/[^\x00-\xff]/g, "00").length > 20) {
      log.info("long ai name", name);
      return {
mercury233's avatar
mercury233 committed
345
        "error": "${windbot_name_too_long}"
mercury233's avatar
mercury233 committed
346 347
      };
    }
mercury233's avatar
mercury233 committed
348 349
    result = new Room(name);
    result.windbot = windbot;
mercury233's avatar
merge  
mercury233 committed
350
    result["private"] = true;
mercury233's avatar
mercury233 committed
351 352 353
    return result;
  };

mercury233's avatar
mercury233 committed
354 355 356
  ROOM_find_by_name = function(name) {
    var result;
    result = _.find(ROOM_all, function(room) {
357
      return room && room.name === name;
mercury233's avatar
mercury233 committed
358 359 360 361 362 363
    });
    return result;
  };

  ROOM_find_by_port = function(port) {
    return _.find(ROOM_all, function(room) {
364
      return room && room.port === port;
mercury233's avatar
mercury233 committed
365 366 367 368 369 370 371 372 373 374 375 376 377
    });
  };

  ROOM_validate = function(name) {
    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;
378 379 380
      if (!room) {
        return false;
      }
mercury233's avatar
mercury233 committed
381 382 383 384 385 386 387
      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;
    });
  };

mercury233's avatar
mercury233 committed
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
  ROOM_unwelcome = function(room, bad_player, reason) {
    var j, len, player, ref;
    if (!room) {
      return;
    }
    ref = room.players;
    for (j = 0, len = ref.length; j < len; j++) {
      player = ref[j];
      if (player && player === bad_player) {
        ygopro.stoc_send_chat(player, "${unwelcome_warn_part1}" + reason + "${unwelcome_warn_part2}", ygopro.constants.COLORS.RED);
      } else if (player && player.pos !== 7 && player !== bad_player) {
        player.flee_free = true;
        ygopro.stoc_send_chat(player, "${unwelcome_tip_part1}" + reason + "${unwelcome_tip_part2}", ygopro.constants.COLORS.BABYBLUE);
      }
    }
  };

mercury233's avatar
mercury233 committed
405 406
  Room = (function() {
    function Room(name, hostinfo) {
mercury233's avatar
mercury233 committed
407
      var draw_count, lflist, param, rule, start_hand, start_lp, time_limit;
mercury233's avatar
mercury233 committed
408 409 410 411 412 413 414 415 416 417
      this.hostinfo = hostinfo;
      this.name = name;
      this.alive = true;
      this.players = [];
      this.player_datas = [];
      this.status = 'starting';
      this.started = false;
      this.established = false;
      this.watcher_buffers = [];
      this.recorder_buffers = [];
418
      this.cloud_replay_id = Math.floor(Math.random() * 100000000);
mercury233's avatar
mercury233 committed
419 420 421
      this.watchers = [];
      this.random_type = '';
      this.welcome = '';
mercury233's avatar
mercury233 committed
422
      this.scores = {};
mercury233's avatar
mercury233 committed
423
      ROOM_all.push(this);
mercury233's avatar
fix  
mercury233 committed
424
      this.hostinfo || (this.hostinfo = JSON.parse(JSON.stringify(settings.hostinfo)));
425 426 427 428 429 430 431 432 433
      if (settings.lflist.length) {
        if (this.hostinfo.rule === 1 && this.hostinfo.lflist === 0) {
          this.hostinfo.lflist = _.findIndex(settings.lflist, function(list) {
            return list.tcg;
          });
        }
      } else {
        this.hostinfo.lflist = -1;
      }
mercury233's avatar
mercury233 committed
434
      this.hostinfo.replay_mode = settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe ? 1 : 0;
mercury233's avatar
mercury233 committed
435 436 437 438 439
      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
440 441 442
      } else if (name.slice(0, 3) === 'AI#') {
        this.hostinfo.rule = 2;
        this.hostinfo.lflist = -1;
mercury233's avatar
mercury233 committed
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
      } 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]);
        this.hostinfo.enable_priority = param[3] === 'T';
        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;
          this.hostinfo.lflist = _.findIndex(settings.lflist, function(list) {
mercury233's avatar
mercury233 committed
464
            return list.tcg;
mercury233's avatar
mercury233 committed
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
          });
        }
        if (rule.match(/(^|,|,)(OCGONLY|OO)(,|,|$)/)) {
          this.hostinfo.rule = 0;
        }
        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;
        }
        if (rule.match(/(^|,|,)(IGPRIORITY|PR)(,|,|$)/)) {
          this.hostinfo.enable_priority = true;
        }
      }
mercury233's avatar
mercury233 committed
533
      param = [0, this.hostinfo.lflist, this.hostinfo.rule, this.hostinfo.mode, (this.hostinfo.enable_priority ? 'T' : 'F'), (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];
mercury233's avatar
mercury233 committed
534 535
      try {
        this.process = spawn('./ygopro', param, {
mercury233's avatar
mercury233 committed
536
          cwd: 'ygopro'
mercury233's avatar
mercury233 committed
537
        });
mercury233's avatar
fix  
mercury233 committed
538 539 540
        this.process.on('error', (function(_this) {
          return function(err) {
            _.each(_this.players, function(player) {
mercury233's avatar
mercury233 committed
541
              return ygopro.stoc_die(player, "${create_room_failed}");
mercury233's avatar
fix  
mercury233 committed
542 543 544 545
            });
            _this["delete"]();
          };
        })(this));
mercury233's avatar
mercury233 committed
546 547 548 549 550 551 552 553 554 555 556 557
        this.process.on('exit', (function(_this) {
          return function(code) {
            if (!_this.disconnector) {
              _this.disconnector = 'server';
            }
            _this["delete"]();
          };
        })(this));
        this.process.stdout.setEncoding('utf8');
        this.process.stdout.once('data', (function(_this) {
          return function(data) {
            _this.established = true;
mercury233's avatar
mercury233 committed
558
            if (!_this.windbot && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
559 560 561 562 563
              roomlist.create(_this);
            }
            _this.port = parseInt(data);
            _.each(_this.players, function(player) {
              player.server.connect(_this.port, '127.0.0.1', function() {
mercury233's avatar
mercury233 committed
564
                var buffer, j, len, ref;
mercury233's avatar
mercury233 committed
565
                ref = player.pre_establish_buffers;
mercury233's avatar
mercury233 committed
566 567
                for (j = 0, len = ref.length; j < len; j++) {
                  buffer = ref[j];
mercury233's avatar
mercury233 committed
568 569 570 571 572 573 574
                  player.server.write(buffer);
                }
                player.established = true;
                player.pre_establish_buffers = [];
              });
            });
            if (_this.windbot) {
mercury233's avatar
mercury233 committed
575 576 577
              setTimeout(function() {
                return _this.add_windbot(_this.windbot);
              }, 200);
mercury233's avatar
mercury233 committed
578 579 580
            }
          };
        })(this));
mercury233's avatar
mercury233 committed
581 582
        this.process.stderr.on('data', (function(_this) {
          return function(data) {
mercury233's avatar
mercury233 committed
583 584 585 586
            data = "Debug: " + data;
            data = data.replace(/\n$/, "");
            log.info("YGOPRO " + data);
            ygopro.stoc_send_chat_to_room(_this, data, ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
587 588 589
            _this.has_ygopro_error = true;
          };
        })(this));
mercury233's avatar
mercury233 committed
590
      } catch (error1) {
mercury233's avatar
mercury233 committed
591
        this.error = "${create_room_failed}";
mercury233's avatar
mercury233 committed
592 593 594 595
      }
    }

    Room.prototype["delete"] = function() {
mercury233's avatar
mercury233 committed
596
      var index, log_rep_id, name, player_ips, player_names, recorder_buffer, ref, replay_id, score, score_array;
mercury233's avatar
mercury233 committed
597 598 599
      if (this.deleted) {
        return;
      }
600
      if (this.started && settings.modules.arena_mode.enabled && this.arena) {
mercury233's avatar
mercury233 committed
601 602 603 604 605 606 607 608 609
        score_array = [];
        ref = this.scores;
        for (name in ref) {
          score = ref[name];
          score_array.push({
            name: name,
            score: score
          });
        }
mercury233's avatar
merge  
mercury233 committed
610 611 612 613
        if (score_array.length === 2) {
          request.post({
            url: settings.modules.arena_mode.post_score,
            form: {
mercury233's avatar
mercury233 committed
614
              accesskey: settings.modules.arena_mode.accesskey,
mercury233's avatar
merge  
mercury233 committed
615 616 617 618 619 620
              usernameA: score_array[0].name,
              usernameB: score_array[1].name,
              userscoreA: score_array[0].score,
              userscoreB: score_array[1].score,
              start: this.start_time,
              end: moment().format(),
mercury233's avatar
mercury233 committed
621
              arena: this.arena
mercury233's avatar
merge  
mercury233 committed
622 623 624 625
            }
          }, (function(_this) {
            return function(error, response, body) {
              if (error) {
mercury233's avatar
merge  
mercury233 committed
626
                log.warn('SCORE POST ERROR', error);
mercury233's avatar
mercury233 committed
627
              } else {
mercury233's avatar
fix  
mercury233 committed
628
                if (response.statusCode !== 204 && response.statusCode !== 200) {
mercury233's avatar
merge  
mercury233 committed
629 630
                  log.warn('SCORE POST FAIL', response.statusCode, response.statusMessage, _this.name, body);
                }
mercury233's avatar
mercury233 committed
631
              }
mercury233's avatar
merge  
mercury233 committed
632 633 634
            };
          })(this));
        }
mercury233's avatar
mercury233 committed
635
      }
mercury233's avatar
mercury233 committed
636
      if (this.player_datas.length && settings.modules.cloud_replay.enabled) {
637
        replay_id = this.cloud_replay_id;
mercury233's avatar
mercury233 committed
638 639 640
        if (this.has_ygopro_error) {
          log_rep_id = true;
        }
mercury233's avatar
mercury233 committed
641 642 643 644 645 646 647
        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) {
          player_ips.push(player.ip);
        });
        recorder_buffer = Buffer.concat(this.recorder_buffers);
        zlib.deflate(recorder_buffer, function(err, replay_buffer) {
648
          var date_time, recorded_ip;
mercury233's avatar
mercury233 committed
649 650 651
          replay_buffer = replay_buffer.toString('binary');
          date_time = moment().format('YYYY-MM-DD HH:mm:ss');
          redisdb.hmset("replay:" + replay_id, "replay_id", replay_id, "replay_buffer", replay_buffer, "player_names", player_names, "date_time", date_time);
mercury233's avatar
mercury233 committed
652 653 654
          if (!log_rep_id) {
            redisdb.expire("replay:" + replay_id, 60 * 60 * 24);
          }
mercury233's avatar
mercury233 committed
655 656 657 658 659 660 661 662
          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
663
          if (log_rep_id) {
mercury233's avatar
mercury233 committed
664 665
            log.info("error replay: R#" + replay_id);
          }
mercury233's avatar
mercury233 committed
666 667 668 669 670 671
        });
      }
      this.watcher_buffers = [];
      this.recorder_buffers = [];
      this.players = [];
      if (this.watcher) {
mercury233's avatar
mercury233 committed
672
        this.watcher.destroy();
mercury233's avatar
mercury233 committed
673
      }
mercury233's avatar
fix  
mercury233 committed
674 675 676
      if (this.recorder) {
        this.recorder.destroy();
      }
mercury233's avatar
mercury233 committed
677 678 679
      this.deleted = true;
      index = _.indexOf(ROOM_all, this);
      if (index !== -1) {
680
        ROOM_all[index] = null;
mercury233's avatar
mercury233 committed
681
      }
mercury233's avatar
mercury233 committed
682
      if (!this.windbot && this.established && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
683
        roomlist["delete"](this);
mercury233's avatar
mercury233 committed
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
      }
    };

    Room.prototype.get_playing_player = function() {
      var playing_player;
      playing_player = [];
      _.each(this.players, function(player) {
        if (player.pos < 4) {
          playing_player.push(player);
        }
      });
      return playing_player;
    };

    Room.prototype.get_host = function() {
      var host_player;
      host_player = null;
      _.each(this.players, function(player) {
        if (player.is_host) {
          host_player = player;
        }
      });
      return host_player;
    };

mercury233's avatar
mercury233 committed
709 710 711
    Room.prototype.add_windbot = function(botdata) {
      this.windbot = botdata;
      request({
mercury233's avatar
mercury233 committed
712
        url: "http://127.0.0.1:" + settings.modules.windbot.port + "/?name=" + (encodeURIComponent(botdata.name)) + "&deck=" + (encodeURIComponent(botdata.deck)) + "&host=127.0.0.1&port=" + settings.port + "&dialog=" + (encodeURIComponent(botdata.dialog)) + "&version=" + settings.version + "&password=" + (encodeURIComponent(this.name))
mercury233's avatar
mercury233 committed
713 714 715
      }, (function(_this) {
        return function(error, response, body) {
          if (error) {
mercury233's avatar
merge  
mercury233 committed
716
            log.warn('windbot add error', error, _this.name);
mercury233's avatar
mercury233 committed
717
            ygopro.stoc_send_chat_to_room(_this, "${add_windbot_failed}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
718 719 720 721 722
          }
        };
      })(this));
    };

mercury233's avatar
mercury233 committed
723
    Room.prototype.connect = function(client) {
mercury233's avatar
mercury233 committed
724
      var host_player;
mercury233's avatar
mercury233 committed
725 726
      this.players.push(client);
      if (this.random_type) {
mercury233's avatar
mercury233 committed
727
        client.abuse_count = 0;
mercury233's avatar
mercury233 committed
728 729
        host_player = this.get_host();
        if (host_player && (host_player !== client)) {
mercury233's avatar
mercury233 committed
730 731
          ROOM_players_oppentlist[host_player.ip] = client.ip;
          ROOM_players_oppentlist[client.ip] = host_player.ip;
mercury233's avatar
mercury233 committed
732
        } else {
mercury233's avatar
mercury233 committed
733
          ROOM_players_oppentlist[client.ip] = null;
mercury233's avatar
mercury233 committed
734 735 736
        }
      }
      if (this.established) {
mercury233's avatar
mercury233 committed
737
        if (!this.windbot && !this.started && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
738 739 740
          roomlist.update(this);
        }
        client.server.connect(this.port, '127.0.0.1', function() {
mercury233's avatar
mercury233 committed
741
          var buffer, j, len, ref;
mercury233's avatar
mercury233 committed
742
          ref = client.pre_establish_buffers;
mercury233's avatar
mercury233 committed
743 744
          for (j = 0, len = ref.length; j < len; j++) {
            buffer = ref[j];
mercury233's avatar
mercury233 committed
745 746 747 748 749 750 751 752 753 754 755
            client.server.write(buffer);
          }
          client.established = true;
          client.pre_establish_buffers = [];
        });
      }
    };

    Room.prototype.disconnect = function(client, error) {
      var index;
      if (client.is_post_watcher) {
mercury233's avatar
mercury233 committed
756
        ygopro.stoc_send_chat_to_room(this, (client.name + " ${quit_watch}") + (error ? ": " + error : ''));
mercury233's avatar
mercury233 committed
757 758 759 760 761 762 763 764 765
        index = _.indexOf(this.watchers, client);
        if (index !== -1) {
          this.watchers.splice(index, 1);
        }
      } else {
        index = _.indexOf(this.players, client);
        if (index !== -1) {
          this.players.splice(index, 1);
        }
mercury233's avatar
mercury233 committed
766 767 768
        if (this.started && this.disconnector !== 'server' && (client.pos < 4 || client.is_host)) {
          this.finished = true;
          this.scores[client.name] = -1;
mercury233's avatar
mercury233 committed
769
          if (this.random_type && !client.flee_free) {
mercury233's avatar
mercury233 committed
770
            ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}");
mercury233's avatar
mercury233 committed
771
          }
mercury233's avatar
mercury233 committed
772
        }
mercury233's avatar
mercury233 committed
773
        if (this.players.length && !(this.windbot && client.is_host)) {
mercury233's avatar
mercury233 committed
774
          ygopro.stoc_send_chat_to_room(this, (client.name + " ${left_game}") + (error ? ": " + error : ''));
mercury233's avatar
mercury233 committed
775
          if (!this.windbot && !this.started && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
776 777 778 779 780 781 782 783 784 785 786 787 788
            roomlist.update(this);
          }
        } else {
          this.process.kill();
          this["delete"]();
        }
      }
    };

    return Room;

  })();

神楽坂玲奈's avatar
神楽坂玲奈 committed
789
  net.createServer(function(client) {
mercury233's avatar
mercury233 committed
790 791 792 793 794 795 796
    var connect_count, server;
    client.ip = client.remoteAddress;
    connect_count = ROOM_connected_ip[client.ip] || 0;
    if (client.ip !== '::ffff:127.0.0.1') {
      connect_count++;
    }
    ROOM_connected_ip[client.ip] = connect_count;
神楽坂玲奈's avatar
神楽坂玲奈 committed
797 798
    server = new net.Socket();
    client.server = server;
mercury233's avatar
mercury233 committed
799
    client.setTimeout(2000);
800
    client.on('close', function(had_error) {
mercury233's avatar
mercury233 committed
801
      var room;
802
      room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
803 804 805 806 807
      connect_count = ROOM_connected_ip[client.ip];
      if (connect_count > 0) {
        connect_count--;
      }
      ROOM_connected_ip[client.ip] = connect_count;
808
      if (!client.closed) {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
809
        client.closed = true;
810 811
        if (room) {
          room.disconnect(client);
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
812
        }
mercury233's avatar
mercury233 committed
813
      }
mercury233's avatar
mercury233 committed
814
      server.destroy();
mercury233's avatar
mercury233 committed
815
    });
816
    client.on('error', function(error) {
mercury233's avatar
mercury233 committed
817
      var room;
818
      room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
819 820 821 822 823
      connect_count = ROOM_connected_ip[client.ip];
      if (connect_count > 0) {
        connect_count--;
      }
      ROOM_connected_ip[client.ip] = connect_count;
824 825
      if (!client.closed) {
        client.closed = error;
826 827
        if (room) {
          room.disconnect(client, error);
828
        }
神楽坂玲奈's avatar
神楽坂玲奈 committed
829
      }
mercury233's avatar
mercury233 committed
830
      server.destroy();
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
831
    });
832
    client.on('timeout', function() {
mercury233's avatar
mercury233 committed
833
      server.destroy();
834
    });
835
    server.on('close', function(had_error) {
836 837 838 839 840
      var room;
      room = ROOM_all[client.rid];
      if (room) {
        room.disconnector = 'server';
      }
841 842
      if (!server.closed) {
        server.closed = true;
mercury233's avatar
mercury233 committed
843
      }
844
      if (!client.closed) {
mercury233's avatar
mercury233 committed
845
        ygopro.stoc_send_chat(client, "${server_closed}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
846
        client.destroy();
mercury233's avatar
mercury233 committed
847 848
      }
    });
849
    server.on('error', function(error) {
850 851 852 853 854
      var room;
      room = ROOM_all[client.rid];
      if (room) {
        room.disconnector = 'server';
      }
855 856
      server.closed = error;
      if (!client.closed) {
mercury233's avatar
mercury233 committed
857
        ygopro.stoc_send_chat(client, "${server_error}: " + error, ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
858
        client.destroy();
mercury233's avatar
mercury233 committed
859 860
      }
    });
mercury233's avatar
mercury233 committed
861
    if (ROOM_bad_ip[client.ip] > 5 || ROOM_connected_ip[client.ip] > 10) {
mercury233's avatar
mercury233 committed
862 863
      log.info('BAD IP', client.ip);
      client.destroy();
mercury233's avatar
mercury233 committed
864 865
      return;
    }
mercury233's avatar
mercury233 committed
866
    if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
867 868 869
      client.open_cloud_replay = function(err, replay) {
        var buffer;
        if (err || !replay) {
mercury233's avatar
mercury233 committed
870
          ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
871
          return;
mercury233's avatar
mercury233 committed
872
        }
mercury233's avatar
mercury233 committed
873 874
        redisdb.expire("replay:" + replay.replay_id, 60 * 60 * 48);
        buffer = new Buffer(replay.replay_buffer, 'binary');
mercury233's avatar
mercury233 committed
875 876
        zlib.unzip(buffer, function(err, replay_buffer) {
          if (err) {
mercury233's avatar
mercury233 committed
877
            log.info("cloud replay unzip error: " + err);
mercury233's avatar
mercury233 committed
878
            ygopro.stoc_send_chat(client, "${cloud_replay_error}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
879
            client.destroy();
mercury233's avatar
mercury233 committed
880 881
            return;
          }
mercury233's avatar
mercury233 committed
882
          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
883
          client.write(replay_buffer, function() {
mercury233's avatar
fix  
mercury233 committed
884
            client.destroy();
mercury233's avatar
mercury233 committed
885
          });
mercury233's avatar
mercury233 committed
886
        });
mercury233's avatar
mercury233 committed
887 888
      };
    }
神楽坂玲奈's avatar
神楽坂玲奈 committed
889
    client.pre_establish_buffers = new Array();
mercury233's avatar
mercury233 committed
890
    client.on('data', function(ctos_buffer) {
mercury233's avatar
mercury233 committed
891
      var b, bad_ip_count, buffer, cancel, ctos_message_length, ctos_proto, datas, j, k, len, len1, looplimit, room, struct;
892
      if (client.is_post_watcher) {
893 894
        room = ROOM_all[client.rid];
        if (room) {
mercury233's avatar
mercury233 committed
895
          room.watcher.write(ctos_buffer);
896
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
897
      } else {
mercury233's avatar
mercury233 committed
898 899
        ctos_message_length = 0;
        ctos_proto = 0;
900
        datas = [];
mercury233's avatar
mercury233 committed
901
        looplimit = 0;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
902
        while (true) {
903 904
          if (ctos_message_length === 0) {
            if (ctos_buffer.length >= 2) {
mercury233's avatar
test3  
mercury233 committed
905
              ctos_message_length = ctos_buffer.readUInt16LE(0);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
906
            } else {
mercury233's avatar
mercury233 committed
907 908 909
              if (ctos_buffer.length !== 0) {
                log.warn("bad ctos_buffer length", client.ip);
              }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
910 911
              break;
            }
912 913
          } else if (ctos_proto === 0) {
            if (ctos_buffer.length >= 3) {
mercury233's avatar
test3  
mercury233 committed
914
              ctos_proto = ctos_buffer.readUInt8(2);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
915
            } else {
mercury233's avatar
mercury233 committed
916
              log.warn("bad ctos_proto length", client.ip);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
917
              break;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
918 919
            }
          } else {
920
            if (ctos_buffer.length >= 2 + ctos_message_length) {
921
              cancel = false;
922 923 924
              if (ygopro.ctos_follows[ctos_proto]) {
                b = ctos_buffer.slice(3, ctos_message_length - 1 + 3);
                if (struct = ygopro.structs[ygopro.proto_structs.CTOS[ygopro.constants.CTOS[ctos_proto]]]) {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
925
                  struct._setBuff(b);
926 927 928 929 930
                  if (ygopro.ctos_follows[ctos_proto].synchronous) {
                    cancel = ygopro.ctos_follows[ctos_proto].callback(b, _.clone(struct.fields), client, server);
                  } else {
                    ygopro.ctos_follows[ctos_proto].callback(b, _.clone(struct.fields), client, server);
                  }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
931
                } else {
932
                  ygopro.ctos_follows[ctos_proto].callback(b, null, client, server);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
933 934
                }
              }
935 936 937
              if (!cancel) {
                datas.push(ctos_buffer.slice(0, 2 + ctos_message_length));
              }
938 939
              ctos_buffer = ctos_buffer.slice(2 + ctos_message_length);
              ctos_message_length = 0;
mercury233's avatar
test3  
mercury233 committed
940
              ctos_proto = 0;
mercury233's avatar
fix  
mercury233 committed
941 942 943 944
            } else {
              if (ctos_message_length !== 17735) {
                log.warn("bad ctos_message length", client.ip, ctos_buffer.length, ctos_message_length, ctos_proto);
              }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
945 946
              break;
            }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
947
          }
mercury233's avatar
mercury233 committed
948
          looplimit++;
mercury233's avatar
mercury233 committed
949 950 951
          if (looplimit > 800 || ROOM_bad_ip[client.ip] > 5) {
            log.info("error ctos", client.name, client.ip);
            bad_ip_count = ROOM_bad_ip[client.ip];
mercury233's avatar
mercury233 committed
952
            if (bad_ip_count) {
mercury233's avatar
mercury233 committed
953
              ROOM_bad_ip[client.ip] = bad_ip_count + 1;
mercury233's avatar
mercury233 committed
954
            } else {
mercury233's avatar
mercury233 committed
955
              ROOM_bad_ip[client.ip] = 1;
mercury233's avatar
mercury233 committed
956
            }
mercury233's avatar
mercury233 committed
957
            client.destroy();
mercury233's avatar
mercury233 committed
958 959
            break;
          }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
960
        }
961
        if (client.established) {
mercury233's avatar
mercury233 committed
962 963
          for (j = 0, len = datas.length; j < len; j++) {
            buffer = datas[j];
964 965 966
            server.write(buffer);
          }
        } else {
mercury233's avatar
mercury233 committed
967 968
          for (k = 0, len1 = datas.length; k < len1; k++) {
            buffer = datas[k];
969 970 971
            client.pre_establish_buffers.push(buffer);
          }
        }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
972 973
      }
    });
mercury233's avatar
mercury233 committed
974
    server.on('data', function(stoc_buffer) {
mercury233's avatar
mercury233 committed
975
      var b, buffer, cancel, datas, j, len, looplimit, stanzas, stoc_message_length, stoc_proto, struct;
mercury233's avatar
mercury233 committed
976 977
      stoc_message_length = 0;
      stoc_proto = 0;
978
      datas = [];
mercury233's avatar
mercury233 committed
979
      looplimit = 0;
神楽坂玲奈's avatar
神楽坂玲奈 committed
980
      while (true) {
981 982
        if (stoc_message_length === 0) {
          if (stoc_buffer.length >= 2) {
mercury233's avatar
test3  
mercury233 committed
983
            stoc_message_length = stoc_buffer.readUInt16LE(0);
神楽坂玲奈's avatar
神楽坂玲奈 committed
984
          } else {
mercury233's avatar
mercury233 committed
985 986 987
            if (stoc_buffer.length !== 0) {
              log.warn("bad stoc_buffer length", client.ip);
            }
神楽坂玲奈's avatar
神楽坂玲奈 committed
988 989
            break;
          }
990 991
        } else if (stoc_proto === 0) {
          if (stoc_buffer.length >= 3) {
mercury233's avatar
test3  
mercury233 committed
992
            stoc_proto = stoc_buffer.readUInt8(2);
神楽坂玲奈's avatar
神楽坂玲奈 committed
993
          } else {
mercury233's avatar
mercury233 committed
994
            log.warn("bad stoc_proto length", client.ip);
神楽坂玲奈's avatar
神楽坂玲奈 committed
995 996 997
            break;
          }
        } else {
998
          if (stoc_buffer.length >= 2 + stoc_message_length) {
999
            cancel = false;
1000 1001 1002 1003
            stanzas = stoc_proto;
            if (ygopro.stoc_follows[stoc_proto]) {
              b = stoc_buffer.slice(3, stoc_message_length - 1 + 3);
              if (struct = ygopro.structs[ygopro.proto_structs.STOC[ygopro.constants.STOC[stoc_proto]]]) {
神楽坂玲奈's avatar
神楽坂玲奈 committed
1004
                struct._setBuff(b);
1005 1006 1007 1008 1009
                if (ygopro.stoc_follows[stoc_proto].synchronous) {
                  cancel = ygopro.stoc_follows[stoc_proto].callback(b, _.clone(struct.fields), client, server);
                } else {
                  ygopro.stoc_follows[stoc_proto].callback(b, _.clone(struct.fields), client, server);
                }
神楽坂玲奈's avatar
神楽坂玲奈 committed
1010
              } else {
1011 1012 1013 1014 1015
                if (ygopro.stoc_follows[stoc_proto].synchronous) {
                  cancel = ygopro.stoc_follows[stoc_proto].callback(b, null, client, server);
                } else {
                  ygopro.stoc_follows[stoc_proto].callback(b, null, client, server);
                }
神楽坂玲奈's avatar
神楽坂玲奈 committed
1016 1017
              }
            }
1018 1019 1020
            if (!cancel) {
              datas.push(stoc_buffer.slice(0, 2 + stoc_message_length));
            }
1021 1022
            stoc_buffer = stoc_buffer.slice(2 + stoc_message_length);
            stoc_message_length = 0;
mercury233's avatar
test3  
mercury233 committed
1023
            stoc_proto = 0;
神楽坂玲奈's avatar
神楽坂玲奈 committed
1024
          } else {
mercury233's avatar
mercury233 committed
1025
            log.warn("bad stoc_message length", client.ip);
神楽坂玲奈's avatar
神楽坂玲奈 committed
1026 1027 1028
            break;
          }
        }
mercury233's avatar
mercury233 committed
1029 1030
        looplimit++;
        if (looplimit > 800) {
mercury233's avatar
fix  
mercury233 committed
1031
          log.info("error stoc", client.name);
mercury233's avatar
mercury233 committed
1032
          server.destroy();
mercury233's avatar
mercury233 committed
1033 1034
          break;
        }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
1035
      }
mercury233's avatar
mercury233 committed
1036 1037
      for (j = 0, len = datas.length; j < len; j++) {
        buffer = datas[j];
1038 1039
        client.write(buffer);
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1040
    });
神楽坂玲奈's avatar
神楽坂玲奈 committed
1041
  }).listen(settings.port, function() {
mercury233's avatar
mercury233 committed
1042
    log.info("server started", settings.port);
神楽坂玲奈's avatar
神楽坂玲奈 committed
1043
  });
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1044

神楽坂玲奈's avatar
神楽坂玲奈 committed
1045
  ygopro.ctos_follow('PLAYER_INFO', true, function(buffer, info, client, server) {
mercury233's avatar
mercury233 committed
1046
    var geo, lang, name, struct;
1047
    name = info.name.split("$")[0];
mercury233's avatar
mercury233 committed
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
    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;
    }
1060 1061 1062 1063 1064
    struct = ygopro.structs["CTOS_PlayerInfo"];
    struct._setBuff(buffer);
    struct.set("name", name);
    buffer = struct.buffer;
    client.name = name;
mercury233's avatar
mercury233 committed
1065
    if (!settings.modules.i18n.auto_pick || client.ip === "::ffff:127.0.0.1") {
mercury233's avatar
mercury233 committed
1066 1067 1068 1069
      client.lang = settings.modules.i18n["default"];
    } else {
      geo = geoip.lookup(client.ip);
      if (!geo) {
mercury233's avatar
mercury233 committed
1070
        log.warn("fail to locate ip", client.name, client.ip);
mercury233's avatar
mercury233 committed
1071 1072 1073 1074 1075 1076 1077 1078
        client.lang = settings.modules.i18n.fallback;
      } else {
        if (lang = settings.modules.i18n.map[geo.country]) {
          client.lang = lang;
        } else {
          client.lang = settings.modules.i18n.fallback;
        }
      }
mercury233's avatar
mercury233 committed
1079
    }
1080
    return false;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1081 1082
  });

神楽坂玲奈's avatar
神楽坂玲奈 committed
1083
  ygopro.ctos_follow('JOIN_GAME', false, function(buffer, info, client, server) {
mercury233's avatar
mercury233 committed
1084
    var check, decrypted_buffer, finish, i, id, j, k, len, len1, name, ref, ref1, replay_id, room, secret, struct;
mercury233's avatar
fix  
mercury233 committed
1085
    if (settings.modules.stop) {
mercury233's avatar
mercury233 committed
1086
      ygopro.stoc_die(client, settings.modules.stop);
mercury233's avatar
mercury233 committed
1087
    } else if (info.pass.toUpperCase() === "R" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
1088
      ygopro.stoc_send_chat(client, "${cloud_replay_hint}", ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
1089
      redisdb.lrange(client.ip + ":replays", 0, 2, function(err, result) {
mercury233's avatar
mercury233 committed
1090 1091 1092
        _.each(result, function(replay_id, id) {
          redisdb.hgetall("replay:" + replay_id, function(err, replay) {
            if (err || !replay) {
mercury233's avatar
mercury233 committed
1093 1094 1095
              if (err) {
                log.info("cloud replay getall error: " + err);
              }
mercury233's avatar
mercury233 committed
1096 1097 1098
              return;
            }
            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
1099
          });
mercury233's avatar
mercury233 committed
1100 1101 1102 1103 1104 1105 1106
        });
      });
      setTimeout((function() {
        ygopro.stoc_send(client, 'ERROR_MSG', {
          msg: 1,
          code: 2
        });
mercury233's avatar
mercury233 committed
1107
        client.destroy();
mercury233's avatar
mercury233 committed
1108
      }), 500);
mercury233's avatar
mercury233 committed
1109
    } else if (info.pass.slice(0, 2).toUpperCase() === "R#" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
1110
      replay_id = info.pass.split("#")[1];
mercury233's avatar
fix  
mercury233 committed
1111
      if (replay_id > 0 && replay_id <= 9) {
mercury233's avatar
mercury233 committed
1112
        redisdb.lindex(client.ip + ":replays", replay_id - 1, function(err, replay_id) {
mercury233's avatar
mercury233 committed
1113
          if (err || !replay_id) {
mercury233's avatar
mercury233 committed
1114 1115 1116
            if (err) {
              log.info("cloud replay replayid error: " + err);
            }
mercury233's avatar
mercury233 committed
1117
            ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
1118 1119 1120 1121
            return;
          }
          redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
        });
mercury233's avatar
mercury233 committed
1122 1123 1124
      } else if (replay_id) {
        redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
      } else {
mercury233's avatar
mercury233 committed
1125
        ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
1126
      }
mercury233's avatar
mercury233 committed
1127
    } else if (info.pass.toUpperCase() === "W" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
1128 1129
      replay_id = Cloud_replay_ids[Math.floor(Math.random() * Cloud_replay_ids.length)];
      redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
mercury233's avatar
mercury233 committed
1130
    } else if (info.version !== settings.version && (info.version !== 4921 || settings.version !== 4922)) {
mercury233's avatar
mercury233 committed
1131
      ygopro.stoc_send_chat(client, settings.modules.update, ygopro.constants.COLORS.RED);
mercury233's avatar
fix  
mercury233 committed
1132 1133 1134 1135
      ygopro.stoc_send(client, 'ERROR_MSG', {
        msg: 4,
        code: settings.version
      });
mercury233's avatar
mercury233 committed
1136
      client.destroy();
mercury233's avatar
mercury233 committed
1137
    } else if (!info.pass.length && !settings.modules.random_duel.enabled && !settings.modules.windbot.enabled) {
mercury233's avatar
mercury233 committed
1138
      ygopro.stoc_die(client, "${blank_room_name}");
mercury233's avatar
fix  
mercury233 committed
1139
    } else if (info.pass.length && settings.modules.mycard.enabled && info.pass.slice(0, 3) !== 'AI#') {
mercury233's avatar
mercury233 committed
1140
      ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1141
      if (info.pass.length <= 8) {
mercury233's avatar
mercury233 committed
1142
        ygopro.stoc_die(client, '${invalid_password_length}');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1143 1144 1145
        return;
      }
      buffer = new Buffer(info.pass.slice(0, 8), 'base64');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1146
      if (buffer.length !== 6) {
mercury233's avatar
mercury233 committed
1147
        ygopro.stoc_die(client, '${invalid_password_payload}');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1148 1149
        return;
      }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1150
      check = function(buf) {
mercury233's avatar
mercury233 committed
1151
        var checksum, i, j, ref;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1152
        checksum = 0;
mercury233's avatar
mercury233 committed
1153
        for (i = j = 0, ref = buf.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1154
          checksum += buf.readUInt8(i);
1155
        }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1156 1157 1158
        return (checksum & 0xFF) === 0;
      };
      finish = function(buffer) {
mercury233's avatar
mercury233 committed
1159
        var action, j, len, name, opt1, opt2, opt3, options, ref, room;
1160 1161
        action = buffer.readUInt8(1) >> 4;
        if (buffer !== decrypted_buffer && (action === 1 || action === 2 || action === 4)) {
mercury233's avatar
mercury233 committed
1162
          ygopro.stoc_die(client, '${invalid_password_unauthorized}');
1163 1164 1165 1166 1167 1168
          return;
        }
        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
1169
            if (ROOM_find_by_name(name)) {
mercury233's avatar
mercury233 committed
1170
              ygopro.stoc_die(client, '${invalid_password_existed}');
1171 1172 1173
              return;
            }
            opt1 = buffer.readUInt8(2);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1174
            opt2 = buffer.readUInt16LE(3);
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
            opt3 = buffer.readUInt8(5);
            options = {
              lflist: 0,
              time_limit: 180,
              rule: (opt1 >> 5) & 3,
              mode: (opt1 >> 3) & 3,
              enable_priority: !!((opt1 >> 2) & 1),
              no_check_deck: !!((opt1 >> 1) & 1),
              no_shuffle_deck: !!(opt1 & 1),
              start_lp: opt2,
              start_hand: opt3 >> 4,
              draw_count: opt3 & 0xF
            };
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1188 1189
            options.lflist = _.findIndex(settings.lflist, function(list) {
              return ((options.rule === 1) === list.tcg) && list.date.isBefore();
神楽坂玲奈's avatar
神楽坂玲奈 committed
1190
            });
1191
            room = new Room(name, options);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1192
            room.title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ');
神楽坂玲奈's avatar
神楽坂玲奈 committed
1193
            room["private"] = action === 2;
1194 1195 1196
            break;
          case 3:
            name = info.pass.slice(8);
mercury233's avatar
mercury233 committed
1197
            room = ROOM_find_by_name(name);
1198
            if (!room) {
mercury233's avatar
mercury233 committed
1199
              ygopro.stoc_die(client, '${invalid_password_not_found}');
1200 1201 1202 1203
              return;
            }
            break;
          case 4:
mercury233's avatar
mercury233 committed
1204
            room = ROOM_find_or_create_by_name('M#' + info.pass.slice(8));
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1205
            room["private"] = true;
1206
            room.arena = settings.modules.arena_mode.mode;
1207 1208
            break;
          default:
mercury233's avatar
mercury233 committed
1209
            ygopro.stoc_die(client, '${invalid_password_action}');
1210 1211
            return;
        }
mercury233's avatar
mercury233 committed
1212
        if (!room) {
mercury233's avatar
mercury233 committed
1213
          ygopro.stoc_die(client, "${server_full}");
mercury233's avatar
mercury233 committed
1214
        } else if (room.error) {
mercury233's avatar
mercury233 committed
1215
          ygopro.stoc_die(client, room.error);
mercury233's avatar
mercury233 committed
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
        } else if (room.started) {
          if (settings.modules.cloud_replay.enable_halfway_watch) {
            client.setTimeout(300000);
            client.rid = _.indexOf(ROOM_all, room);
            client.is_post_watcher = true;
            ygopro.stoc_send_chat_to_room(room, client.name + " ${watch_join}");
            room.watchers.push(client);
            ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
            ref = room.watcher_buffers;
            for (j = 0, len = ref.length; j < len; j++) {
              buffer = ref[j];
              client.write(buffer);
            }
          } else {
            ygopro.stoc_die(client, "${watch_denied}");
          }
mercury233's avatar
mercury233 committed
1232
        } else {
mercury233's avatar
mercury233 committed
1233
          client.setTimeout(300000);
1234 1235
          client.rid = _.indexOf(ROOM_all, room);
          room.connect(client);
mercury233's avatar
mercury233 committed
1236
        }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1237 1238 1239 1240 1241
      };
      if (id = users_cache[client.name]) {
        secret = id % 65535 + 1;
        decrypted_buffer = new Buffer(6);
        ref = [0, 2, 4];
mercury233's avatar
mercury233 committed
1242 1243
        for (j = 0, len = ref.length; j < len; j++) {
          i = ref[j];
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1244 1245 1246 1247 1248 1249 1250
          decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
        }
        if (check(decrypted_buffer)) {
          return finish(decrypted_buffer);
        }
      }
      request({
mercury233's avatar
mercury233 committed
1251
        baseUrl: settings.modules.mycard.auth_base_url,
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1252 1253
        url: '/users/' + encodeURIComponent(client.name) + '.json',
        qs: {
mercury233's avatar
fix  
mercury233 committed
1254
          api_key: settings.modules.mycard.auth_key,
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1255 1256 1257 1258 1259
          api_username: client.name,
          skip_track_visit: true
        },
        json: true
      }, function(error, response, body) {
mercury233's avatar
mercury233 committed
1260
        var k, len1, ref1;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1261
        if (body && body.user) {
mercury233's avatar
fix  
mercury233 committed
1262
          users_cache[client.name] = body.user.id;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1263 1264 1265
          secret = body.user.id % 65535 + 1;
          decrypted_buffer = new Buffer(6);
          ref1 = [0, 2, 4];
mercury233's avatar
mercury233 committed
1266 1267
          for (k = 0, len1 = ref1.length; k < len1; k++) {
            i = ref1[k];
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1268 1269 1270 1271 1272 1273 1274
            decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
          }
          if (check(decrypted_buffer)) {
            buffer = decrypted_buffer;
          }
        }
        if (!check(buffer)) {
mercury233's avatar
mercury233 committed
1275
          ygopro.stoc_die(client, '${invalid_password_checksum}');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1276 1277 1278
          return;
        }
        return finish(buffer);
1279
      });
mercury233's avatar
mercury233 committed
1280
    } else if (!client.name || client.name === "") {
mercury233's avatar
mercury233 committed
1281
      ygopro.stoc_die(client, "${bad_user_name}");
mercury233's avatar
mercury233 committed
1282 1283
    } else if (ROOM_connected_ip[client.ip] > 5) {
      log.warn("MULTI LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
1284
      ygopro.stoc_die(client, "${too_much_connection}" + client.ip);
mercury233's avatar
mercury233 committed
1285
    } else if (_.indexOf(settings.ban.banned_user, client.name) > -1) {
mercury233's avatar
mercury233 committed
1286 1287
      settings.ban.banned_ip.push(client.ip);
      log.warn("BANNED USER LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
1288
      ygopro.stoc_die(client, "${banned_user_login}");
mercury233's avatar
mercury233 committed
1289 1290
    } else if (_.indexOf(settings.ban.banned_ip, client.ip) > -1) {
      log.warn("BANNED IP LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
1291
      ygopro.stoc_die(client, "${banned_ip_login}");
mercury233's avatar
mercury233 committed
1292 1293
    } else if (_.any(settings.ban.badword_level3, function(badword) {
      var regexp;
mercury233's avatar
fix  
mercury233 committed
1294
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
1295 1296
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
1297
      log.warn("BAD NAME LEVEL 3", client.name, client.ip);
mercury233's avatar
mercury233 committed
1298
      ygopro.stoc_die(client, "${bad_name_level3}");
mercury233's avatar
mercury233 committed
1299 1300
    } else if (_.any(settings.ban.badword_level2, function(badword) {
      var regexp;
mercury233's avatar
fix  
mercury233 committed
1301
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
1302 1303
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
1304
      log.warn("BAD NAME LEVEL 2", client.name, client.ip);
mercury233's avatar
mercury233 committed
1305
      ygopro.stoc_die(client, "${bad_name_level2}");
mercury233's avatar
mercury233 committed
1306 1307
    } else if (_.any(settings.ban.badword_level1, function(badword) {
      var regexp;
mercury233's avatar
fix  
mercury233 committed
1308
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
1309 1310
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
1311
      log.warn("BAD NAME LEVEL 1", client.name, client.ip);
mercury233's avatar
mercury233 committed
1312
      ygopro.stoc_die(client, "${bad_name_level1}");
mercury233's avatar
mercury233 committed
1313
    } else if (info.pass.length && !ROOM_validate(info.pass)) {
mercury233's avatar
mercury233 committed
1314
      ygopro.stoc_die(client, "${invalid_password_room}");
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1315
    } else {
mercury233's avatar
mercury233 committed
1316
      if (info.version === 4921 && settings.version === 4922) {
mercury233's avatar
mercury233 committed
1317 1318 1319 1320 1321 1322
        info.version = settings.version;
        struct = ygopro.structs["CTOS_JoinGame"];
        struct._setBuff(buffer);
        struct.set("version", info.version);
        buffer = struct.buffer;
      }
mercury233's avatar
mercury233 committed
1323
      room = ROOM_find_or_create_by_name(info.pass, client.ip);
mercury233's avatar
mercury233 committed
1324
      if (!room) {
mercury233's avatar
mercury233 committed
1325
        ygopro.stoc_die(client, "${server_full}");
mercury233's avatar
mercury233 committed
1326
      } else if (room.error) {
mercury233's avatar
mercury233 committed
1327
        ygopro.stoc_die(client, room.error);
mercury233's avatar
mercury233 committed
1328
      } else if (room.started) {
mercury233's avatar
mercury233 committed
1329
        if (settings.modules.cloud_replay.enable_halfway_watch) {
mercury233's avatar
mercury233 committed
1330
          client.setTimeout(300000);
1331
          client.rid = _.indexOf(ROOM_all, room);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1332
          client.is_post_watcher = true;
mercury233's avatar
mercury233 committed
1333
          ygopro.stoc_send_chat_to_room(room, client.name + " ${watch_join}");
1334
          room.watchers.push(client);
mercury233's avatar
mercury233 committed
1335
          ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
1336
          ref1 = room.watcher_buffers;
mercury233's avatar
mercury233 committed
1337 1338
          for (k = 0, len1 = ref1.length; k < len1; k++) {
            buffer = ref1[k];
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1339 1340 1341
            client.write(buffer);
          }
        } else {
mercury233's avatar
mercury233 committed
1342
          ygopro.stoc_die(client, "${watch_denied}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1343 1344
        }
      } else {
mercury233's avatar
mercury233 committed
1345
        client.setTimeout(300000);
1346 1347
        client.rid = _.indexOf(ROOM_all, room);
        room.connect(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1348
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1349 1350 1351
    }
  });

神楽坂玲奈's avatar
神楽坂玲奈 committed
1352
  ygopro.stoc_follow('JOIN_GAME', false, function(buffer, info, client, server) {
1353 1354 1355
    var recorder, room, watcher;
    room = ROOM_all[client.rid];
    if (!room) {
1356 1357
      return;
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1358
    if (settings.modules.welcome) {
mercury233's avatar
mercury233 committed
1359
      ygopro.stoc_send_chat(client, settings.modules.welcome, ygopro.constants.COLORS.GREEN);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1360
    }
1361 1362
    if (room.welcome) {
      ygopro.stoc_send_chat(client, room.welcome, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
add  
mercury233 committed
1363
    }
mercury233's avatar
mercury233 committed
1364
    if (settings.modules.arena_mode.enabled && client.ip !== '::ffff:127.0.0.1') {
mercury233's avatar
mercury233 committed
1365 1366 1367 1368
      request({
        url: settings.modules.arena_mode.get_score + encodeURIComponent(client.name),
        json: true
      }, function(error, response, body) {
mercury233's avatar
merge  
mercury233 committed
1369
        var rank_txt;
mercury233's avatar
merge  
mercury233 committed
1370 1371 1372 1373
        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
1374
        } else {
mercury233's avatar
mercury233 committed
1375 1376
          rank_txt = body.arena_rank > 0 ? "${rank_arena}" + body.arena_rank : "${rank_blank}";
          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
1377 1378 1379
        }
      });
    }
1380 1381
    if (!room.recorder) {
      room.recorder = recorder = net.connect(room.port, function() {
mercury233's avatar
mercury233 committed
1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
        ygopro.ctos_send(recorder, 'PLAYER_INFO', {
          name: "Marshtomp"
        });
        ygopro.ctos_send(recorder, 'JOIN_GAME', {
          version: settings.version,
          gameid: 2577,
          some_unknown_mysterious_fucking_thing: 0,
          pass: ""
        });
        ygopro.ctos_send(recorder, 'HS_TOOBSERVER');
      });
      recorder.on('data', function(data) {
1394
        room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
1395
        if (!(room && settings.modules.cloud_replay.enabled)) {
mercury233's avatar
mercury233 committed
1396 1397
          return;
        }
mercury233's avatar
mercury233 committed
1398
        room.recorder_buffers.push(data);
mercury233's avatar
mercury233 committed
1399 1400 1401
      });
      recorder.on('error', function(error) {});
    }
mercury233's avatar
mercury233 committed
1402
    if (settings.modules.cloud_replay.enable_halfway_watch && !room.watcher) {
1403
      room.watcher = watcher = net.connect(room.port, function() {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1404 1405 1406 1407 1408 1409 1410 1411 1412
        ygopro.ctos_send(watcher, 'PLAYER_INFO', {
          name: "the Big Brother"
        });
        ygopro.ctos_send(watcher, 'JOIN_GAME', {
          version: settings.version,
          gameid: 2577,
          some_unknown_mysterious_fucking_thing: 0,
          pass: ""
        });
mercury233's avatar
test3  
mercury233 committed
1413
        ygopro.ctos_send(watcher, 'HS_TOOBSERVER');
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1414
      });
mercury233's avatar
fix  
mercury233 committed
1415
      watcher.on('data', function(data) {
mercury233's avatar
mercury233 committed
1416
        var j, len, ref, w;
1417 1418
        room = ROOM_all[client.rid];
        if (!room) {
1419 1420
          return;
        }
1421 1422
        room.watcher_buffers.push(data);
        ref = room.watchers;
mercury233's avatar
mercury233 committed
1423 1424
        for (j = 0, len = ref.length; j < len; j++) {
          w = ref[j];
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
1425
          if (w) {
mercury233's avatar
test3  
mercury233 committed
1426
            w.write(data);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
1427
          }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1428 1429
        }
      });
mercury233's avatar
test3  
mercury233 committed
1430
      watcher.on('error', function(error) {});
神楽坂玲奈's avatar
神楽坂玲奈 committed
1431
    }
神楽坂玲奈's avatar
tip  
神楽坂玲奈 committed
1432
  });
神楽坂玲奈's avatar
神楽坂玲奈 committed
1433

mercury233's avatar
mercury233 committed
1434
  load_dialogues = function() {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1435
    request({
mercury233's avatar
mercury233 committed
1436
      url: settings.modules.dialogues.get,
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1437 1438 1439
      json: true
    }, function(error, response, body) {
      if (_.isString(body)) {
mercury233's avatar
test3  
mercury233 committed
1440
        log.warn("dialogues bad json", body);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
1441
      } else if (error || !body) {
mercury233's avatar
test3  
mercury233 committed
1442
        log.warn('dialogues error', error, response);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1443
      } else {
mercury233's avatar
mercury233 committed
1444 1445
        nconf.myset(settings, "dialogues", body);
        log.info("dialogues loaded", _.size(body));
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1446 1447
      }
    });
mercury233's avatar
mercury233 committed
1448 1449
  };

mercury233's avatar
mercury233 committed
1450
  if (settings.modules.dialogues.get) {
mercury233's avatar
mercury233 committed
1451
    load_dialogues();
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1452 1453
  }

神楽坂玲奈's avatar
神楽坂玲奈 committed
1454
  ygopro.stoc_follow('GAME_MSG', false, function(buffer, info, client, server) {
mercury233's avatar
mercury233 committed
1455
    var card, j, len, line, msg, playertype, pos, reason, ref, ref1, ref2, room, val;
1456 1457 1458 1459
    room = ROOM_all[client.rid];
    if (!room) {
      return;
    }
神楽坂玲奈's avatar
神楽坂玲奈 committed
1460
    msg = buffer.readInt8(0);
1461
    if (msg >= 10 && msg < 30) {
1462 1463
      room.waiting_for_player = client;
      room.last_active_time = moment();
1464
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1465 1466 1467
    if (ygopro.constants.MSG[msg] === 'START') {
      playertype = buffer.readUInt8(1);
      client.is_first = !(playertype & 0xf);
1468
      client.lp = room.hostinfo.start_lp;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1469
    }
mercury233's avatar
mercury233 committed
1470 1471 1472 1473
    if (ygopro.constants.MSG[msg] === 'NEW_TURN' && client.surrend_confirm) {
      client.surrend_confirm = false;
      ygopro.stoc_send_chat(client, "${surrender_canceled}", ygopro.constants.COLORS.BABYBLUE);
    }
mercury233's avatar
mercury233 committed
1474 1475 1476 1477 1478 1479 1480
    if (ygopro.constants.MSG[msg] === 'WIN' && client.is_host) {
      pos = buffer.readUInt8(1);
      if (!(client.is_first || pos === 2)) {
        pos = 1 - pos;
      }
      reason = buffer.readUInt8(2);
      room.winner = pos;
mercury233's avatar
fix  
mercury233 committed
1481
      if (room && !room.finished && room.dueling_players[pos]) {
mercury233's avatar
mercury233 committed
1482 1483 1484
        room.winner_name = room.dueling_players[pos].name;
        room.scores[room.winner_name] = room.scores[room.winner_name] + 1;
      }
mercury233's avatar
mercury233 committed
1485
    }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
1486 1487 1488 1489 1490 1491
    if (ygopro.constants.MSG[msg] === 'DAMAGE' && client.is_host) {
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      val = buffer.readInt32LE(2);
1492 1493
      room.dueling_players[pos].lp -= val;
      if ((0 < (ref = room.dueling_players[pos].lp) && ref <= 100)) {
mercury233's avatar
mercury233 committed
1494
        ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
1495 1496 1497 1498 1499 1500 1501 1502
      }
    }
    if (ygopro.constants.MSG[msg] === 'RECOVER' && client.is_host) {
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      val = buffer.readInt32LE(2);
1503
      room.dueling_players[pos].lp += val;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
1504 1505 1506 1507 1508 1509 1510
    }
    if (ygopro.constants.MSG[msg] === 'LPUPDATE' && client.is_host) {
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      val = buffer.readInt32LE(2);
1511
      room.dueling_players[pos].lp = val;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
1512 1513 1514 1515 1516 1517 1518
    }
    if (ygopro.constants.MSG[msg] === 'PAY_LPCOST' && client.is_host) {
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      val = buffer.readInt32LE(2);
1519 1520
      room.dueling_players[pos].lp -= val;
      if ((0 < (ref1 = room.dueling_players[pos].lp) && ref1 <= 100)) {
mercury233's avatar
mercury233 committed
1521
        ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
1522 1523
      }
    }
mercury233's avatar
mercury233 committed
1524
    if (settings.modules.dialogues.enabled) {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1525 1526
      if (ygopro.constants.MSG[msg] === 'SUMMONING' || ygopro.constants.MSG[msg] === 'SPSUMMONING') {
        card = buffer.readUInt32LE(1);
mercury233's avatar
mercury233 committed
1527 1528
        if (settings.dialogues[card]) {
          ref2 = _.lines(settings.dialogues[card][Math.floor(Math.random() * settings.dialogues[card].length)]);
mercury233's avatar
mercury233 committed
1529 1530
          for (j = 0, len = ref2.length; j < len; j++) {
            line = ref2[j];
mercury233's avatar
mercury233 committed
1531
            ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1532
          }
神楽坂玲奈's avatar
神楽坂玲奈 committed
1533
        }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
1534 1535 1536 1537
      }
    }
  });

1538
  ygopro.ctos_follow('HS_KICK', true, function(buffer, info, client, server) {
mercury233's avatar
mercury233 committed
1539
    var j, len, player, ref, room;
1540 1541
    room = ROOM_all[client.rid];
    if (!room) {
1542 1543
      return;
    }
1544
    ref = room.players;
mercury233's avatar
mercury233 committed
1545 1546
    for (j = 0, len = ref.length; j < len; j++) {
      player = ref[j];
mercury233's avatar
mercury233 committed
1547
      if (player && player.pos === info.pos && player !== client) {
mercury233's avatar
mercury233 committed
1548
        client.kick_count = client.kick_count ? client.kick_count + 1 : 1;
mercury233's avatar
fix  
mercury233 committed
1549
        if (client.kick_count >= 5 && room.random_type) {
mercury233's avatar
mercury233 committed
1550
          ygopro.stoc_send_chat_to_room(room, client.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1551
          ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
mercury233's avatar
mercury233 committed
1552
          client.destroy();
mercury233's avatar
mercury233 committed
1553 1554
          return true;
        }
mercury233's avatar
mercury233 committed
1555
        ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_player}", ygopro.constants.COLORS.RED);
1556 1557 1558 1559 1560
      }
    }
    return false;
  });

神楽坂玲奈's avatar
神楽坂玲奈 committed
1561 1562 1563 1564 1565
  ygopro.stoc_follow('TYPE_CHANGE', false, function(buffer, info, client, server) {
    var is_host, selftype;
    selftype = info.type & 0xf;
    is_host = ((info.type >> 4) & 0xf) !== 0;
    client.is_host = is_host;
mercury233's avatar
test3  
mercury233 committed
1566
    client.pos = selftype;
神楽坂玲奈's avatar
神楽坂玲奈 committed
1567 1568
  });

1569
  ygopro.stoc_follow('HS_PLAYER_CHANGE', false, function(buffer, info, client, server) {
mercury233's avatar
mercury233 committed
1570
    var is_ready, j, len, player, pos, ref, room;
1571 1572
    room = ROOM_all[client.rid];
    if (!(room && room.max_player && client.is_host)) {
1573 1574 1575 1576
      return;
    }
    pos = info.status >> 4;
    is_ready = (info.status & 0xf) === 9;
1577 1578 1579
    if (pos < room.max_player) {
      room.ready_player_count_without_host = 0;
      ref = room.players;
mercury233's avatar
mercury233 committed
1580 1581
      for (j = 0, len = ref.length; j < len; j++) {
        player = ref[j];
1582 1583 1584 1585
        if (player.pos === pos) {
          player.is_ready = is_ready;
        }
        if (!player.is_host) {
1586
          room.ready_player_count_without_host += player.is_ready;
1587 1588
        }
      }
1589
      if (room.ready_player_count_without_host >= room.max_player - 1) {
1590
        setTimeout((function() {
1591
          wait_room_start(ROOM_all[client.rid], 20);
1592 1593 1594 1595 1596 1597
        }), 1000);
      }
    }
  });

  wait_room_start = function(room, time) {
mercury233's avatar
mercury233 committed
1598
    var j, len, player, ref;
1599 1600 1601 1602
    if (!(!room || room.started || room.ready_player_count_without_host < room.max_player - 1)) {
      time -= 1;
      if (time) {
        if (!(time % 5)) {
mercury233's avatar
mercury233 committed
1603
          ygopro.stoc_send_chat_to_room(room, "" + (time <= 9 ? ' ' : '') + time + "${kick_count_down}", time <= 9 ? ygopro.constants.COLORS.RED : ygopro.constants.COLORS.LIGHTBLUE);
1604 1605 1606 1607 1608 1609
        }
        setTimeout((function() {
          wait_room_start(room, time);
        }), 1000);
      } else {
        ref = room.players;
mercury233's avatar
mercury233 committed
1610 1611
        for (j = 0, len = ref.length; j < len; j++) {
          player = ref[j];
mercury233's avatar
fix  
mercury233 committed
1612
          if (player && player.is_host) {
mercury233's avatar
mercury233 committed
1613
            ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
mercury233's avatar
mercury233 committed
1614
            ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1615
            player.destroy();
1616 1617 1618 1619 1620 1621
          }
        }
      }
    }
  };

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1622
  ygopro.stoc_send_random_tip = function(client) {
mercury233's avatar
mercury233 committed
1623
    if (settings.modules.tips.enabled && settings.tips.length) {
mercury233's avatar
mercury233 committed
1624
      ygopro.stoc_send_chat(client, "Tip: " + settings.tips[Math.floor(Math.random() * settings.tips.length)]);
神楽坂玲奈's avatar
神楽坂玲奈 committed
1625
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1626 1627
  };

1628
  ygopro.stoc_send_random_tip_to_room = function(room) {
mercury233's avatar
mercury233 committed
1629
    if (settings.modules.tips.enabled && settings.tips.length) {
mercury233's avatar
mercury233 committed
1630
      ygopro.stoc_send_chat_to_room(room, "Tip: " + settings.tips[Math.floor(Math.random() * settings.tips.length)]);
1631 1632 1633
    }
  };

mercury233's avatar
mercury233 committed
1634
  load_tips = function() {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1635
    request({
mercury233's avatar
mercury233 committed
1636
      url: settings.modules.tips.get,
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1637 1638
      json: true
    }, function(error, response, body) {
mercury233's avatar
mercury233 committed
1639 1640 1641 1642 1643 1644 1645
      if (_.isString(body)) {
        log.warn("tips bad json", body);
      } else if (error || !body) {
        log.warn('tips error', error, response);
      } else {
        nconf.myset(settings, "tips", body);
        log.info("tips loaded", settings.tips.length);
mercury233's avatar
mercury233 committed
1646
      }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1647
    });
mercury233's avatar
mercury233 committed
1648 1649
  };

mercury233's avatar
mercury233 committed
1650
  if (settings.modules.tips.get) {
mercury233's avatar
mercury233 committed
1651 1652
    load_tips();
    setInterval(function() {
mercury233's avatar
mercury233 committed
1653 1654 1655
      var j, len, room;
      for (j = 0, len = ROOM_all.length; j < len; j++) {
        room = ROOM_all[j];
1656
        if (room && room.established) {
1657
          if (!room.started || room.changing_side) {
1658 1659
            ygopro.stoc_send_random_tip_to_room(room);
          }
mercury233's avatar
mercury233 committed
1660 1661 1662
        }
      }
    }, 30000);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
1663
  }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1664 1665

  ygopro.stoc_follow('DUEL_START', false, function(buffer, info, client, server) {
mercury233's avatar
mercury233 committed
1666
    var deck_arena, deck_name, deck_text, j, len, player, ref, room;
1667 1668
    room = ROOM_all[client.rid];
    if (!room) {
1669 1670
      return;
    }
1671 1672
    if (!room.started) {
      room.started = true;
mercury233's avatar
mercury233 committed
1673
      room.start_time = moment().format();
mercury233's avatar
mercury233 committed
1674
      if (!room.windbot && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1675
        roomlist.start(room);
神楽坂玲奈's avatar
神楽坂玲奈 committed
1676
      }
1677 1678
      room.dueling_players = [];
      ref = room.players;
mercury233's avatar
mercury233 committed
1679 1680
      for (j = 0, len = ref.length; j < len; j++) {
        player = ref[j];
mercury233's avatar
mercury233 committed
1681 1682
        if (!(player.pos !== 7)) {
          continue;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
1683
        }
1684
        room.dueling_players[player.pos] = player;
mercury233's avatar
mercury233 committed
1685
        room.scores[player.name] = 0;
1686
        room.player_datas.push({
mercury233's avatar
mercury233 committed
1687
          ip: player.ip,
mercury233's avatar
mercury233 committed
1688 1689
          name: player.name
        });
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1690 1691
      }
    }
mercury233's avatar
mercury233 committed
1692
    if (settings.modules.tips.enabled) {
mercury233's avatar
test3  
mercury233 committed
1693
      ygopro.stoc_send_random_tip(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1694
    }
mercury233's avatar
mercury233 committed
1695
    if (settings.modules.deck_log.enabled && client.main && client.main.length && !client.deck_saved && !room.windbot) {
mercury233's avatar
mercury233 committed
1696
      deck_text = '#ygopro-server deck log\n#main\n' + client.main.join('\n') + '\n!side\n' + client.side.join('\n') + '\n';
mercury233's avatar
mercury233 committed
1697 1698 1699 1700 1701 1702 1703 1704
      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
1705
        deck_arena = deck_arena + 'athletic';
mercury233's avatar
mercury233 committed
1706 1707 1708
      } else {
        deck_arena = deck_arena + 'custom';
      }
mercury233's avatar
mercury233 committed
1709
      if (settings.modules.deck_log.local) {
mercury233's avatar
mercury233 committed
1710
        deck_name = moment().format('YYYY-MM-DD HH-mm-ss') + ' ' + room.port + ' ' + client.pos + ' ' + client.name.replace(/[\/\\\?\*]/g, '_');
mercury233's avatar
mercury233 committed
1711
        fs.writeFile(settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', function(err) {
mercury233's avatar
mercury233 committed
1712 1713 1714 1715 1716
          if (err) {
            return log.warn('DECK SAVE ERROR', err);
          }
        });
      }
mercury233's avatar
mercury233 committed
1717
      if (settings.modules.deck_log.post) {
mercury233's avatar
mercury233 committed
1718
        request.post({
mercury233's avatar
mercury233 committed
1719
          url: settings.modules.deck_log.post,
mercury233's avatar
mercury233 committed
1720
          form: {
mercury233's avatar
mercury233 committed
1721
            accesskey: settings.modules.deck_log.accesskey,
mercury233's avatar
mercury233 committed
1722 1723
            deck: deck_text,
            playername: client.name,
mercury233's avatar
mercury233 committed
1724
            arena: deck_arena
mercury233's avatar
mercury233 committed
1725 1726 1727
          }
        }, function(error, response, body) {
          if (error) {
mercury233's avatar
merge  
mercury233 committed
1728
            log.warn('DECK POST ERROR', error);
mercury233's avatar
mercury233 committed
1729 1730
          } else {
            if (response.statusCode !== 200) {
mercury233's avatar
merge  
mercury233 committed
1731
              log.warn('DECK POST FAIL', response.statusCode, client.name, body);
mercury233's avatar
mercury233 committed
1732 1733 1734 1735
            }
          }
        });
      }
mercury233's avatar
mercury233 committed
1736 1737
      client.deck_saved = true;
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1738 1739
  });

1740
  ygopro.ctos_follow('CHAT', true, function(buffer, info, client, server) {
mercury233's avatar
mercury233 committed
1741
    var cancel, cmd, msg, name, oldmsg, room, struct, windbot;
1742 1743
    room = ROOM_all[client.rid];
    if (!room) {
mercury233's avatar
mercury233 committed
1744 1745
      return;
    }
mercury233's avatar
mercury233 committed
1746 1747
    msg = _.trim(info.msg);
    cancel = _.startsWith(msg, "/");
1748 1749
    if (!(cancel || !room.random_type)) {
      room.last_active_time = moment();
1750
    }
mercury233's avatar
mercury233 committed
1751 1752
    cmd = msg.split(' ');
    switch (cmd[0]) {
mercury233's avatar
mercury233 committed
1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
      case '/投降':
      case '/surrender':
        if (!room.started || room.hostinfo.mode === 2) {
          return cancel;
        }
        if (room.random_type) {
          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
1769
      case '/help':
mercury233's avatar
mercury233 committed
1770 1771
        ygopro.stoc_send_chat(client, "${chat_order_main}");
        ygopro.stoc_send_chat(client, "${chat_order_help}");
mercury233's avatar
mercury233 committed
1772
        if (!settings.modules.mycard.enabled) {
mercury233's avatar
mercury233 committed
1773
          ygopro.stoc_send_chat(client, "${chat_order_roomname}");
mercury233's avatar
merge  
mercury233 committed
1774
        }
mercury233's avatar
mercury233 committed
1775
        if (settings.modules.windbot.enabled) {
mercury233's avatar
mercury233 committed
1776
          ygopro.stoc_send_chat(client, "${chat_order_windbot}");
mercury233's avatar
mercury233 committed
1777
        }
mercury233's avatar
mercury233 committed
1778
        if (settings.modules.tips.enabled) {
mercury233's avatar
mercury233 committed
1779
          ygopro.stoc_send_chat(client, "${chat_order_tip}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1780
        }
mercury233's avatar
mercury233 committed
1781
        break;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1782
      case '/tip':
mercury233's avatar
mercury233 committed
1783
        if (settings.modules.tips.enabled) {
mercury233's avatar
test3  
mercury233 committed
1784
          ygopro.stoc_send_random_tip(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1785
        }
mercury233's avatar
mercury233 committed
1786
        break;
mercury233's avatar
mercury233 committed
1787
      case '/ai':
mercury233's avatar
mercury233 committed
1788
        if (settings.modules.windbot.enabled) {
mercury233's avatar
mercury233 committed
1789 1790 1791 1792 1793
          if (name = cmd[1]) {
            windbot = _.sample(_.filter(settings.modules.windbots, function(w) {
              return w.name === name || w.deck === name;
            }));
            if (!windbot) {
mercury233's avatar
mercury233 committed
1794
              ygopro.stoc_send_chat(client, "${windbot_deck_not_found}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1795 1796 1797 1798 1799
              return;
            }
          } else {
            windbot = _.sample(settings.modules.windbots);
          }
mercury233's avatar
mercury233 committed
1800 1801 1802
          room.add_windbot(windbot);
        }
        break;
mercury233's avatar
mercury233 committed
1803
      case '/roomname':
1804
        if (room) {
mercury233's avatar
mercury233 committed
1805
          ygopro.stoc_send_chat(client, "${room_name} " + room.name, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
1806
        }
神楽坂玲奈's avatar
神楽坂玲奈 committed
1807
    }
mercury233's avatar
mercury233 committed
1808 1809 1810 1811 1812 1813 1814 1815
    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
1816 1817 1818
    if (!(room && room.random_type)) {
      return cancel;
    }
mercury233's avatar
mercury233 committed
1819
    if (client.abuse_count >= 5) {
mercury233's avatar
mercury233 committed
1820
      log.warn("BANNED CHAT", client.name, client.ip, msg);
mercury233's avatar
mercury233 committed
1821
      ygopro.stoc_send_chat(client, "${banned_chat_tip}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1822 1823
      return true;
    }
mercury233's avatar
mercury233 committed
1824 1825 1826
    oldmsg = msg;
    if (_.any(settings.ban.badword_level3, function(badword) {
      var regexp;
mercury233's avatar
fix  
mercury233 committed
1827
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
1828 1829
      return msg.match(regexp);
    }, msg)) {
mercury233's avatar
mercury233 committed
1830
      log.warn("BAD WORD LEVEL 3", client.name, client.ip, oldmsg);
mercury233's avatar
mercury233 committed
1831
      cancel = true;
mercury233's avatar
mercury233 committed
1832
      if (client.abuse_count > 0) {
mercury233's avatar
mercury233 committed
1833 1834 1835
        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);
mercury233's avatar
mercury233 committed
1836
        client.destroy();
mercury233's avatar
mercury233 committed
1837 1838 1839
        return true;
      } else {
        client.abuse_count = client.abuse_count + 4;
mercury233's avatar
mercury233 committed
1840
        ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1841
      }
mercury233's avatar
mercury233 committed
1842 1843 1844 1845 1846 1847 1848 1849 1850
    } else if (client.rag && room.started) {
      client.rag = false;
      cancel = true;
    } else if (_.any(settings.ban.spam_word, function(badword) {
      var regexp;
      regexp = new RegExp(badword, 'i');
      return msg.match(regexp);
    }, msg)) {
      client.abuse_count = client.abuse_count + 2;
mercury233's avatar
mercury233 committed
1851
      ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1852
      cancel = true;
mercury233's avatar
mercury233 committed
1853 1854
    } else if (_.any(settings.ban.badword_level2, function(badword) {
      var regexp;
mercury233's avatar
fix  
mercury233 committed
1855
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
1856 1857
      return msg.match(regexp);
    }, msg)) {
mercury233's avatar
mercury233 committed
1858
      log.warn("BAD WORD LEVEL 2", client.name, client.ip, oldmsg);
mercury233's avatar
mercury233 committed
1859
      client.abuse_count = client.abuse_count + 3;
mercury233's avatar
mercury233 committed
1860
      ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1861 1862 1863 1864
      cancel = true;
    } else {
      _.each(settings.ban.badword_level1, function(badword) {
        var regexp;
mercury233's avatar
fix  
mercury233 committed
1865
        regexp = new RegExp(badword, "ig");
mercury233's avatar
mercury233 committed
1866 1867 1868
        msg = msg.replace(regexp, "**");
      }, msg);
      if (oldmsg !== msg) {
mercury233's avatar
mercury233 committed
1869
        log.warn("BAD WORD LEVEL 1", client.name, client.ip, oldmsg);
mercury233's avatar
mercury233 committed
1870
        client.abuse_count = client.abuse_count + 1;
mercury233's avatar
mercury233 committed
1871
        ygopro.stoc_send_chat(client, "${chat_warn_level1}");
mercury233's avatar
mercury233 committed
1872 1873 1874 1875 1876 1877 1878 1879 1880
        struct = ygopro.structs["chat"];
        struct._setBuff(buffer);
        struct.set("msg", msg);
        buffer = struct.buffer;
      } else if (_.any(settings.ban.badword_level0, function(badword) {
        var regexp;
        regexp = new RegExp(badword, 'i');
        return msg.match(regexp);
      }, msg)) {
mercury233's avatar
mercury233 committed
1881
        log.info("BAD WORD LEVEL 0", client.name, client.ip, oldmsg);
mercury233's avatar
mercury233 committed
1882 1883
      }
    }
mercury233's avatar
mercury233 committed
1884 1885 1886
    if (client.abuse_count >= 2) {
      ROOM_unwelcome(room, client, "${random_ban_reason_abuse}");
    }
mercury233's avatar
mercury233 committed
1887
    if (client.abuse_count >= 5) {
mercury233's avatar
mercury233 committed
1888 1889
      ygopro.stoc_send_chat_to_room(room, client.name + " ${chat_banned}", ygopro.constants.COLORS.RED);
      ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}");
mercury233's avatar
mercury233 committed
1890
    }
1891
    return cancel;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1892 1893
  });

mercury233's avatar
mercury233 committed
1894
  ygopro.ctos_follow('UPDATE_DECK', true, function(buffer, info, client, server) {
mercury233's avatar
mercury233 committed
1895
    var buff_main, buff_side, card, current_deck, deck, deck_array, deck_main, deck_side, deck_text, deckbuf, decks, found_deck, i, j, k, len, len1, line, room, struct;
mercury233's avatar
mercury233 committed
1896 1897 1898 1899 1900
    room = ROOM_all[client.rid];
    if (!room) {
      return false;
    }
    buff_main = (function() {
mercury233's avatar
mercury233 committed
1901
      var j, ref, results;
1902
      results = [];
mercury233's avatar
mercury233 committed
1903
      for (i = j = 0, ref = info.mainc; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
1904
        results.push(info.deckbuf[i]);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1905
      }
1906
      return results;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1907
    })();
mercury233's avatar
mercury233 committed
1908
    buff_side = (function() {
mercury233's avatar
mercury233 committed
1909
      var j, ref, ref1, results;
1910
      results = [];
mercury233's avatar
mercury233 committed
1911
      for (i = j = ref = info.mainc, ref1 = info.mainc + info.sidec; ref <= ref1 ? j < ref1 : j > ref1; i = ref <= ref1 ? ++j : --j) {
1912
        results.push(info.deckbuf[i]);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1913
      }
1914
      return results;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1915
    })();
mercury233's avatar
mercury233 committed
1916 1917
    client.main = buff_main;
    client.side = buff_side;
1918
    if (room.random_type || room.arena) {
mercury233's avatar
mercury233 committed
1919 1920 1921 1922
      if (client.is_host) {
        room.waiting_for_player = room.waiting_for_player2;
      }
      room.last_active_time = moment();
mercury233's avatar
mercury233 committed
1923
    } else if (!room.started && room.hostinfo.mode === 1 && settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.deck_check) {
mercury233's avatar
mercury233 committed
1924 1925 1926 1927 1928 1929 1930 1931
      struct = ygopro.structs["deck"];
      struct._setBuff(buffer);
      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);
mercury233's avatar
mercury233 committed
1932 1933
      for (j = 0, len = decks.length; j < len; j++) {
        deck = decks[j];
mercury233's avatar
mercury233 committed
1934 1935 1936
        if (_.endsWith(deck, client.name + ".ydk")) {
          found_deck = deck;
        }
mercury233's avatar
fix  
mercury233 committed
1937 1938 1939
        if (_.endsWith(deck, client.name + ".ydk.ydk")) {
          found_deck = deck;
        }
mercury233's avatar
mercury233 committed
1940 1941
      }
      if (found_deck) {
mercury233's avatar
mercury233 committed
1942
        deck_text = fs.readFileSync(settings.modules.tournament_mode.deck_path + found_deck, {
mercury233's avatar
mercury233 committed
1943 1944 1945 1946 1947 1948
          encoding: "ASCII"
        });
        deck_array = deck_text.split("\n");
        deck_main = [];
        deck_side = [];
        current_deck = deck_main;
mercury233's avatar
mercury233 committed
1949 1950
        for (k = 0, len1 = deck_array.length; k < len1; k++) {
          line = deck_array[k];
mercury233's avatar
mercury233 committed
1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
          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;
mercury233's avatar
mercury233 committed
1965
          ygopro.stoc_send_chat(client, "${deck_correct_part1} " + found_deck + " ${deck_correct_part2}", ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
1966
        } else {
mercury233's avatar
mercury233 committed
1967
          ygopro.stoc_send_chat(client, "${deck_incorrect_part1} " + found_deck + " ${deck_incorrect_part2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1968 1969
        }
      } else {
mercury233's avatar
mercury233 committed
1970
        ygopro.stoc_send_chat(client, client.name + "${deck_not_found}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1971
      }
mercury233's avatar
mercury233 committed
1972
    }
mercury233's avatar
mercury233 committed
1973
    return false;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1974 1975
  });

1976
  ygopro.ctos_follow('RESPONSE', false, function(buffer, info, client, server) {
1977 1978
    var room;
    room = ROOM_all[client.rid];
1979
    if (!(room && (room.random_type || room.arena))) {
1980 1981
      return;
    }
1982
    room.last_active_time = moment();
1983 1984 1985
  });

  ygopro.ctos_follow('HAND_RESULT', false, function(buffer, info, client, server) {
1986 1987 1988
    var room;
    room = ROOM_all[client.rid];
    if (!(room && room.random_type)) {
1989 1990 1991
      return;
    }
    if (client.is_host) {
1992
      room.waiting_for_player = room.waiting_for_player2;
1993
    }
mercury233's avatar
mercury233 committed
1994
    room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's');
1995 1996 1997
  });

  ygopro.ctos_follow('TP_RESULT', false, function(buffer, info, client, server) {
1998 1999 2000
    var room;
    room = ROOM_all[client.rid];
    if (!(room && room.random_type)) {
2001 2002
      return;
    }
2003
    room.last_active_time = moment();
2004 2005 2006
  });

  ygopro.stoc_follow('SELECT_HAND', false, function(buffer, info, client, server) {
2007 2008 2009
    var room;
    room = ROOM_all[client.rid];
    if (!(room && room.random_type)) {
2010 2011 2012
      return;
    }
    if (client.is_host) {
2013
      room.waiting_for_player = client;
2014
    } else {
2015
      room.waiting_for_player2 = client;
2016
    }
mercury233's avatar
mercury233 committed
2017
    room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's');
2018 2019 2020
  });

  ygopro.stoc_follow('SELECT_TP', false, function(buffer, info, client, server) {
2021 2022
    var room;
    room = ROOM_all[client.rid];
2023
    if (!room) {
2024 2025
      return;
    }
2026 2027 2028 2029 2030
    room.changing_side = false;
    if (room.random_type) {
      room.waiting_for_player = client;
      room.last_active_time = moment();
    }
2031 2032
  });

mercury233's avatar
mercury233 committed
2033
  ygopro.stoc_follow('CHANGE_SIDE', false, function(buffer, info, client, server) {
2034 2035
    var room;
    room = ROOM_all[client.rid];
2036
    if (!room) {
mercury233's avatar
mercury233 committed
2037 2038
      return;
    }
2039 2040 2041 2042 2043 2044 2045 2046
    room.changing_side = true;
    if (room.random_type || room.arena) {
      if (client.is_host) {
        room.waiting_for_player = client;
      } else {
        room.waiting_for_player2 = client;
      }
      room.last_active_time = moment();
mercury233's avatar
mercury233 committed
2047 2048 2049
    }
  });

2050
  ygopro.stoc_follow('REPLAY', true, function(buffer, info, client, server) {
mercury233's avatar
mercury233 committed
2051
    var duellog, dueltime, i, j, len, player, ref, replay_filename, room;
2052 2053
    room = ROOM_all[client.rid];
    if (!room) {
mercury233's avatar
mercury233 committed
2054
      return settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe;
2055
    }
mercury233's avatar
mercury233 committed
2056
    if (settings.modules.cloud_replay.enabled && room.random_type) {
mercury233's avatar
fix  
mercury233 committed
2057 2058
      Cloud_replay_ids.push(room.cloud_replay_id);
    }
mercury233's avatar
mercury233 committed
2059
    if (settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe) {
mercury233's avatar
mercury233 committed
2060
      if (client.is_host) {
mercury233's avatar
mercury233 committed
2061 2062 2063
        dueltime = moment().format('YYYY-MM-DD HH:mm:ss');
        replay_filename = dueltime;
        ref = room.dueling_players;
mercury233's avatar
mercury233 committed
2064
        for (i = j = 0, len = ref.length; j < len; i = ++j) {
mercury233's avatar
mercury233 committed
2065 2066 2067 2068
          player = ref[i];
          replay_filename = replay_filename + (i > 0 ? " VS " : " ") + player.name;
        }
        replay_filename = replay_filename.replace(/[\/\\\?\*]/g, '_') + ".yrp";
mercury233's avatar
mercury233 committed
2069
        duellog = {
mercury233's avatar
mercury233 committed
2070
          time: dueltime,
mercury233's avatar
mercury233 committed
2071 2072 2073
          name: room.name,
          roomid: room.port.toString(),
          cloud_replay_id: "R#" + room.cloud_replay_id,
mercury233's avatar
mercury233 committed
2074
          replay_filename: replay_filename,
mercury233's avatar
mercury233 committed
2075
          players: (function() {
mercury233's avatar
mercury233 committed
2076
            var k, len1, ref1, results;
mercury233's avatar
mercury233 committed
2077
            ref1 = room.dueling_players;
mercury233's avatar
mercury233 committed
2078
            results = [];
mercury233's avatar
mercury233 committed
2079 2080
            for (k = 0, len1 = ref1.length; k < len1; k++) {
              player = ref1[k];
mercury233's avatar
mercury233 committed
2081 2082 2083 2084 2085 2086 2087 2088
              results.push({
                name: player.name,
                winner: player.pos === room.winner
              });
            }
            return results;
          })()
        };
mercury233's avatar
mercury233 committed
2089
        settings.modules.tournament_mode.duel_log.unshift(duellog);
mercury233's avatar
mercury233 committed
2090
        nconf.myset(settings, "modules:tournament_mode:duel_log", settings.modules.tournament_mode.duel_log);
mercury233's avatar
mercury233 committed
2091 2092 2093 2094 2095
        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
2096
      }
mercury233's avatar
mercury233 committed
2097
      if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2098
        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
2099
      }
2100 2101 2102 2103 2104 2105
      return true;
    } else {
      return false;
    }
  });

mercury233's avatar
mercury233 committed
2106
  if (settings.modules.random_duel.enabled) {
mercury233's avatar
mercury233 committed
2107
    setInterval(function() {
mercury233's avatar
mercury233 committed
2108 2109 2110
      var j, len, room, time_passed;
      for (j = 0, len = ROOM_all.length; j < len; j++) {
        room = ROOM_all[j];
mercury233's avatar
mercury233 committed
2111 2112 2113 2114
        if (!(room && room.started && room.random_type && room.last_active_time && room.waiting_for_player)) {
          continue;
        }
        time_passed = Math.floor((moment() - room.last_active_time) / 1000);
mercury233's avatar
mercury233 committed
2115
        if (time_passed >= settings.modules.random_duel.hang_timeout) {
mercury233's avatar
mercury233 committed
2116
          room.last_active_time = moment();
mercury233's avatar
mercury233 committed
2117 2118
          ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}");
          ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
2119
          room.waiting_for_player.server.destroy();
mercury233's avatar
mercury233 committed
2120
        } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
mercury233's avatar
mercury233 committed
2121
          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);
mercury233's avatar
mercury233 committed
2122
          ROOM_unwelcome(room, room.waiting_for_player, "${random_ban_reason_AFK}");
mercury233's avatar
mercury233 committed
2123
        }
2124
      }
mercury233's avatar
mercury233 committed
2125 2126 2127
    }, 1000);
  }

2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139
  if (settings.modules.mycard.enabled) {
    setInterval(function() {
      var j, len, room, time_passed;
      for (j = 0, len = ROOM_all.length; j < len; j++) {
        room = ROOM_all[j];
        if (!(room && room.started && room.arena && room.changing_side && room.last_active_time && room.waiting_for_player)) {
          continue;
        }
        time_passed = Math.floor((moment() - room.last_active_time) / 1000);
        if (time_passed >= settings.modules.random_duel.hang_timeout) {
          room.last_active_time = moment();
          ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
2140
          room.scores[room.waiting_for_player.name] = -1;
2141 2142 2143 2144 2145 2146 2147 2148
          room.waiting_for_player.server.destroy();
        } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
          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);
        }
      }
    }, 1000);
  }

mercury233's avatar
mercury233 committed
2149 2150
  if (settings.modules.windbot.spawn) {
    windbot_process = spawn('mono', ['WindBot.exe', settings.modules.windbot.port], {
mercury233's avatar
mercury233 committed
2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162
      cwd: 'windbot'
    });
    windbot_process.on('error', function(err) {
      log.warn('WindBot ERROR', err);
    });
    windbot_process.on('exit', function(code) {
      log.warn('WindBot EXIT', code);
    });
    windbot_process.stdout.setEncoding('utf8');
    windbot_process.stdout.on('data', function(data) {
      log.info('WindBot:', data);
    });
mercury233's avatar
fix  
mercury233 committed
2163
    windbot_process.stderr.setEncoding('utf8');
mercury233's avatar
mercury233 committed
2164 2165 2166 2167
    windbot_process.stderr.on('data', function(data) {
      log.warn('WindBot Error:', data);
    });
  }
2168

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2169
  if (settings.modules.http) {
mercury233's avatar
mercury233 committed
2170 2171 2172 2173 2174 2175
    addCallback = function(callback, text) {
      if (!callback) {
        return text;
      }
      return callback + "( " + text + " );";
    };
2176
    requestListener = function(request, response) {
mercury233's avatar
mercury233 committed
2177
      var duellog, filename, getpath, j, len, parseQueryString, pass_validated, player, room, roomsjson, u;
2178 2179 2180 2181
      parseQueryString = true;
      u = url.parse(request.url, parseQueryString);
      pass_validated = u.query.pass === settings.modules.http.password;
      if (u.pathname === '/api/getrooms') {
mercury233's avatar
mercury233 committed
2182
        if (!pass_validated && !settings.modules.http.public_roomlist) {
2183
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2184
          response.end(addCallback(u.query.callback, '{"rooms":[{"roomid":"0","roomname":"密码错误","needpass":"true"}]}'));
2185 2186 2187 2188
        } else {
          response.writeHead(200);
          roomsjson = JSON.stringify({
            rooms: (function() {
mercury233's avatar
mercury233 committed
2189
              var j, len, results;
2190
              results = [];
mercury233's avatar
mercury233 committed
2191 2192
              for (j = 0, len = ROOM_all.length; j < len; j++) {
                room = ROOM_all[j];
2193
                if (room && room.established) {
2194
                  results.push({
mercury233's avatar
mercury233 committed
2195
                    pid: room.process.pid.toString(),
2196 2197 2198 2199
                    roomid: room.port.toString(),
                    roomname: pass_validated ? room.name : room.name.split('$', 2)[0],
                    needpass: (room.name.indexOf('$') !== -1).toString(),
                    users: (function() {
mercury233's avatar
mercury233 committed
2200
                      var k, len1, ref, results1;
mercury233's avatar
mercury233 committed
2201
                      ref = room.players;
2202
                      results1 = [];
mercury233's avatar
mercury233 committed
2203 2204
                      for (k = 0, len1 = ref.length; k < len1; k++) {
                        player = ref[k];
2205 2206 2207 2208 2209 2210 2211
                        if (player.pos != null) {
                          results1.push({
                            id: (-1).toString(),
                            name: player.name,
                            pos: player.pos
                          });
                        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2212
                      }
2213 2214 2215 2216 2217
                      return results1;
                    })(),
                    istart: room.started ? 'start' : 'wait'
                  });
                }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2218
              }
2219 2220
              return results;
            })()
mercury233's avatar
mercury233 committed
2221 2222
          }, null, 2);
          response.end(addCallback(u.query.callback, roomsjson));
2223
        }
mercury233's avatar
mercury233 committed
2224
      } else if (u.pathname === '/api/duellog' && settings.modules.tournament_mode.enabled) {
mercury233's avatar
mercury233 committed
2225
        if (!(u.query.pass === settings.modules.tournament_mode.password)) {
mercury233's avatar
mercury233 committed
2226
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2227
          response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"));
mercury233's avatar
mercury233 committed
2228 2229 2230
          return;
        } else {
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2231
          duellog = JSON.stringify(settings.modules.tournament_mode.duel_log, null, 2);
mercury233's avatar
mercury233 committed
2232
          response.end(addCallback(u.query.callback, duellog));
mercury233's avatar
mercury233 committed
2233
        }
mercury233's avatar
mercury233 committed
2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254
      } else if (_.startsWith(u.pathname, '/api/replay') && settings.modules.tournament_mode.enabled) {
        if (!(u.query.pass === settings.modules.tournament_mode.password)) {
          response.writeHead(403);
          response.end("密码错误");
          return;
        } else {
          getpath = u.pathname.split("/");
          filename = decodeURIComponent(getpath.pop());
          fs.readFile(settings.modules.tournament_mode.replay_path + filename, function(error, buffer) {
            if (error) {
              response.writeHead(404);
              return response.end("未找到文件 " + filename);
            } else {
              response.writeHead(200, {
                "Content-Type": "application/octet-stream",
                "Content-Disposition": "attachment"
              });
              return response.end(buffer);
            }
          });
        }
2255 2256 2257
      } else if (u.pathname === '/api/message') {
        if (!pass_validated) {
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2258
          response.end(addCallback(u.query.callback, "['密码错误', 0]"));
2259 2260 2261
          return;
        }
        if (u.query.shout) {
mercury233's avatar
mercury233 committed
2262 2263
          for (j = 0, len = ROOM_all.length; j < len; j++) {
            room = ROOM_all[j];
2264 2265 2266
            if (room && room.established) {
              ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW);
            }
2267 2268
          }
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2269
          response.end(addCallback(u.query.callback, "['shout ok', '" + u.query.shout + "']"));
2270 2271 2272 2273 2274 2275
        } else if (u.query.stop) {
          if (u.query.stop === 'false') {
            u.query.stop = false;
          }
          settings.modules.stop = u.query.stop;
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2276
          response.end(addCallback(u.query.callback, "['stop ok', '" + u.query.stop + "']"));
2277
        } else if (u.query.welcome) {
mercury233's avatar
mercury233 committed
2278 2279
          nconf.myset(settings, 'modules:welcome', u.query.welcome);
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2280
          response.end(addCallback(u.query.callback, "['welcome ok', '" + u.query.welcome + "']"));
mercury233's avatar
mercury233 committed
2281
        } else if (u.query.getwelcome) {
2282
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2283
          response.end(addCallback(u.query.callback, "['get ok', '" + settings.modules.welcome + "']"));
mercury233's avatar
mercury233 committed
2284 2285 2286
        } else if (u.query.loadtips) {
          load_tips();
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2287
          response.end(addCallback(u.query.callback, "['loading tip', '" + settings.modules.tips.get + "']"));
mercury233's avatar
mercury233 committed
2288 2289 2290
        } else if (u.query.loaddialogues) {
          load_dialogues();
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2291
          response.end(addCallback(u.query.callback, "['loading dialogues', '" + settings.modules.dialogues.get + "']"));
mercury233's avatar
mercury233 committed
2292
        } else if (u.query.ban) {
mercury233's avatar
mercury233 committed
2293
          ban_user(u.query.ban);
mercury233's avatar
mercury233 committed
2294
          response.writeHead(200);
mercury233's avatar
mercury233 committed
2295
          response.end(addCallback(u.query.callback, "['ban ok', '" + u.query.ban + "']"));
2296
        } else {
mercury233's avatar
mercury233 committed
2297
          response.writeHead(400);
2298
          response.end();
2299
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2300
      } else {
mercury233's avatar
mercury233 committed
2301
        response.writeHead(400);
mercury233's avatar
test3  
mercury233 committed
2302
        response.end();
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2303
      }
2304 2305
    };
    http_server = http.createServer(requestListener);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2306
    http_server.listen(settings.modules.http.port);
mercury233's avatar
mercury233 committed
2307
    if (settings.modules.http.ssl.enabled) {
2308 2309 2310 2311 2312 2313
      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);
mercury233's avatar
fix  
mercury233 committed
2314
      roomlist.init(https_server, ROOM_all);
2315 2316
      https_server.listen(settings.modules.http.ssl.port);
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2317
  }
神楽坂玲奈's avatar
神楽坂玲奈 committed
2318

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