1. #include "stdafx.h"
  2. #include <sstream>
  3. #ifndef __WIN32__
  4. #include <ifaddrs.h>
  5. #endif
  6. #include "constants.h"
  7. #include "utils.h"
  8. #include "log.h"
  9. #include "desc.h"
  10. #include "desc_manager.h"
  11. #include "item_manager.h"
  12. #include "p2p.h"
  13. #include "char.h"
  14. #include "ip_ban.h"
  15. #include "war_map.h"
  16. #include "locale_service.h"
  17. #include "config.h"
  18. #include "dev_log.h"
  19. #include "db.h"
  20. #include "skill_power.h"
  21. using std::string;
  22. BYTE g_bChannel = 0;
  23. WORD mother_port = 50080;
  24. int passes_per_sec = 25;
  25. WORD db_port = 0;
  26. WORD p2p_port = 50900;
  27. char db_addr[ADDRESS_MAX_LEN + 1];
  28. int save_event_second_cycle = passes_per_sec * 120; // 3분
  29. int ping_event_second_cycle = passes_per_sec * 60;
  30. bool g_bNoMoreClient = false;
  31. bool g_bNoRegen = false;
  32. bool g_bNoPasspod = false;
  33. // TRAFFIC_PROFILER
  34. bool g_bTrafficProfileOn = false;
  35. DWORD g_dwTrafficProfileFlushCycle = 3600;
  36. // END_OF_TRAFFIC_PROFILER
  37. int test_server = 0;
  38. int speed_server = 0;
  39. #ifdef __AUCTION__
  40. int auction_server = 0;
  41. #endif
  42. bool distribution_test_server = false;
  43. bool china_event_server = false;
  44. bool guild_mark_server = true;
  45. BYTE guild_mark_min_level = 3;
  46. bool no_wander = false;
  47. int g_iUserLimit = 32768;
  48. char g_szPublicIP[16] = "0";
  49. char g_szInternalIP[16] = "0";
  50. bool g_bSkillDisable = false;
  51. int g_iFullUserCount = 1200;
  52. int g_iBusyUserCount = 650;
  53. //Canada
  54. //int g_iFullUserCount = 600;
  55. //int g_iBusyUserCount = 350;
  56. //Brazil
  57. //int g_iFullUserCount = 650;
  58. //int g_iBusyUserCount = 450;
  59. bool g_bEmpireWhisper = true;
  60. BYTE g_bAuthServer = false;
  61. bool g_bCheckClientVersion = true;
  62. string g_stClientVersion = "1215955205";
  63. BYTE g_bBilling = false;
  64. string g_stAuthMasterIP;
  65. WORD g_wAuthMasterPort = 0;
  66. static std::set<DWORD> s_set_dwFileCRC;
  67. static std::set<DWORD> s_set_dwProcessCRC;
  68. string g_stHostname = "";
  69. string g_table_postfix = "";
  70. string g_stQuestDir = "./quest";
  71. //string g_stQuestObjectDir = "./quest/object";
  72. string g_stDefaultQuestObjectDir = "./quest/object";
  73. std::set<string> g_setQuestObjectDir;
  74. std::vector<std::string> g_stAdminPageIP;
  75. std::string g_stAdminPagePassword = "SHOWMETHEMONEY";
  76. string g_stBlockDate = "30000705";
  77. extern string g_stLocale;
  78. char teen_addr[ADDRESS_MAX_LEN + 1] = {0};
  79. WORD teen_port = 0;
  80. int SPEEDHACK_LIMIT_COUNT = 50;
  81. int SPEEDHACK_LIMIT_BONUS = 80;
  82. int g_iSyncHackLimitCount = 20; // 10 -> 20 2013 09 11 CYH
  83. //시야 = VIEW_RANGE + VIEW_BONUS_RANGE
  84. //VIEW_BONUSE_RANGE : 클라이언트와 시야 처리에서너무 딱 떨어질경우 문제가 발생할수있어 500CM의 여분을 항상준다.
  85. int VIEW_RANGE = 5000;
  86. int VIEW_BONUS_RANGE = 500;
  87. int g_server_id = 0;
  88. string g_strWebMallURL = "www.metin2.de";
  89. unsigned int g_uiSpamBlockDuration = 60 * 15; // 기본 15분
  90. unsigned int g_uiSpamBlockScore = 100; // 기본 100점
  91. unsigned int g_uiSpamReloadCycle = 60 * 10; // 기본 10분
  92. bool g_bCheckMultiHack = true;
  93. int g_iSpamBlockMaxLevel = 10;
  94. void LoadStateUserCount();
  95. void LoadValidCRCList();
  96. bool LoadClientVersion();
  97. bool g_protectNormalPlayer = false; // 범법자가 "평화모드" 인 일반유저를 공격하지 못함
  98. bool g_noticeBattleZone = false; // 중립지대에 입장하면 안내메세지를 알려줌
  99. bool isHackShieldEnable = false;
  100. int HackShield_FirstCheckWaitTime = passes_per_sec * 30;
  101. int HackShield_CheckCycleTime = passes_per_sec * 180;
  102. bool bXTrapEnabled = false;
  103. int gPlayerMaxLevel = 99;
  104. bool g_BlockCharCreation = false;
  105. //OPENID
  106. int openid_server = 0;
  107. char openid_host[256];
  108. char openid_uri[256];
  109. bool is_string_true(const char * string)
  110. {
  111. bool result = 0;
  112. if (isnhdigit(*string))
  113. {
  114. str_to_number(result, string);
  115. return result > 0 ? true : false;
  116. }
  117. else if (LOWER(*string) == 't')
  118. return true;
  119. else
  120. return false;
  121. }
  122. static std::set<int> s_set_map_allows;
  123. bool map_allow_find(int index)
  124. {
  125. if (g_bAuthServer)
  126. return false;
  127. if (s_set_map_allows.find(index) == s_set_map_allows.end())
  128. return false;
  129. return true;
  130. }
  131. void map_allow_log()
  132. {
  133. std::set<int>::iterator i;
  134. for (i = s_set_map_allows.begin(); i != s_set_map_allows.end(); ++i)
  135. sys_log(0, "MAP_ALLOW: %d", *i);
  136. }
  137. void map_allow_add(int index)
  138. {
  139. if (map_allow_find(index) == true)
  140. {
  141. fprintf(stdout, "!!! FATAL ERROR !!! multiple MAP_ALLOW setting!!\n");
  142. exit(1);
  143. }
  144. fprintf(stdout, "MAP ALLOW %d\n", index);
  145. s_set_map_allows.insert(index);
  146. }
  147. void map_allow_copy(long * pl, int size)
  148. {
  149. int iCount = 0;
  150. std::set<int>::iterator it = s_set_map_allows.begin();
  151. while (it != s_set_map_allows.end())
  152. {
  153. int i = *(it++);
  154. *(pl++) = i;
  155. if (++iCount > size)
  156. break;
  157. }
  158. }
  159. static void FN_add_adminpageIP(char *line)
  160. {
  161. char *last;
  162. const char *delim = " \t\r\n";
  163. char *v = strtok_r(line, delim, &last);
  164. while (v)
  165. {
  166. g_stAdminPageIP.push_back(v);
  167. v = strtok_r(NULL, delim, &last);
  168. }
  169. }
  170. static void FN_log_adminpage()
  171. {
  172. itertype(g_stAdminPageIP) iter = g_stAdminPageIP.begin();
  173. while (iter != g_stAdminPageIP.end())
  174. {
  175. dev_log(LOG_DEB0, "ADMIN_PAGE_IP = %s", (*iter).c_str());
  176. ++iter;
  177. }
  178. dev_log(LOG_DEB0, "ADMIN_PAGE_PASSWORD = %s", g_stAdminPagePassword.c_str());
  179. }
  180. bool GetIPInfo()
  181. {
  182. #ifndef __WIN32__
  183. struct ifaddrs* ifaddrp = NULL;
  184. if (0 != getifaddrs(&ifaddrp))
  185. return false;
  186. for( struct ifaddrs* ifap=ifaddrp ; NULL != ifap ; ifap = ifap->ifa_next )
  187. {
  188. struct sockaddr_in * sai = (struct sockaddr_in *) ifap->ifa_addr;
  189. if (!ifap->ifa_netmask || // ignore if no netmask
  190. sai->sin_addr.s_addr == 0 || // ignore if address is 0.0.0.0
  191. sai->sin_addr.s_addr == 16777343) // ignore if address is 127.0.0.1
  192. continue;
  193. #else
  194. WSADATA wsa_data;
  195. char host_name[100];
  196. HOSTENT* host_ent;
  197. int n = 0;
  198. if (WSAStartup(0x0101, &wsa_data)) {
  199. return false;
  200. }
  201. gethostname(host_name, sizeof(host_name));
  202. host_ent = gethostbyname(host_name);
  203. if (host_ent == NULL) {
  204. return false;
  205. }
  206. for ( ; host_ent->h_addr_list[n] != NULL; ++n) {
  207. struct sockaddr_in addr;
  208. struct sockaddr_in* sai = &addr;
  209. memcpy(&sai->sin_addr.s_addr, host_ent->h_addr_list[n], host_ent->h_length);
  210. #endif
  211. char * netip = inet_ntoa(sai->sin_addr);
  212. if (!strncmp(netip, "999.999", 7)) // ignore if address is starting with 192
  213. {
  214. strlcpy(g_szInternalIP, netip, sizeof(g_szInternalIP));
  215. #ifndef __WIN32__
  216. fprintf(stderr, "INTERNAL_IP: %s interface %s\n", netip, ifap->ifa_name);
  217. #else
  218. fprintf(stderr, "INTERNAL_IP: %s\n", netip);
  219. #endif
  220. }
  221. else if (!strncmp(netip, "10.", 3))
  222. {
  223. strlcpy(g_szInternalIP, netip, sizeof(g_szInternalIP));
  224. #ifndef __WIN32__
  225. fprintf(stderr, "INTERNAL_IP: %s interface %s\n", netip, ifap->ifa_name);
  226. #else
  227. fprintf(stderr, "INTERNAL_IP: %s\n", netip);
  228. #endif
  229. }
  230. else if (g_szPublicIP[0] == '0')
  231. {
  232. strlcpy(g_szPublicIP, netip, sizeof(g_szPublicIP));
  233. #ifndef __WIN32__
  234. fprintf(stderr, "PUBLIC_IP: %s interface %s\n", netip, ifap->ifa_name);
  235. #else
  236. fprintf(stderr, "PUBLIC_IP: %s\n", netip);
  237. #endif
  238. }
  239. }
  240. #ifndef __WIN32__
  241. freeifaddrs( ifaddrp );
  242. #else
  243. WSACleanup();
  244. #endif
  245. if (g_szPublicIP[0] != '0')
  246. return true;
  247. else
  248. return false;
  249. }
  250. void config_init(const string& st_localeServiceName)
  251. {
  252. FILE *fp;
  253. char buf[256];
  254. char token_string[256];
  255. char value_string[256];
  256. // LOCALE_SERVICE
  257. string st_configFileName;
  258. st_configFileName.reserve(32);
  259. st_configFileName = "CONFIG";
  260. if (!st_localeServiceName.empty())
  261. {
  262. st_configFileName += ".";
  263. st_configFileName += st_localeServiceName;
  264. }
  265. // END_OF_LOCALE_SERVICE
  266. if (!(fp = fopen(st_configFileName.c_str(), "r")))
  267. {
  268. fprintf(stderr, "Can not open [%s]\n", st_configFileName.c_str());
  269. exit(1);
  270. }
  271. if (!GetIPInfo())
  272. {
  273. fprintf(stderr, "Can not get public ip address\n");
  274. exit(1);
  275. }
  276. char db_host[2][64], db_user[2][64], db_pwd[2][64], db_db[2][64];
  277. // ... 아... db_port는 이미 있는데... 네이밍 어찌해야함...
  278. int mysql_db_port[2];
  279. for (int n = 0; n < 2; ++n)
  280. {
  281. *db_host[n] = '\0';
  282. *db_user[n] = '\0';
  283. *db_pwd[n]= '\0';
  284. *db_db[n]= '\0';
  285. mysql_db_port[n] = 0;
  286. }
  287. char log_host[64], log_user[64], log_pwd[64], log_db[64];
  288. int log_port = 0;
  289. *log_host = '\0';
  290. *log_user = '\0';
  291. *log_pwd = '\0';
  292. *log_db = '\0';
  293. // DB에서 로케일정보를 세팅하기위해서는 다른 세팅값보다 선행되어서
  294. // DB정보만 읽어와 로케일 세팅을 한후 다른 세팅을 적용시켜야한다.
  295. // 이유는 로케일관련된 초기화 루틴이 곳곳에 존재하기 때문.
  296. bool isCommonSQL = false;
  297. bool isPlayerSQL = false;
  298. FILE* fpOnlyForDB;
  299. if (!(fpOnlyForDB = fopen(st_configFileName.c_str(), "r")))
  300. {
  301. fprintf(stderr, "Can not open [%s]\n", st_configFileName.c_str());
  302. exit(1);
  303. }
  304. while (fgets(buf, 256, fpOnlyForDB))
  305. {
  306. parse_token(buf, token_string, value_string);
  307. TOKEN("BLOCK_LOGIN")
  308. {
  309. g_stBlockDate = value_string;
  310. }
  311. TOKEN("adminpage_ip")
  312. {
  313. FN_add_adminpageIP(value_string);
  314. //g_stAdminPageIP[0] = value_string;
  315. }
  316. TOKEN("adminpage_ip1")
  317. {
  318. FN_add_adminpageIP(value_string);
  319. //g_stAdminPageIP[0] = value_string;
  320. }
  321. TOKEN("adminpage_ip2")
  322. {
  323. FN_add_adminpageIP(value_string);
  324. //g_stAdminPageIP[1] = value_string;
  325. }
  326. TOKEN("adminpage_ip3")
  327. {
  328. FN_add_adminpageIP(value_string);
  329. //g_stAdminPageIP[2] = value_string;
  330. }
  331. TOKEN("adminpage_password")
  332. {
  333. g_stAdminPagePassword = value_string;
  334. }
  335. TOKEN("hostname")
  336. {
  337. g_stHostname = value_string;
  338. fprintf(stdout, "HOSTNAME: %s\n", g_stHostname.c_str());
  339. continue;
  340. }
  341. TOKEN("channel")
  342. {
  343. str_to_number(g_bChannel, value_string);
  344. continue;
  345. }
  346. TOKEN("player_sql")
  347. {
  348. const char * line = two_arguments(value_string, db_host[0], sizeof(db_host[0]), db_user[0], sizeof(db_user[0]));
  349. line = two_arguments(line, db_pwd[0], sizeof(db_pwd[0]), db_db[0], sizeof(db_db[0]));
  350. if ('\0' != line[0])
  351. {
  352. char buf[256];
  353. one_argument(line, buf, sizeof(buf));
  354. str_to_number(mysql_db_port[0], buf);
  355. }
  356. if (!*db_host[0] || !*db_user[0] || !*db_pwd[0] || !*db_db[0])
  357. {
  358. fprintf(stderr, "PLAYER_SQL syntax: logsql <host user password db>\n");
  359. exit(1);
  360. }
  361. char buf[1024];
  362. snprintf(buf, sizeof(buf), "PLAYER_SQL: %s %s %s %s %d", db_host[0], db_user[0], db_pwd[0], db_db[0], mysql_db_port[0]);
  363. isPlayerSQL = true;
  364. continue;
  365. }
  366. TOKEN("common_sql")
  367. {
  368. const char * line = two_arguments(value_string, db_host[1], sizeof(db_host[1]), db_user[1], sizeof(db_user[1]));
  369. line = two_arguments(line, db_pwd[1], sizeof(db_pwd[1]), db_db[1], sizeof(db_db[1]));
  370. if ('\0' != line[0])
  371. {
  372. char buf[256];
  373. one_argument(line, buf, sizeof(buf));
  374. str_to_number(mysql_db_port[1], buf);
  375. }
  376. if (!*db_host[1] || !*db_user[1] || !*db_pwd[1] || !*db_db[1])
  377. {
  378. fprintf(stderr, "COMMON_SQL syntax: logsql <host user password db>\n");
  379. exit(1);
  380. }
  381. char buf[1024];
  382. snprintf(buf, sizeof(buf), "COMMON_SQL: %s %s %s %s %d", db_host[1], db_user[1], db_pwd[1], db_db[1], mysql_db_port[1]);
  383. isCommonSQL = true;
  384. continue;
  385. }
  386. TOKEN("log_sql")
  387. {
  388. const char * line = two_arguments(value_string, log_host, sizeof(log_host), log_user, sizeof(log_user));
  389. line = two_arguments(line, log_pwd, sizeof(log_pwd), log_db, sizeof(log_db));
  390. if ('\0' != line[0])
  391. {
  392. char buf[256];
  393. one_argument(line, buf, sizeof(buf));
  394. str_to_number(log_port, buf);
  395. }
  396. if (!*log_host || !*log_user || !*log_pwd || !*log_db)
  397. {
  398. fprintf(stderr, "LOG_SQL syntax: logsql <host user password db>\n");
  399. exit(1);
  400. }
  401. char buf[1024];
  402. snprintf(buf, sizeof(buf), "LOG_SQL: %s %s %s %s %d", log_host, log_user, log_pwd, log_db, log_port);
  403. continue;
  404. }
  405. //OPENID
  406. TOKEN("WEB_AUTH")
  407. {
  408. //const char * line = two_arguments(value_string, openid_host, sizeof(openid_host), openid_uri, sizeof(openid_uri));
  409. if (!*openid_host || !*openid_uri)
  410. {
  411. fprintf(stderr, "WEB_AUTH syntax error (ex: WEB_AUTH <host(metin2.co.kr) uri(/kyw/gameauth.php)>\n");
  412. exit(1);
  413. }
  414. char buf[1024];
  415. openid_server = 1;
  416. snprintf(buf, sizeof(buf), "WEB_AUTH: %s %s", openid_host, openid_uri);
  417. continue;
  418. }
  419. }
  420. //처리가 끝났으니 파일을 닫자.
  421. fclose(fpOnlyForDB);
  422. // CONFIG_SQL_INFO_ERROR
  423. if (!isCommonSQL)
  424. {
  425. puts("LOAD_COMMON_SQL_INFO_FAILURE:");
  426. puts("");
  427. puts("CONFIG:");
  428. puts("------------------------------------------------");
  429. puts("COMMON_SQL: HOST USER PASSWORD DATABASE");
  430. puts("");
  431. exit(1);
  432. }
  433. if (!isPlayerSQL)
  434. {
  435. puts("LOAD_PLAYER_SQL_INFO_FAILURE:");
  436. puts("");
  437. puts("CONFIG:");
  438. puts("------------------------------------------------");
  439. puts("PLAYER_SQL: HOST USER PASSWORD DATABASE");
  440. puts("");
  441. exit(1);
  442. }
  443. // Common DB 가 Locale 정보를 가지고 있기 때문에 가장 먼저 접속해야 한다.
  444. AccountDB::instance().Connect(db_host[1], mysql_db_port[1], db_user[1], db_pwd[1], db_db[1]);
  445. if (false == AccountDB::instance().IsConnected())
  446. {
  447. fprintf(stderr, "cannot start server while no common sql connected\n");
  448. exit(1);
  449. }
  450. fprintf(stdout, "CommonSQL connected\n");
  451. // 로케일 정보를 가져오자
  452. // <경고> 쿼리문에 절대 조건문(WHERE) 달지 마세요. (다른 지역에서 문제가 생길수 있습니다)
  453. {
  454. char szQuery[512];
  455. snprintf(szQuery, sizeof(szQuery), "SELECT mKey, mValue FROM locale");
  456. std::auto_ptr<SQLMsg> pMsg(AccountDB::instance().DirectQuery(szQuery));
  457. if (pMsg->Get()->uiNumRows == 0)
  458. {
  459. fprintf(stderr, "COMMON_SQL: DirectQuery failed : %s\n", szQuery);
  460. exit(1);
  461. }
  462. MYSQL_ROW row;
  463. while (NULL != (row = mysql_fetch_row(pMsg->Get()->pSQLResult)))
  464. {
  465. // 로케일 세팅
  466. if (strcasecmp(row[0], "LOCALE") == 0)
  467. {
  468. if (LocaleService_Init(row[1]) == false)
  469. {
  470. fprintf(stderr, "COMMON_SQL: invalid locale key %s\n", row[1]);
  471. exit(1);
  472. }
  473. }
  474. }
  475. }
  476. // 로케일 정보를 COMMON SQL에 세팅해준다.
  477. // 참고로 g_stLocale 정보는 LocaleService_Init() 내부에서 세팅된다.
  478. fprintf(stdout, "Setting DB to locale %s\n", g_stLocale.c_str());
  479. AccountDB::instance().SetLocale(g_stLocale);
  480. AccountDB::instance().ConnectAsync(db_host[1], mysql_db_port[1], db_user[1], db_pwd[1], db_db[1], g_stLocale.c_str());
  481. // Player DB 접속
  482. DBManager::instance().Connect(db_host[0], mysql_db_port[0], db_user[0], db_pwd[0], db_db[0]);
  483. if (!DBManager::instance().IsConnected())
  484. {
  485. fprintf(stderr, "PlayerSQL.ConnectError\n");
  486. exit(1);
  487. }
  488. fprintf(stdout, "PlayerSQL connected\n");
  489. if (false == g_bAuthServer) // 인증 서버가 아닐 경우
  490. {
  491. // Log DB 접속
  492. LogManager::instance().Connect(log_host, log_port, log_user, log_pwd, log_db);
  493. if (!LogManager::instance().IsConnected())
  494. {
  495. fprintf(stderr, "LogSQL.ConnectError\n");
  496. exit(1);
  497. }
  498. fprintf(stdout, "LogSQL connected\n");
  499. LogManager::instance().BootLog(g_stHostname.c_str(), g_bChannel);
  500. }
  501. // SKILL_POWER_BY_LEVEL
  502. // 스트링 비교의 문제로 인해서 AccountDB::instance().SetLocale(g_stLocale) 후부터 한다.
  503. // 물론 국내는 별로 문제가 안된다(해외가 문제)
  504. {
  505. char szQuery[256];
  506. snprintf(szQuery, sizeof(szQuery), "SELECT mValue FROM locale WHERE mKey='SKILL_POWER_BY_LEVEL'");
  507. std::auto_ptr<SQLMsg> pMsg(AccountDB::instance().DirectQuery(szQuery));
  508. if (pMsg->Get()->uiNumRows == 0)
  509. {
  510. fprintf(stderr, "[SKILL_PERCENT] Query failed: %s", szQuery);
  511. exit(1);
  512. }
  513. MYSQL_ROW row;
  514. row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  515. const char * p = row[0];
  516. int cnt = 0;
  517. char num[128];
  518. int aiBaseSkillPowerByLevelTable[SKILL_MAX_LEVEL+1];
  519. fprintf(stdout, "SKILL_POWER_BY_LEVEL %s\n", p);
  520. while (*p != '\0' && cnt < (SKILL_MAX_LEVEL + 1))
  521. {
  522. p = one_argument(p, num, sizeof(num));
  523. aiBaseSkillPowerByLevelTable[cnt++] = atoi(num);
  524. //fprintf(stdout, "%d %d\n", cnt - 1, aiBaseSkillPowerByLevelTable[cnt - 1]);
  525. if (*p == '\0')
  526. {
  527. if (cnt != (SKILL_MAX_LEVEL + 1))
  528. {
  529. fprintf(stderr, "[SKILL_PERCENT] locale table has not enough skill information! (count: %d query: %s)", cnt, szQuery);
  530. exit(1);
  531. }
  532. fprintf(stdout, "SKILL_POWER_BY_LEVEL: Done! (count %d)\n", cnt);
  533. break;
  534. }
  535. }
  536. // 종족별 스킬 세팅
  537. for (int job = 0; job < JOB_MAX_NUM * 2; ++job)
  538. {
  539. snprintf(szQuery, sizeof(szQuery), "SELECT mValue from locale where mKey='SKILL_POWER_BY_LEVEL_TYPE%d' ORDER BY CAST(mValue AS unsigned)", job);
  540. std::auto_ptr<SQLMsg> pMsg(AccountDB::instance().DirectQuery(szQuery));
  541. // 세팅이 안되어있으면 기본테이블을 사용한다.
  542. if (pMsg->Get()->uiNumRows == 0)
  543. {
  544. CTableBySkill::instance().SetSkillPowerByLevelFromType(job, aiBaseSkillPowerByLevelTable);
  545. continue;
  546. }
  547. row = mysql_fetch_row(pMsg->Get()->pSQLResult);
  548. cnt = 0;
  549. p = row[0];
  550. int aiSkillTable[SKILL_MAX_LEVEL + 1];
  551. fprintf(stdout, "SKILL_POWER_BY_JOB %d %s\n", job, p);
  552. while (*p != '\0' && cnt < (SKILL_MAX_LEVEL + 1))
  553. {
  554. p = one_argument(p, num, sizeof(num));
  555. aiSkillTable[cnt++] = atoi(num);
  556. //fprintf(stdout, "%d %d\n", cnt - 1, aiBaseSkillPowerByLevelTable[cnt - 1]);
  557. if (*p == '\0')
  558. {
  559. if (cnt != (SKILL_MAX_LEVEL + 1))
  560. {
  561. fprintf(stderr, "[SKILL_PERCENT] locale table has not enough skill information! (count: %d query: %s)", cnt, szQuery);
  562. exit(1);
  563. }
  564. fprintf(stdout, "SKILL_POWER_BY_JOB: Done! (job: %d count: %d)\n", job, cnt);
  565. break;
  566. }
  567. }
  568. CTableBySkill::instance().SetSkillPowerByLevelFromType(job, aiSkillTable);
  569. }
  570. }
  571. // END_SKILL_POWER_BY_LEVEL
  572. // LOG_KEEP_DAYS_EXTEND
  573. log_set_expiration_days(2);
  574. // END_OF_LOG_KEEP_DAYS_EXTEND
  575. while (fgets(buf, 256, fp))
  576. {
  577. parse_token(buf, token_string, value_string);
  578. TOKEN("empire_whisper")
  579. {
  580. bool b_value = 0;
  581. str_to_number(b_value, value_string);
  582. g_bEmpireWhisper = !!b_value;
  583. continue;
  584. }
  585. TOKEN("mark_server")
  586. {
  587. guild_mark_server = is_string_true(value_string);
  588. continue;
  589. }
  590. TOKEN("mark_min_level")
  591. {
  592. str_to_number(guild_mark_min_level, value_string);
  593. guild_mark_min_level = MINMAX(0, guild_mark_min_level, GUILD_MAX_LEVEL);
  594. continue;
  595. }
  596. TOKEN("port")
  597. {
  598. str_to_number(mother_port, value_string);
  599. continue;
  600. }
  601. TOKEN("log_keep_days")
  602. {
  603. int i = 0;
  604. str_to_number(i, value_string);
  605. log_set_expiration_days(MINMAX(1, i, 90));
  606. continue;
  607. }
  608. TOKEN("passes_per_sec")
  609. {
  610. str_to_number(passes_per_sec, value_string);
  611. continue;
  612. }
  613. TOKEN("p2p_port")
  614. {
  615. str_to_number(p2p_port, value_string);
  616. continue;
  617. }
  618. TOKEN("db_port")
  619. {
  620. str_to_number(db_port, value_string);
  621. continue;
  622. }
  623. TOKEN("db_addr")
  624. {
  625. strlcpy(db_addr, value_string, sizeof(db_addr));
  626. for (int n =0; n < ADDRESS_MAX_LEN; ++n)
  627. {
  628. if (db_addr[n] == ' ')
  629. db_addr[n] = '\0';
  630. }
  631. continue;
  632. }
  633. TOKEN("save_event_second_cycle")
  634. {
  635. int cycle = 0;
  636. str_to_number(cycle, value_string);
  637. save_event_second_cycle = cycle * passes_per_sec;
  638. continue;
  639. }
  640. TOKEN("ping_event_second_cycle")
  641. {
  642. int cycle = 0;
  643. str_to_number(cycle, value_string);
  644. ping_event_second_cycle = cycle * passes_per_sec;
  645. continue;
  646. }
  647. TOKEN("table_postfix")
  648. {
  649. g_table_postfix = value_string;
  650. continue;
  651. }
  652. TOKEN("test_server")
  653. {
  654. printf("-----------------------------------------------\n");
  655. printf("TEST_SERVER\n");
  656. printf("-----------------------------------------------\n");
  657. str_to_number(test_server, value_string);
  658. continue;
  659. }
  660. TOKEN("speed_server")
  661. {
  662. printf("-----------------------------------------------\n");
  663. printf("SPEED_SERVER\n");
  664. printf("-----------------------------------------------\n");
  665. str_to_number(speed_server, value_string);
  666. continue;
  667. }
  668. #ifdef __AUCTION__
  669. TOKEN("auction_server")
  670. {
  671. printf("-----------------------------------------------\n");
  672. printf("AUCTION_SERVER\n");
  673. printf("-----------------------------------------------\n");
  674. str_to_number(auction_server, value_string);
  675. continue;
  676. }
  677. #endif
  678. TOKEN("distribution_test_server")
  679. {
  680. str_to_number(distribution_test_server, value_string);
  681. continue;
  682. }
  683. TOKEN("china_event_server")
  684. {
  685. str_to_number(china_event_server, value_string);
  686. continue;
  687. }
  688. TOKEN("shutdowned")
  689. {
  690. g_bNoMoreClient = true;
  691. continue;
  692. }
  693. TOKEN("no_regen")
  694. {
  695. g_bNoRegen = true;
  696. continue;
  697. }
  698. TOKEN("traffic_profile")
  699. {
  700. g_bTrafficProfileOn = true;
  701. continue;
  702. }
  703. TOKEN("map_allow")
  704. {
  705. char * p = value_string;
  706. string stNum;
  707. for (; *p; p++)
  708. {
  709. if (isnhspace(*p))
  710. {
  711. if (stNum.length())
  712. {
  713. int index = 0;
  714. str_to_number(index, stNum.c_str());
  715. map_allow_add(index);
  716. stNum.clear();
  717. }
  718. }
  719. else
  720. stNum += *p;
  721. }
  722. if (stNum.length())
  723. {
  724. int index = 0;
  725. str_to_number(index, stNum.c_str());
  726. map_allow_add(index);
  727. }
  728. continue;
  729. }
  730. TOKEN("no_wander")
  731. {
  732. no_wander = true;
  733. continue;
  734. }
  735. TOKEN("user_limit")
  736. {
  737. str_to_number(g_iUserLimit, value_string);
  738. continue;
  739. }
  740. TOKEN("skill_disable")
  741. {
  742. str_to_number(g_bSkillDisable, value_string);
  743. continue;
  744. }
  745. TOKEN("auth_server")
  746. {
  747. char szIP[32];
  748. char szPort[32];
  749. two_arguments(value_string, szIP, sizeof(szIP), szPort, sizeof(szPort));
  750. if (!*szIP || (!*szPort && strcasecmp(szIP, "master")))
  751. {
  752. fprintf(stderr, "AUTH_SERVER: syntax error: <ip|master> <port>\n");
  753. exit(1);
  754. }
  755. g_bAuthServer = true;
  756. LoadBanIP("BANIP");
  757. if (!strcasecmp(szIP, "master"))
  758. fprintf(stdout, "AUTH_SERVER: I am the master\n");
  759. else
  760. {
  761. g_stAuthMasterIP = szIP;
  762. str_to_number(g_wAuthMasterPort, szPort);
  763. fprintf(stdout, "AUTH_SERVER: master %s %u\n", g_stAuthMasterIP.c_str(), g_wAuthMasterPort);
  764. }
  765. continue;
  766. }
  767. TOKEN("billing")
  768. {
  769. g_bBilling = true;
  770. }
  771. TOKEN("quest_dir")
  772. {
  773. sys_log(0, "QUEST_DIR SETTING : %s", value_string);
  774. g_stQuestDir = value_string;
  775. }
  776. TOKEN("quest_object_dir")
  777. {
  778. //g_stQuestObjectDir = value_string;
  779. std::istringstream is(value_string);
  780. sys_log(0, "QUEST_OBJECT_DIR SETTING : %s", value_string);
  781. string dir;
  782. while (!is.eof())
  783. {
  784. is >> dir;
  785. if (is.fail())
  786. break;
  787. g_setQuestObjectDir.insert(dir);
  788. sys_log(0, "QUEST_OBJECT_DIR INSERT : %s", dir .c_str());
  789. }
  790. }
  791. TOKEN("teen_addr")
  792. {
  793. strlcpy(teen_addr, value_string, sizeof(teen_addr));
  794. for (int n =0; n < ADDRESS_MAX_LEN; ++n)
  795. {
  796. if (teen_addr[n] == ' ')
  797. teen_addr[n] = '\0';
  798. }
  799. continue;
  800. }
  801. TOKEN("teen_port")
  802. {
  803. str_to_number(teen_port, value_string);
  804. }
  805. TOKEN("synchack_limit_count")
  806. {
  807. str_to_number(g_iSyncHackLimitCount, value_string);
  808. }
  809. TOKEN("speedhack_limit_count")
  810. {
  811. str_to_number(SPEEDHACK_LIMIT_COUNT, value_string);
  812. }
  813. TOKEN("speedhack_limit_bonus")
  814. {
  815. str_to_number(SPEEDHACK_LIMIT_BONUS, value_string);
  816. }
  817. TOKEN("server_id")
  818. {
  819. str_to_number(g_server_id, value_string);
  820. }
  821. TOKEN("mall_url")
  822. {
  823. g_strWebMallURL = value_string;
  824. }
  825. TOKEN("bind_ip")
  826. {
  827. strlcpy(g_szPublicIP, value_string, sizeof(g_szPublicIP));
  828. }
  829. TOKEN("view_range")
  830. {
  831. str_to_number(VIEW_RANGE, value_string);
  832. }
  833. TOKEN("spam_block_duration")
  834. {
  835. str_to_number(g_uiSpamBlockDuration, value_string);
  836. }
  837. TOKEN("spam_block_score")
  838. {
  839. str_to_number(g_uiSpamBlockScore, value_string);
  840. g_uiSpamBlockScore = MAX(1, g_uiSpamBlockScore);
  841. }
  842. TOKEN("spam_block_reload_cycle")
  843. {
  844. str_to_number(g_uiSpamReloadCycle, value_string);
  845. g_uiSpamReloadCycle = MAX(60, g_uiSpamReloadCycle); // 최소 1분
  846. }
  847. TOKEN("check_multihack")
  848. {
  849. str_to_number(g_bCheckMultiHack, value_string);
  850. }
  851. TOKEN("spam_block_max_level")
  852. {
  853. str_to_number(g_iSpamBlockMaxLevel, value_string);
  854. }
  855. TOKEN("protect_normal_player")
  856. {
  857. str_to_number(g_protectNormalPlayer, value_string);
  858. }
  859. TOKEN("notice_battle_zone")
  860. {
  861. str_to_number(g_noticeBattleZone, value_string);
  862. }
  863. TOKEN("hackshield_enable")
  864. {
  865. int flag = 0;
  866. str_to_number(flag, value_string);
  867. //if (1 == flag && LC_IsEurope() )
  868. if (1 == flag)
  869. {
  870. isHackShieldEnable = true;
  871. }
  872. }
  873. TOKEN("hackshield_first_check_time")
  874. {
  875. int secs = 30;
  876. str_to_number(secs, value_string);
  877. HackShield_FirstCheckWaitTime = passes_per_sec * secs;
  878. }
  879. TOKEN("hackshield_check_cycle_time")
  880. {
  881. int secs = 180;
  882. str_to_number(secs, value_string);
  883. HackShield_CheckCycleTime = passes_per_sec * secs;
  884. }
  885. TOKEN("xtrap_enable")
  886. {
  887. int flag = 0;
  888. str_to_number(flag, value_string);
  889. if (1 == flag )
  890. {
  891. bXTrapEnabled = true;
  892. }
  893. }
  894. TOKEN("pk_protect_level")
  895. {
  896. str_to_number(PK_PROTECT_LEVEL, value_string);
  897. fprintf(stderr, "PK_PROTECT_LEVEL: %d", PK_PROTECT_LEVEL);
  898. }
  899. TOKEN("max_level")
  900. {
  901. str_to_number(gPlayerMaxLevel, value_string);
  902. gPlayerMaxLevel = MINMAX(1, gPlayerMaxLevel, PLAYER_MAX_LEVEL_CONST);
  903. fprintf(stderr, "PLAYER_MAX_LEVEL: %d\n", gPlayerMaxLevel);
  904. }
  905. TOKEN("block_char_creation")
  906. {
  907. int tmp = 0;
  908. str_to_number(tmp, value_string);
  909. if (0 == tmp)
  910. g_BlockCharCreation = false;
  911. else
  912. g_BlockCharCreation = true;
  913. continue;
  914. }
  915. }
  916. if (g_setQuestObjectDir.empty())
  917. g_setQuestObjectDir.insert(g_stDefaultQuestObjectDir);
  918. if (0 == db_port)
  919. {
  920. fprintf(stderr, "DB_PORT not configured\n");
  921. exit(1);
  922. }
  923. if (0 == g_bChannel)
  924. {
  925. fprintf(stderr, "CHANNEL not configured\n");
  926. exit(1);
  927. }
  928. if (g_stHostname.empty())
  929. {
  930. fprintf(stderr, "HOSTNAME must be configured.\n");
  931. exit(1);
  932. }
  933. // LOCALE_SERVICE
  934. LocaleService_LoadLocaleStringFile();
  935. LocaleService_TransferDefaultSetting();
  936. LocaleService_LoadEmpireTextConvertTables();
  937. // END_OF_LOCALE_SERVICE
  938. fclose(fp);
  939. if ((fp = fopen("CMD", "r")))
  940. {
  941. while (fgets(buf, 256, fp))
  942. {
  943. char cmd[32], levelname[32];
  944. int level;
  945. two_arguments(buf, cmd, sizeof(cmd), levelname, sizeof(levelname));
  946. if (!*cmd || !*levelname)
  947. {
  948. fprintf(stderr, "CMD syntax error: <cmd> <DISABLE | LOW_WIZARD | WIZARD | HIGH_WIZARD | GOD>\n");
  949. exit(1);
  950. }
  951. if (!strcasecmp(levelname, "LOW_WIZARD"))
  952. level = GM_LOW_WIZARD;
  953. else if (!strcasecmp(levelname, "WIZARD"))
  954. level = GM_WIZARD;
  955. else if (!strcasecmp(levelname, "HIGH_WIZARD"))
  956. level = GM_HIGH_WIZARD;
  957. else if (!strcasecmp(levelname, "GOD"))
  958. level = GM_GOD;
  959. else if (!strcasecmp(levelname, "IMPLEMENTOR"))
  960. level = GM_IMPLEMENTOR;
  961. else if (!strcasecmp(levelname, "DISABLE"))
  962. level = GM_IMPLEMENTOR + 1;
  963. else
  964. {
  965. fprintf(stderr, "CMD syntax error: <cmd> <DISABLE | LOW_WIZARD | WIZARD | HIGH_WIZARD | GOD>\n");
  966. exit(1);
  967. }
  968. interpreter_set_privilege(cmd, level);
  969. }
  970. fclose(fp);
  971. }
  972. LoadValidCRCList();
  973. LoadStateUserCount();
  974. CWarMapManager::instance().LoadWarMapInfo(NULL);
  975. FN_log_adminpage();
  976. }
  977. const char* get_table_postfix()
  978. {
  979. return g_table_postfix.c_str();
  980. }
  981. void LoadValidCRCList()
  982. {
  983. s_set_dwProcessCRC.clear();
  984. s_set_dwFileCRC.clear();
  985. FILE * fp;
  986. char buf[256];
  987. if ((fp = fopen("CRC", "r")))
  988. {
  989. while (fgets(buf, 256, fp))
  990. {
  991. if (!*buf)
  992. continue;
  993. DWORD dwValidClientProcessCRC;
  994. DWORD dwValidClientFileCRC;
  995. sscanf(buf, " %u %u ", &dwValidClientProcessCRC, &dwValidClientFileCRC);
  996. s_set_dwProcessCRC.insert(dwValidClientProcessCRC);
  997. s_set_dwFileCRC.insert(dwValidClientFileCRC);
  998. fprintf(stderr, "CLIENT_CRC: %u %u\n", dwValidClientProcessCRC, dwValidClientFileCRC);
  999. }
  1000. fclose(fp);
  1001. }
  1002. }
  1003. bool LoadClientVersion()
  1004. {
  1005. FILE * fp = fopen("VERSION", "r");
  1006. if (!fp)
  1007. return false;
  1008. char buf[256];
  1009. fgets(buf, 256, fp);
  1010. char * p = strchr(buf, '\n');
  1011. if (p) *p = '\0';
  1012. fprintf(stderr, "VERSION: \"%s\"\n", buf);
  1013. g_stClientVersion = buf;
  1014. fclose(fp);
  1015. return true;
  1016. }
  1017. void CheckClientVersion()
  1018. {
  1019. if (LC_IsEurope())
  1020. {
  1021. g_bCheckClientVersion = true;
  1022. }
  1023. else
  1024. {
  1025. g_bCheckClientVersion = false;
  1026. }
  1027. const DESC_MANAGER::DESC_SET & set = DESC_MANAGER::instance().GetClientSet();
  1028. DESC_MANAGER::DESC_SET::const_iterator it = set.begin();
  1029. while (it != set.end())
  1030. {
  1031. LPDESC d = *(it++);
  1032. if (!d->GetCharacter())
  1033. continue;
  1034. int version = atoi(g_stClientVersion.c_str());
  1035. int date = atoi(d->GetClientVersion() );
  1036. //if (0 != g_stClientVersion.compare(d->GetClientVersion()) )
  1037. if (version != date)
  1038. {
  1039. d->GetCharacter()->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("클라이언트 버전이 틀려 로그아웃 됩니다. 정상적으로 패치 후 접속하세요."));
  1040. d->DelayedDisconnect(10);
  1041. }
  1042. }
  1043. }
  1044. void LoadStateUserCount()
  1045. {
  1046. FILE * fp = fopen("state_user_count", "r");
  1047. if (!fp)
  1048. return;
  1049. if (!LC_IsHongKong())
  1050. fscanf(fp, " %d %d ", &g_iFullUserCount, &g_iBusyUserCount);
  1051. fclose(fp);
  1052. }
  1053. bool IsValidProcessCRC(DWORD dwCRC)
  1054. {
  1055. return s_set_dwProcessCRC.find(dwCRC) != s_set_dwProcessCRC.end();
  1056. }
  1057. bool IsValidFileCRC(DWORD dwCRC)
  1058. {
  1059. return s_set_dwFileCRC.find(dwCRC) != s_set_dwFileCRC.end();
  1060. }

asd