#include "StdAfx.h" #include "PythonApplication.h" #include "ProcessScanner.h" #include "PythonExceptionSender.h" #include "resource.h" #include "Version.h" #ifdef _DEBUG #include #endif #include "eterLib/Util.h" #include "EterBase/lzo.h" #include "PackLib/PackManager.h" #include #include extern "C" { extern int _fltused; volatile int _AVOID_FLOATING_POINT_LIBRARY_BUG = _fltused; }; extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; } #pragma comment(linker, "/NODEFAULTLIB:libci.lib") #include bool __IS_TEST_SERVER_MODE__=false; extern bool SetDefaultCodePage(DWORD codePage); static const char * sc_apszPythonLibraryFilenames[] = { "UserDict.pyc", "__future__.pyc", "copy_reg.pyc", "linecache.pyc", "ntpath.pyc", "os.pyc", "site.pyc", "stat.pyc", "string.pyc", "traceback.pyc", "types.pyc", "\n", }; char gs_szErrorString[512] = ""; void ApplicationSetErrorString(const char* szErrorString) { strcpy(gs_szErrorString, szErrorString); } bool CheckPythonLibraryFilenames() { for (int i = 0; *sc_apszPythonLibraryFilenames[i] != '\n'; ++i) { std::string stFilename = "lib\\"; stFilename += sc_apszPythonLibraryFilenames[i]; if (_access(stFilename.c_str(), 0) != 0) { return false; } MoveFile(stFilename.c_str(), stFilename.c_str()); } return true; } struct ApplicationStringTable { HINSTANCE m_hInstance; std::map m_kMap_dwID_stLocale; } gs_kAppStrTable; void ApplicationStringTable_Initialize(HINSTANCE hInstance) { gs_kAppStrTable.m_hInstance=hInstance; } const std::string& ApplicationStringTable_GetString(DWORD dwID, LPCSTR szKey) { char szBuffer[512]; char szIniFileName[256]; char szLocale[256]; ::GetCurrentDirectory(sizeof(szIniFileName), szIniFileName); if(szIniFileName[lstrlen(szIniFileName)-1] != '\\') strcat(szIniFileName, "\\"); strcat(szIniFileName, "metin2client.dat"); strcpy(szLocale, LocaleService_GetLocalePath()); if(strnicmp(szLocale, "locale/", strlen("locale/")) == 0) strcpy(szLocale, LocaleService_GetLocalePath() + strlen("locale/")); ::GetPrivateProfileString(szLocale, szKey, NULL, szBuffer, sizeof(szBuffer)-1, szIniFileName); if(szBuffer[0] == '\0') LoadString(gs_kAppStrTable.m_hInstance, dwID, szBuffer, sizeof(szBuffer)-1); if(szBuffer[0] == '\0') ::GetPrivateProfileString("en", szKey, NULL, szBuffer, sizeof(szBuffer)-1, szIniFileName); if(szBuffer[0] == '\0') strcpy(szBuffer, szKey); std::string& rstLocale=gs_kAppStrTable.m_kMap_dwID_stLocale[dwID]; rstLocale=szBuffer; return rstLocale; } const std::string& ApplicationStringTable_GetString(DWORD dwID) { char szBuffer[512]; LoadString(gs_kAppStrTable.m_hInstance, dwID, szBuffer, sizeof(szBuffer)-1); std::string& rstLocale=gs_kAppStrTable.m_kMap_dwID_stLocale[dwID]; rstLocale=szBuffer; return rstLocale; } const char* ApplicationStringTable_GetStringz(DWORD dwID, LPCSTR szKey) { return ApplicationStringTable_GetString(dwID, szKey).c_str(); } const char* ApplicationStringTable_GetStringz(DWORD dwID) { return ApplicationStringTable_GetString(dwID).c_str(); } //////////////////////////////////////////// int Setup(LPSTR lpCmdLine); // Internal function forward bool PackInitialize(const char * c_pszFolder) { NANOBEGIN if (_access(c_pszFolder, 0) != 0) return false; std::vector packFiles = { "patch1", "season3_eu", "patch2", "metin2_patch_snow", "metin2_patch_snow_dungeon", "metin2_patch_etc_costume1", "metin2_patch_pet1", "metin2_patch_pet2", "metin2_patch_ramadan_costume", "metin2_patch_flame", "metin2_patch_flame_dungeon", "metin2_patch_w21_etc", "metin2_patch_w21_mobs", "metin2_patch_w21_mobs_m", "metin2_patch_dss_box", "metin2_patch_costume_soccer", "metin2_patch_easter1", "metin2_patch_mineral", "metin2_patch_w20_sound", "metin2_patch_ds", "metin2_patch_5th_armor", "metin2_patch_w20_etc", "metin2_patch_dragon_rock", "metin2_patch_dragon_rock_mobs", "metin2_patch_dragon_rock_texcache", "metin2_patch_dragon_rock_mobs_texcache", "metin2_patch_etc", "metin2_patch_xmas", "metin2_patch_eu3", "metin2_patch_eu4", "metin2_patch_mundi", "metin2_patch_sd", "metin2_patch_halloween", "metin2_patch_party", "metin2_patch_dance", "pc", "pc2", "monster", "monster2", "effect", "zone", "terrain", "npc", "npc2", "tree", "guild", "item", "textureset", "property", "icon", "season1", "season2", "outdoora1", "outdoora2", "outdoora3", "outdoorb1", "outdoorb3", "outdoorc1", "outdoorc3", "outdoorsnow1", "outdoordesert1", "outdoorflame1", "outdoorfielddungeon1", "outdoort1", "outdoort2", "outdoort3", "outdoort4", "outdoorwedding", "outdoormilgyo1", "indoorspiderdungeon1", "indoordeviltower1", "indoormonkeydungeon1", "indoormonkeydungeon2", "indoormonkeydungeon3", "outdoortrent", "outdoortrent02", "outdoorguild1", "outdoorguild2", "outdoorguild3", "outdoorduel", "outdoorgmguildbuild", "sound", "sound_m", "sound2", "bgm", "locale_ca", "locale_ae", "locale_de", "locale_es", "locale_fr", "locale_gr", "locale_it", "locale_nl", "locale_pl", "locale_pt", "locale_tr", "locale_uk", "locale_bg", "locale_en", "locale_mx", "locale_ro", "locale_ru", "locale_dk", "locale_cz", "locale_hu", "locale_us", "locale_pa", "uiscript", "ETC", "uiloading", }; CPackManager::instance().AddPack(std::format("{}/root.pck", c_pszFolder)); for (const std::string& packFileName : packFiles) { CPackManager::instance().AddPack(std::format("{}/{}.pck", c_pszFolder, packFileName)); } NANOEND return true; } bool RunMainScript(CPythonLauncher& pyLauncher, const char* lpCmdLine) { initpack(); initdbg(); initime(); initgrp(); initgrpImage(); initgrpText(); initwndMgr(); ///////////////////////////////////////////// initudp(); initapp(); initsystem(); initchr(); initchrmgr(); initPlayer(); initItem(); initNonPlayer(); initTrade(); initChat(); initTextTail(); initnet(); initMiniMap(); initProfiler(); initEvent(); initeffect(); initfly(); initsnd(); initeventmgr(); initshop(); initskill(); initquest(); initBackground(); initMessenger(); initsafebox(); initguild(); initServerStateChecker(); NANOBEGIN // RegisterDebugFlag { std::string stRegisterDebugFlag; #ifdef _DISTRIBUTE stRegisterDebugFlag ="__DEBUG__ = 0"; #else stRegisterDebugFlag ="__DEBUG__ = 1"; #endif if (!pyLauncher.RunLine(stRegisterDebugFlag.c_str())) { TraceError("RegisterDebugFlag Error"); return false; } } // RegisterCommandLine { std::string stRegisterCmdLine; const char * loginMark = "-cs"; const char * loginMark_NonEncode = "-ncs"; const char * seperator = " "; std::string stCmdLine; const int CmdSize = 3; std::vector stVec; SplitLine(lpCmdLine,seperator,&stVec); if (CmdSize == stVec.size() && stVec[0]==loginMark) { char buf[MAX_PATH]; //TODO 아래 함수 string 형태로 수정 base64_decode(stVec[2].c_str(),buf); stVec[2] = buf; string_join(seperator,stVec,&stCmdLine); } else if (CmdSize <= stVec.size() && stVec[0]==loginMark_NonEncode) { stVec[0] = loginMark; string_join(" ",stVec,&stCmdLine); } else stCmdLine = lpCmdLine; stRegisterCmdLine ="__COMMAND_LINE__ = "; stRegisterCmdLine+='"'; stRegisterCmdLine+=stCmdLine; stRegisterCmdLine+='"'; const CHAR* c_szRegisterCmdLine=stRegisterCmdLine.c_str(); if (!pyLauncher.RunLine(c_szRegisterCmdLine)) { TraceError("RegisterCommandLine Error"); return false; } } { std::vector stVec; SplitLine(lpCmdLine," " ,&stVec); if (stVec.size() != 0 && "--pause-before-create-window" == stVec[0]) { system("pause"); } if (!pyLauncher.RunFile("system.py")) { TraceError("RunMain Error"); return false; } } NANOEND return true; } bool Main(HINSTANCE hInstance, LPSTR lpCmdLine) { #ifdef LOCALE_SERVICE_YMIR extern bool g_isScreenShotKey; g_isScreenShotKey = true; #endif DWORD dwRandSeed=time(NULL)+DWORD(GetCurrentProcess()); srandom(dwRandSeed); srand(random()); SetLogLevel(1); #ifdef LOCALE_SERVICE_VIETNAM_MILD extern BOOL USE_VIETNAM_CONVERT_WEAPON_VNUM; USE_VIETNAM_CONVERT_WEAPON_VNUM = true; #endif if (_access("perf_game_update.txt", 0)==0) { DeleteFile("perf_game_update.txt"); } if (_access("newpatch.exe", 0)==0) { system("patchupdater.exe"); return false; } if (!Setup(lpCmdLine)) return false; #ifdef _DEBUG OpenConsoleWindow(); OpenLogFile(true); // true == uses syserr.txt and log.txt #else OpenLogFile(false); // false == uses syserr.txt only #endif static CLZO lzo; CPackManager packMgr; if (!PackInitialize("pack")) { LogBox("Pack Initialization failed. Check log.txt file.."); return false; } if(LocaleService_LoadGlobal(hInstance)) SetDefaultCodePage(LocaleService_GetCodePage()); CPythonApplication * app = new CPythonApplication; app->Initialize(hInstance); bool ret=false; { CPythonLauncher pyLauncher; CPythonExceptionSender pyExceptionSender; SetExceptionSender(&pyExceptionSender); if (pyLauncher.Create()) { ret=RunMainScript(pyLauncher, lpCmdLine); //게임 실행중엔 함수가 끝나지 않는다. } //ProcessScanner_ReleaseQuitEvent(); //게임 종료시. app->Clear(); timeEndPeriod(1); pyLauncher.Clear(); } app->Destroy(); delete app; return ret; } HANDLE CreateMetin2GameMutex() { SECURITY_ATTRIBUTES sa; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; return CreateMutex(&sa, FALSE, "Metin2GameMutex"); } void DestroyMetin2GameMutex(HANDLE hMutex) { if (hMutex) { ReleaseMutex(hMutex); hMutex = NULL; } } void __ErrorPythonLibraryIsNotExist() { LogBoxf("FATAL ERROR!! Python Library file not exist!"); } bool __IsTimeStampOption(LPSTR lpCmdLine) { const char* TIMESTAMP = "/timestamp"; return (strncmp(lpCmdLine, TIMESTAMP, strlen(TIMESTAMP))==0); } void __PrintTimeStamp() { #ifdef _DEBUG if (__IS_TEST_SERVER_MODE__) LogBoxf("METIN2 BINARY TEST DEBUG VERSION %s ( MS C++ %d Compiled )", __TIMESTAMP__, _MSC_VER); else LogBoxf("METIN2 BINARY DEBUG VERSION %s ( MS C++ %d Compiled )", __TIMESTAMP__, _MSC_VER); #else if (__IS_TEST_SERVER_MODE__) LogBoxf("METIN2 BINARY TEST VERSION %s ( MS C++ %d Compiled )", __TIMESTAMP__, _MSC_VER); else LogBoxf("METIN2 BINARY DISTRIBUTE VERSION %s ( MS C++ %d Compiled )", __TIMESTAMP__, _MSC_VER); #endif } bool __IsLocaleOption(LPSTR lpCmdLine) { return (strcmp(lpCmdLine, "--locale") == 0); } bool __IsLocaleVersion(LPSTR lpCmdLine) { return (strcmp(lpCmdLine, "--perforce-revision") == 0); } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { #ifdef _DEBUG _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_CRT_DF | _CRTDBG_LEAK_CHECK_DF ); //_CrtSetBreakAlloc( 110247 ); #endif ApplicationStringTable_Initialize(hInstance); LocaleService_LoadConfig("config/locale.cfg"); SetDefaultCodePage(LocaleService_GetCodePage()); bool bQuit = false; int nArgc = 0; PCHAR* szArgv = CommandLineToArgv( lpCmdLine, &nArgc ); for( int i=0; i < nArgc; i++ ) { if(szArgv[i] == 0) continue; if (__IsLocaleVersion(szArgv[i])) // #0000829: [M2EU] 버전 파일이 항상 생기지 않도록 수정 { char szModuleName[MAX_PATH]; char szVersionPath[MAX_PATH]; GetModuleFileName(NULL, szModuleName, sizeof(szModuleName)); sprintf(szVersionPath, "%s.version", szModuleName); FILE* fp = fopen(szVersionPath, "wt"); if (fp) { extern int METIN2_GET_VERSION(); fprintf(fp, "r%d\n", METIN2_GET_VERSION()); fclose(fp); } bQuit = true; } else if (__IsLocaleOption(szArgv[i])) { FILE* fp=fopen("locale.txt", "wt"); fprintf(fp, "service[%s] code_page[%d]", LocaleService_GetName(), LocaleService_GetCodePage()); fclose(fp); bQuit = true; } else if (__IsTimeStampOption(szArgv[i])) { __PrintTimeStamp(); bQuit = true; } else if ((strcmp(szArgv[i], "--force-set-locale") == 0)) { // locale 설정엔 인자가 두 개 더 필요함 (로케일 명칭, 데이터 경로) if (nArgc <= i + 2) { MessageBox(NULL, "Invalid arguments", ApplicationStringTable_GetStringz(IDS_APP_NAME, "APP_NAME"), MB_ICONSTOP); goto Clean; } const char* localeName = szArgv[++i]; const char* localePath = szArgv[++i]; LocaleService_ForceSetLocale(localeName, localePath); } } if(bQuit) goto Clean; if (!CheckPythonLibraryFilenames()) { __ErrorPythonLibraryIsNotExist(); goto Clean; } Main(hInstance, lpCmdLine); ::CoUninitialize(); if(gs_szErrorString[0]) MessageBox(NULL, gs_szErrorString, ApplicationStringTable_GetStringz(IDS_APP_NAME, "APP_NAME"), MB_ICONSTOP); Clean: SAFE_FREE_GLOBAL(szArgv); return 0; } static void GrannyError(granny_log_message_type Type, granny_log_message_origin Origin, char const* File, granny_int32x Line, char const* Message, void* UserData) { TraceError("GRANNY: %s", Message); } int Setup(LPSTR lpCmdLine) { /* * 타이머 정밀도를 올린다. */ TIMECAPS tc; UINT wTimerRes; if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) return 0; wTimerRes = MINMAX(tc.wPeriodMin, 1, tc.wPeriodMax); timeBeginPeriod(wTimerRes); /* * 그래니 에러 핸들링 */ granny_log_callback Callback; Callback.Function = nullptr; Callback.UserData = 0; GrannySetLogCallback(&Callback); return 1; }