forked from metin-server/m2dev-client-src
This commit is well documented, so no need to tell you my life story. Full Unicode patch with RTL Support & BiDi logic. Removed the legacy codePage, normalised to UTF8 (65001). It also comes with: CTRL + A : select text (highlighted) CTRL + C : copy CTRL + V : paste CTRL + X : cut CTRL + Y : redo CTRL + Z : undo
329 lines
6.3 KiB
C++
329 lines
6.3 KiB
C++
#include "StdAfx.h"
|
|
#include "PythonApplication.h"
|
|
#include "ProcessScanner.h"
|
|
#include "PythonExceptionSender.h"
|
|
#include "resource.h"
|
|
#include "Version.h"
|
|
|
|
#ifdef _DEBUG
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
#include "eterLib/Util.h"
|
|
#include "EterBase/lzo.h"
|
|
|
|
#include "PackLib/PackManager.h"
|
|
|
|
#include <filesystem>
|
|
#include <format>
|
|
|
|
#include <stdlib.h>
|
|
#include <utf8.h>
|
|
|
|
extern "C" {
|
|
extern int _fltused;
|
|
FILE __iob_func[3] = { *stdin, *stdout, *stderr };
|
|
volatile int _AVOID_FLOATING_POINT_LIBRARY_BUG = _fltused;
|
|
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
|
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
|
};
|
|
|
|
#pragma comment(linker, "/NODEFAULTLIB:libci.lib")
|
|
|
|
int Setup(LPSTR lpCmdLine);
|
|
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",
|
|
};
|
|
|
|
bool CheckPythonLibraryFilenames()
|
|
{
|
|
for (int i = 0; *sc_apszPythonLibraryFilenames[i] != '\n'; ++i)
|
|
{
|
|
std::string stFilenameUtf8 = "lib\\";
|
|
stFilenameUtf8 += sc_apszPythonLibraryFilenames[i];
|
|
|
|
std::wstring stFilenameW = Utf8ToWide(stFilenameUtf8);
|
|
|
|
// Check existence
|
|
if (GetFileAttributesW(stFilenameW.c_str()) == INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Keep original behavior (forces Windows path normalization)
|
|
MoveFileW(stFilenameW.c_str(), stFilenameW.c_str());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PackInitialize(const char * c_pszFolder)
|
|
{
|
|
if (_access(c_pszFolder, 0) != 0)
|
|
return false;
|
|
|
|
std::vector<std::string> 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",
|
|
"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));
|
|
}
|
|
|
|
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();
|
|
std::string stRegisterDebugFlag;
|
|
|
|
#ifdef _DISTRIBUTE
|
|
stRegisterDebugFlag = "__DEBUG__ = 0";
|
|
#else
|
|
stRegisterDebugFlag = "__DEBUG__ = 1";
|
|
#endif
|
|
|
|
if (!pyLauncher.RunLine(stRegisterDebugFlag.c_str()))
|
|
{
|
|
TraceError("RegisterDebugFlag Error");
|
|
return false;
|
|
}
|
|
|
|
if (!pyLauncher.RunFile("system.py"))
|
|
{
|
|
TraceError("RunMain Error");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool Main(HINSTANCE hInstance, LPSTR lpCmdLine)
|
|
{
|
|
DWORD dwRandSeed = (DWORD)time(NULL) ^ GetCurrentProcessId() ^ GetTickCount();
|
|
srandom(dwRandSeed);
|
|
srand(random());
|
|
SetLogLevel(1);
|
|
|
|
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;
|
|
}
|
|
|
|
auto app = new CPythonApplication;
|
|
app->Initialize (hInstance);
|
|
CPythonLauncher pyLauncher;
|
|
|
|
if (pyLauncher.Create())
|
|
{
|
|
RunMainScript (pyLauncher, lpCmdLine);
|
|
}
|
|
|
|
app->Clear();
|
|
timeEndPeriod (1);
|
|
pyLauncher.Clear();
|
|
|
|
app->Destroy();
|
|
delete app;
|
|
return 0;
|
|
}
|
|
|
|
void __ErrorPythonLibraryIsNotExist()
|
|
{
|
|
LogBoxf("FATAL ERROR!! Python Library file not exist!");
|
|
}
|
|
|
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
LoadConfig("config/locale.cfg");
|
|
|
|
int nArgc = 0;
|
|
auto szArgv = CommandLineToArgv (lpCmdLine, &nArgc);
|
|
|
|
if (!CheckPythonLibraryFilenames())
|
|
{
|
|
__ErrorPythonLibraryIsNotExist();
|
|
goto Clean;
|
|
}
|
|
|
|
Main (hInstance, lpCmdLine);
|
|
::CoUninitialize();
|
|
|
|
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;
|
|
}
|