Files
m2dev-client-src/src/UserInterface/UserInterface.cpp
rtw1x1 a955c50744 Full Unicode patch with RTL Support & BiDi logic.
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
2025-12-26 12:32:43 +00:00

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;
}