#include "UserInterface/StdAfx.h" #include "UserInterface/PythonApplication.h" #include "UserInterface/MarkManager.h" #include "GameLib/GameUtil.h" #include "EterLib/Camera.h" #include "EterBase/Timer.h" #include "EterLib/ResourceManager.h" #include "UserInterface/PythonNetworkStream.h" #include "UserInterface/AccountConnector.h" #include "EterLib/NetDevice.h" #include "../PlatformStub.h" #include "../EterLib/UIRenderCommands.h" #include "../ScriptLib/PythonBoot.h" // 2V0-d link surface; 2V0-f adds the application lifecycle (Create/Loop/Process/Exit) that // prototype.RunApp() drives. The rest of the members still wait for the game slices (2V1-2V3). // // PORT: there is no CPythonApplication object yet (its members are the whole game: background, // network stream, player, ...), so these functions only use the singletons PythonBoot owns // (UI::CWindowManager, CTimer, CResourceManager) and never touch a data member. CPythonApplication* CPythonApplication::ms_pInstance = nullptr; void CPythonApplication::ShowWebPage(const char*, const RECT&) { MT_PLATFORM_STUB(); } void CPythonApplication::MoveWebPage(const RECT&) { MT_PLATFORM_STUB(); } void CPythonApplication::HideWebPage() { MT_PLATFORM_STUB(); } bool CPythonApplication::IsWebPageMode() { MT_PLATFORM_STUB(); return false; } void CPythonApplication::GetInfo(UINT, std::string* out) { MT_PLATFORM_STUB(); if (out) out->clear(); } // In 40250, Loop() is: while (1) { if (IsMessage()) { if (!MessageProcess()) break; } else { if (!Process()) break; } } // PORT: Godot owns the message pump and forwards input to the window manager between frames // (PythonBoot::UIMouseMove & co.), so the loop here only waits for the host's next frame. It runs // on PythonBoot's script thread; WM_QUIT is PythonBoot::AppRequestQuit. void CPythonApplication::Loop() { while (PythonBoot::AppLoopWait()) { if (!Process()) break; } } // In 40250 this is PostQuitMessage(0). void CPythonApplication::Exit() { PythonBoot::AppRequestQuit(); } // 40250 also writes a TraceError banner first; the caller (system.py) has already logged the reason. void CPythonApplication::Abort() { TraceError("============================================================================================================"); TraceError("Abort!!!!\n\n"); PythonBoot::AppRequestQuit(); } void CPythonApplication::SetMinFog(float) { MT_PLATFORM_STUB(); } // In 40250 Process() copies CTimer::GetCurrentSecond() into m_fGlobalTime right after Advance() and // this returns it. PORT: no member to hold it; the timer only advances in Process(), so reading it // here gives the same value. float CPythonApplication::GetGlobalTime() { return CTimer::Instance().GetCurrentSecond(); } // Camera (2V3). void CPythonApplication::SetEventCamera(const SCameraSetting&) { MT_PLATFORM_STUB(); } void CPythonApplication::SetDefaultCamera() { MT_PLATFORM_STUB(); } // In 40250 this stores m_v3CenterPosition for the game view (introselect.py sets it on the character list). void CPythonApplication::SetCenterPosition(float, float, float) { MT_PLATFORM_STUB(); } void CPythonApplication::SetFrameSkip(bool) { MT_PLATFORM_STUB(); } // PORT: 40250 creates the Win32 window, the D3D8 device, cursors, sound, keyboard, the net device, // fonts and the IME here. The Godot window and its canvas are the device on this platform and they // already exist when the host starts the script, so the window size is the canvas size // (PythonBoot::SetUISize) rather than the width/height passed from metin2.cfg. What remains of // Create belongs to the subsystems that are not ported yet (sound 2V4, net 2V1, game render 2V3). bool CPythonApplication::Create(PyObject*, const char*, int, int, int) { unsigned width = 0, height = 0; UIRenderGetSize(&width, &height); if (!width || !height) { // appCreate returns NULL on failure; RunApp turns this into the original LogBox. TraceError("CreateDevice: GraphicDevice create failed"); PyErr_SetString(PyExc_RuntimeError, "CREATE_DEVICE"); return false; } // In 40250 m_netDevice is a member created here (PythonApplication.cpp:1242). static CNetworkDevice s_netDevice; if (!s_netDevice.Create()) { TraceError("NetDevice::Create failed"); PyErr_SetString(PyExc_RuntimeError, "CREATE_NETWORK"); return false; } return true; } void CPythonApplication::UpdateGame() { MT_PLATFORM_STUB(); } void CPythonApplication::RenderGame() { MT_PLATFORM_STUB(); } // 40250 PythonApplication.cpp:399. Kept in order: timer, network (2V1), input polling (Godot pushes // input instead), camera (2V3), resource GC, mouse/UI update, then the render block's interface pass. // PORT: the frame-skip bookkeeping and the game render pass are left out; the Godot frame clock // decides when this runs, and RenderGame belongs to 2V3. bool CPythonApplication::Process() { ELTimer_SetFrameMSec(); CTimer& rkTimer=CTimer::Instance(); rkTimer.Advance(); // Network I/O CPythonNetworkStream::Instance().Process(); // PORT: m_kGuildMarkUploader/m_kGuildMarkDownloader.Process() follow here in 40250; the guild mark // transfer is not ported yet (GuildMarkDownloader.cpp/GuildMarkUploader.cpp). CAccountConnector::Instance().Process(); CResourceManager::Instance().Update(); OnUIUpdate(); UIRenderBeginFrame(); OnUIRender(); return true; } // 40250 PythonApplicationEvent.cpp:15-25 void CPythonApplication::OnUIUpdate() { UI::CWindowManager& rkUIMgr=UI::CWindowManager::Instance(); rkUIMgr.Update(); } void CPythonApplication::OnUIRender() { UI::CWindowManager& rkUIMgr=UI::CWindowManager::Instance(); rkUIMgr.Render(); } BOOL CPythonApplication::SetCursorNum(int) { MT_PLATFORM_STUB(); return FALSE; } void CPythonApplication::SetCursorVisible(BOOL, bool) { MT_PLATFORM_STUB(); } BOOL CPythonApplication::GetCursorVisible() { MT_PLATFORM_STUB(); return FALSE; } bool CPythonApplication::GetLiarCursorOn() { MT_PLATFORM_STUB(); return false; } void CPythonApplication::SetCursorMode(int) { MT_PLATFORM_STUB(); } void CPythonApplication::SetMouseHandler(PyObject*) { MT_PLATFORM_STUB(); } void CPythonApplication::SetGlobalCenterPosition(LONG, LONG) { MT_PLATFORM_STUB(); } void CPythonApplication::SetCamera(float, float, float, float) { MT_PLATFORM_STUB(); } void CPythonApplication::GetCamera(float* distance, float* pitch, float* rotation, float* height) { MT_PLATFORM_STUB(); if (distance) *distance = 0; if (pitch) *pitch = 0; if (rotation) *rotation = 0; if (height) *height = 0; } void CPythonApplication::RotateCamera(int) { MT_PLATFORM_STUB(); } void CPythonApplication::PitchCamera(int) { MT_PLATFORM_STUB(); } void CPythonApplication::ZoomCamera(int) { MT_PLATFORM_STUB(); } void CPythonApplication::MovieRotateCamera(int) { MT_PLATFORM_STUB(); } void CPythonApplication::MoviePitchCamera(int) { MT_PLATFORM_STUB(); } void CPythonApplication::MovieZoomCamera(int) { MT_PLATFORM_STUB(); } void CPythonApplication::MovieResetCamera() { MT_PLATFORM_STUB(); } float CPythonApplication::GetRotation() { MT_PLATFORM_STUB(); return 0; } float CPythonApplication::GetPitch() { MT_PLATFORM_STUB(); return 0; } void CPythonApplication::SetFPS(int) { MT_PLATFORM_STUB(); } time_t CPythonApplication::GetServerTime() { MT_PLATFORM_STUB(); return 0; } time_t CPythonApplication::GetServerTimeStamp() { MT_PLATFORM_STUB(); return 0; } void CPythonApplication::SetConnectData(const char*, int) { MT_PLATFORM_STUB(); } void CPythonApplication::GetConnectData(std::string& ip, int& port) { MT_PLATFORM_STUB(); ip.clear(); port = 0; } void CPythonApplication::EnableSpecialCameraMode() { MT_PLATFORM_STUB(); } void CPythonApplication::SetCameraSpeed(int) { MT_PLATFORM_STUB(); } void CPythonApplication::SaveCameraSetting(const char*) { MT_PLATFORM_STUB(); } bool CPythonApplication::LoadCameraSetting(const char*) { MT_PLATFORM_STUB(); return false; } void CPythonApplication::SetForceSightRange(int) { MT_PLATFORM_STUB(); } void CCamera::SetResistance(float) { MT_PLATFORM_STUB(); } void CCamera::SetCameraMaxDistance(float) { MT_PLATFORM_STUB(); } void CMovieMan::PlayLogo(const char*) { MT_PLATFORM_STUB(); } float GetDegreeDifference(float, float) { MT_PLATFORM_STUB(); return 0; } int GetRotatingDirection(float, float) { MT_PLATFORM_STUB(); return 0; } BOOL PERF_CHECKER_RENDER_GAME = FALSE; BOOL SKILL_EFFECT_UPGRADE_ENABLE = FALSE; BOOL USE_WEAPON_SPECULAR = FALSE; D3DXCOLOR g_fSpecularColor; double g_specularSpd = 0; bool LoadLocaleData(const char*) { MT_PLATFORM_STUB(); return false; } void SetGuildSymbolPath(const char*) { MT_PLATFORM_STUB(); } void TextTail_SetLivingTime(long) { MT_PLATFORM_STUB(); } namespace { // The supplied 40250 Client/locale.cfg selects "en" (code page 1252). // Keep these mutable for app.ForceSetLocale, as Locale.cpp does. std::string locale_name = "en"; std::string locale_path = "locale/en"; } const char* LocaleService_GetName() { return "EUROPE"; } bool LocaleService_IsCHEONMA() { MT_PLATFORM_STUB(); return false; } void LocaleService_SetCHEONMA(bool) { MT_PLATFORM_STUB(); } unsigned LocaleService_GetCodePage() { return 1252; } const char* LocaleService_GetLocaleName() { return locale_name.c_str(); } const char* LocaleService_GetLocalePath() { return locale_path.c_str(); } void LocaleService_ForceSetLocale(const char* name, const char* path) { locale_name = name ? name : ""; locale_path = path ? path : ""; } // 40250 UserInterface/Locale.cpp:9-31, 168-172 and 393-423 (the non-Japan branch), verbatim: what the network // slice (批次 2V1) and InsultChecker call. const char* LSS_YMIR = "YMIR"; const char* LSS_JAPAN = "JAPAN"; const char* LSS_ENGLISH = "ENGLISH"; const char* LSS_HONGKONG = "HONGKONG"; const char* LSS_TAIWAN = "TAIWAN"; const char* LSS_NEWCIBN = "NEWCIBN"; const char* LSS_EUROPE = "EUROPE"; const char* LSS_GLOBAL = "GLOBAL"; #ifndef LSS_SECURITY_KEY #define LSS_SECURITY_KEY "testtesttesttest" #endif std::string __SECURITY_KEY_STRING__ = LSS_SECURITY_KEY; const char* LocaleService_GetSecurityKey() { return __SECURITY_KEY_STRING__.c_str(); } bool LocaleService_IsYMIR() { return (stricmp( LocaleService_GetName(), LSS_YMIR ) == 0) || (stricmp( LocaleService_GetLocaleName(), "ymir" ) == 0); } bool LocaleService_IsJAPAN() { return (stricmp( LocaleService_GetName(), LSS_JAPAN ) == 0) || (stricmp( LocaleService_GetLocaleName(), "japan" ) == 0); } bool LocaleService_IsENGLISH() { return (stricmp( LocaleService_GetName(), LSS_ENGLISH ) == 0); } bool LocaleService_IsEUROPE() { return (stricmp( LocaleService_GetName(), LSS_EUROPE ) == 0); } bool LocaleService_IsHONGKONG() { return (stricmp( LocaleService_GetName(), LSS_HONGKONG ) == 0); } bool LocaleService_IsTAIWAN() { return (stricmp( LocaleService_GetName(), LSS_TAIWAN ) == 0); } bool LocaleService_IsNEWCIBN() { return (stricmp( LocaleService_GetName(), LSS_NEWCIBN ) == 0); } BOOL LocaleService_IsLeadByte( const char chByte ) { return (((unsigned char) chByte) & 0x80) != 0; } int LocaleService_StringCompareCI( LPCSTR szStringLeft, LPCSTR szStringRight, size_t sizeLength ) { return strnicmp( szStringLeft, szStringRight, sizeLength ); } // 40250 UserInterface/GameType.cpp:9-73 (DEFAULT_FONT), verbatim. // PORT: the default names are CP949 literals in 40250; ui.py sets the locale font (app.SetDefaultFontName) // before anything asks for it. static std::string gs_strDefaultFontName = "굴림체:12.fnt"; static std::string gs_strDefaultItalicFontName = "굴림체:12i.fnt"; static CResource* gs_pkDefaultFont = NULL; static CResource* gs_pkDefaultItalicFont = NULL; static bool gs_isReloadDefaultFont = false; void DefaultFont_Startup() { gs_pkDefaultFont = NULL; } void DefaultFont_Cleanup() { if (gs_pkDefaultFont) gs_pkDefaultFont->Release(); } void DefaultFont_SetName(const char * c_szFontName) { gs_strDefaultFontName = c_szFontName; gs_strDefaultFontName += ".fnt"; gs_strDefaultItalicFontName = c_szFontName; if(strchr(c_szFontName, ':')) gs_strDefaultItalicFontName += "i"; gs_strDefaultItalicFontName += ".fnt"; gs_isReloadDefaultFont = true; } bool ReloadDefaultFonts() { CResourceManager& rkResMgr = CResourceManager::Instance(); gs_isReloadDefaultFont = false; CResource* pkNewFont = rkResMgr.GetResourcePointer(gs_strDefaultFontName.c_str()); pkNewFont->AddReference(); if (gs_pkDefaultFont) gs_pkDefaultFont->Release(); gs_pkDefaultFont = pkNewFont; CResource* pkNewItalicFont = rkResMgr.GetResourcePointer(gs_strDefaultItalicFontName.c_str()); pkNewItalicFont->AddReference(); if (gs_pkDefaultItalicFont) gs_pkDefaultItalicFont->Release(); gs_pkDefaultItalicFont = pkNewItalicFont; return true; } CResource* DefaultFont_GetResource() { if (!gs_pkDefaultFont || gs_isReloadDefaultFont) ReloadDefaultFonts(); return gs_pkDefaultFont; } CResource* DefaultItalicFont_GetResource() { if (!gs_pkDefaultItalicFont || gs_isReloadDefaultFont) ReloadDefaultFonts(); return gs_pkDefaultItalicFont; }