#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 "UserInterface/PythonItem.h" #include "UserInterface/PythonTextTail.h" #include "UserInterface/PythonSkill.h" #include "UserInterface/PythonNonPlayer.h" #include "GameLib/ItemManager.h" #include "EterLib/NetDevice.h" #include "../PlatformStub.h" #include "../EterLib/UIRenderCommands.h" #include "../EterLib/RenderCommands3D.h" #include "EterLib/GrpDevice.h" #include "EterGrnLib/LODController.h" #include "UserInterface/PythonBackground.h" #include "UserInterface/PythonSystem.h" #include "../ScriptLib/PythonBoot.h" #include "ServerClock.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 alignas(alignof(CPythonApplication)) static char s_app_storage[sizeof(CPythonApplication)] = {}; CPythonApplication* CPythonApplication::ms_pInstance = reinterpret_cast(s_app_storage); extern double g_specularSpd; 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(); } static float MIN_FOG = 2400.0f; void CPythonApplication::SetMinFog(float fMinFog) { MIN_FOG = fMinFog; } // 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(); } // In 40250 Process() also copies CTimer::GetElapsedSecond() into m_fGlobalElapsedTime (PythonApplication.cpp:448). // PORT: read straight from the timer, as GetGlobalTime above. float CPythonApplication::GetGlobalElapsedTime() { return CTimer::Instance().GetElapsedSecond(); } static bool s_isFrameSkipDisable = false; // m_iForceSightRange (the 40250 constructor sets -1: automatic sight range). static int s_iForceSightRange = -1; static float s_nativeRenderFrameTime = 0.0f; void PythonBoot::SetNativeRenderFrameTime(float milliseconds) { s_nativeRenderFrameTime = milliseconds; } void CPythonApplication::SetFrameSkip(bool isEnable) { s_isFrameSkipDisable = !isEnable; } // 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 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, and the graphic device is the recording device (RecordingDevice.h) at that // size. Cursors, sound, keyboard and fonts are not created here yet. 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; } // 40250 PythonApplication.cpp:1196-1199. extern bool GRAPHICS_CAPS_SOFTWARE_TILING; if (!CPythonSystem::Instance().IsAutoTiling()) GRAPHICS_CAPS_SOFTWARE_TILING = CPythonSystem::Instance().IsSoftwareTiling(); // In 40250 m_grpDevice is a member created here (PythonApplication.cpp:909). static CGraphicDevice s_grpDevice; int iRet = s_grpDevice.Create(NULL, width, height, true, 32, 0); switch (iRet) { case CGraphicDevice::CREATE_OK: break; case CGraphicDevice::CREATE_REFRESHRATE: break; case CGraphicDevice::CREATE_GET_DEVICE_CAPS: PyErr_SetString(PyExc_RuntimeError, "GetDevCaps failed"); TraceError("CreateDevice: GetDevCaps failed"); return false; case CGraphicDevice::CREATE_GET_DEVICE_CAPS2: PyErr_SetString(PyExc_RuntimeError, "GetDevCaps2 failed"); TraceError("CreateDevice: GetDevCaps2 failed"); return false; default: // PORT: the recording device returns only the cases above; the rest is 40250's fallback. if (iRet & CGraphicDevice::CREATE_OK) break; TraceError("CreateDevice: Unknown Error!"); PyErr_SetString(PyExc_RuntimeError, "UNKNOWN_ERROR"); return false; } // 40250 PythonApplication.cpp:1206-1220. if (CPythonSystem::Instance().IsAutoTiling()) { if (s_grpDevice.IsFastTNL()) { CPythonBackground::Instance().ReserveSoftwareTilingEnable(false); } else { CPythonBackground::Instance().ReserveSoftwareTilingEnable(true); } } else { CPythonBackground::Instance().ReserveSoftwareTilingEnable(CPythonSystem::Instance().IsSoftwareTiling()); } // 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; } // 40250 PythonApplication.cpp:1250-1251. if (!s_grpDevice.IsFastTNL()) CGrannyLODController::SetMinLODMode(true); // 40250 m_pyItem.Create() (PythonApplication.cpp:1253): registers dropitem.mse with CEffectManager. CPythonItem::Instance().Create(); // 40250 PythonApplication.cpp:1258-1259 (after DefaultFont_Startup). CPythonIME::Instance().Create(GetWindowHandle()); CPythonIME::Instance().SetText("", 0); // 40250 PythonApplication.cpp:1260. CPythonTextTail::Instance().Initialize(); // 40250 PythonApplication.cpp:1262-1263. // Light Manager m_LightManager.Initialize(); if (IsNativeTerrainRenderEnabled()) { const bool use_hardware_cursor = PythonBoot::HostHardwareCursorEnabled() || PythonBoot::TouchInput(); if (CPythonSystem::InstancePtr() && CPythonSystem::Instance().GetConfig()) CPythonSystem::Instance().GetConfig()->is_software_cursor = !use_hardware_cursor; SetCursorMode(use_hardware_cursor ? CURSOR_MODE_HARDWARE : CURSOR_MODE_SOFTWARE); CGrannyMaterial::CreateSphereMap(0, "d:/ymir work/special/spheremap.jpg"); CGrannyMaterial::CreateSphereMap(1, "d:/ymir work/special/spheremap01.jpg"); } return true; } // 40250 PythonApplication.cpp:105 void CPythonApplication::GetMousePosition(POINT* ppt) { CMSApplication::GetMousePosition(ppt); } // 40250 PythonApplication.cpp:168, the !PERF_CHECKER_RENDER_GAME branch (the profiling copy below it // only adds timers). game.GameWindow.OnRender calls it every frame. // PORT: the members are reached through their singletons (see the note at the top of the file). void CPythonApplication::RenderGame() { float fAspect=UI::CWindowManager::Instance().GetAspect(); float fFarClip=CPythonBackground::Instance().GetFarClip(); CPythonGraphic::Instance().SetPerspective(30.0f, fAspect, 100.0, fFarClip); CCullingManager::Instance().Process(); CPythonCharacterManager::Instance().Deform(); CEffectManager::Instance().Update(); CPythonBackground::Instance().RenderCharacterShadowToTexture(); CPythonGraphic::Instance().SetGameRenderState(); CPythonGraphic::Instance().PushState(); { long lx, ly; UI::CWindowManager::Instance().GetMousePosition(lx, ly); // PORT: window coordinates -> the screen coordinates of the full-width 3D view. lx += UI::CWindowManager::Instance().GetScreenOffsetX(); CPythonGraphic::Instance().SetCursorPosition(lx, ly); } CPythonBackground::Instance().RenderSky(); CPythonBackground::Instance().RenderBeforeLensFlare(); CPythonBackground::Instance().RenderCloud(); CPythonBackground::Instance().BeginEnvironment(); CPythonBackground::Instance().Render(); CPythonBackground::Instance().SetCharacterDirLight(); CPythonCharacterManager::Instance().Render(); CPythonBackground::Instance().SetBackgroundDirLight(); CPythonBackground::Instance().RenderWater(); CPythonBackground::Instance().RenderSnow(); CPythonBackground::Instance().RenderEffect(); CPythonBackground::Instance().EndEnvironment(); CEffectManager::Instance().Render(); CPythonItem::Instance().Render(); CFlyingManager::Instance().Render(); CPythonBackground::Instance().BeginEnvironment(); CPythonBackground::Instance().RenderPCBlocker(); CPythonBackground::Instance().EndEnvironment(); CPythonBackground::Instance().RenderAfterLensFlare(); } // 40250 PythonApplication.cpp:321 without the PERF_CHECKER_RENDER_GAME timers. game.GameWindow.OnUpdate // calls it every frame. PORT: members through their singletons, as in RenderGame. void CPythonApplication::UpdateGame() { POINT ptMouse; GetMousePosition(&ptMouse); CGraphicTextInstance::Hyperlink_UpdateMousePos(ptMouse.x, ptMouse.y); //!@# Alt+Tab 중 SetTransfor 에서 튕김 현상 해결을 위해 - [levites] //if (m_isActivateWnd) { CScreen s; float fAspect = UI::CWindowManager::Instance().GetAspect(); float fFarClip = CPythonBackground::Instance().GetFarClip(); s.SetPerspective(30.0f,fAspect, 100.0f, fFarClip); s.BuildViewFrustum(); } TPixelPosition kPPosMainActor; CPythonPlayer::Instance().NEW_GetMainActorPosition(&kPPosMainActor); CPythonBackground::Instance().Update(kPPosMainActor.x, kPPosMainActor.y, kPPosMainActor.z); CGameEventManager::Instance().SetCenterPosition(kPPosMainActor.x, kPPosMainActor.y, kPPosMainActor.z); CGameEventManager::Instance().Update(); CPythonCharacterManager::Instance().Update(); CEffectManager::Instance().UpdateSound(); CFlyingManager::Instance().Update(); CPythonItem::Instance().Update(ptMouse); CPythonPlayer::Instance().Update(); // NOTE : Update 에서 위치 값이 바뀌므로 다시 얻어 옵니다 - [levites] // 이 부분 때문에 메인 케릭터의 Sound가 이전 위치에서 플레이 되는 현상이 있었음. CPythonPlayer::Instance().NEW_GetMainActorPosition(&kPPosMainActor); SetCenterPosition(kPPosMainActor.x, kPPosMainActor.y, kPPosMainActor.z); } // 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(); //!@# Alt+Tab 중 SetTransfor 에서 튕김 현상 해결을 위해 - [levites] //if (m_isActivateWnd) __UpdateCamera(); CResourceManager::Instance().Update(); OnCameraUpdate(); if (IsNativeTerrainRenderEnabled()) OnMouseUpdate(); OnUIUpdate(); if (IsNativeTerrainRenderEnabled()) CGrannyMaterial::TranslateSpecularMatrix(g_specularSpd, g_specularSpd, 0.0f); // PORT: the render block without the lost-device restore, ClearDepthBuffer and Show (Godot clears // and presents the frame), and without the !IsActive() SkipRenderBuffering(3000): the host has no // Win32 activation (CMSWindow::IsActive is a stub). The frame's UI and 3D command lists restart here. // 40250 PythonApplication.cpp:681. DWORD dwRenderStartTime = ELTimer_GetMSec(); CCullingManager::Instance().Update(); UIRenderBeginFrame(); Render3DBeginFrame(); CPythonGraphic& rkGraphic = CPythonGraphic::Instance(); if (rkGraphic.Begin()) { rkGraphic.SetInterfaceRenderState(); OnUIRender(); if (IsNativeTerrainRenderEnabled()) { rkGraphic.SetInterfaceRenderState(); unsigned cw = 0, ch = 0; UIRenderGetSize(&cw, &ch); UIRenderSetClip(0.0f, 0.0f, float(cw), float(ch)); OnMouseRender(); } rkGraphic.End(); // 40250 PythonApplication.cpp:741-842 (render time, face count, automatic sight range), minus the // per-second FPS/face counters and the windowed dwBufRenderTime rounding, whose result 40250 never // uses (its Sleep is commented out). DWORD dwRenderEndTime = ELTimer_GetMSec(); static DWORD s_dwRenderCheckTime = dwRenderEndTime; static DWORD s_dwRenderRangeTime = 0; static DWORD s_dwRenderRangeFrame = 0; // The native host completes Vulkan work after this command-recording pass. // Use its last completed frame, including presentation, for automatic sight range. m_dwCurRenderTime = s_nativeRenderFrameTime > 0.0f ? static_cast(s_nativeRenderFrameTime + 0.5f) : dwRenderEndTime - dwRenderStartTime; s_dwRenderRangeTime += m_dwCurRenderTime; ++s_dwRenderRangeFrame; if (dwRenderEndTime-s_dwRenderCheckTime>1000) { m_fAveRenderTime=float(double(s_dwRenderRangeTime)/double(s_dwRenderRangeFrame)); s_dwRenderCheckTime=ELTimer_GetMSec(); s_dwRenderRangeTime=0; s_dwRenderRangeFrame=0; } DWORD dwCurFaceCount=rkGraphic.GetFaceCount(); rkGraphic.ResetFaceCount(); if (dwCurFaceCount > 5000) { // 프레임 완충 처리 if (dwRenderEndTime > m_dwBufSleepSkipTime) { static float s_fBufRenderTime = 0.0f; float fCurRenderTime = m_dwCurRenderTime; if (fCurRenderTime > s_fBufRenderTime) { float fRatio = fMAX(0.5f, (fCurRenderTime - s_fBufRenderTime) / 30.0f); s_fBufRenderTime = (s_fBufRenderTime * (100.0f - fRatio) + (fCurRenderTime + 5) * fRatio) / 100.0f; } else { float fRatio = 0.5f; s_fBufRenderTime = (s_fBufRenderTime * (100.0f - fRatio) + fCurRenderTime * fRatio) / 100.0f; } // 한계치를 정한다 if (s_fBufRenderTime > 100.0f) s_fBufRenderTime = 100.0f; m_fAveRenderTime=s_fBufRenderTime; } m_dwFaceAccCount += dwCurFaceCount; m_dwFaceAccTime += m_dwCurRenderTime; // PORT: recording a frame can take under 1 ms, so the integer division is guarded (40250's // D3D frame never took 0 ms). if (m_dwFaceAccTime) m_fFaceSpd=(m_dwFaceAccCount/m_dwFaceAccTime); // 거리 자동 조절 if (-1 == s_iForceSightRange) { static float s_fAveRenderTime = 16.0f; float fRatio=0.3f; s_fAveRenderTime=(s_fAveRenderTime*(100.0f-fRatio)+max(16.0f, m_dwCurRenderTime)*fRatio)/100.0f; float fFar=25600.0f; float fNear=MIN_FOG; double dbAvePow=double(1000.0f/s_fAveRenderTime); double dbMaxPow=60.0; float fDistance=max(fNear+(fFar-fNear)*(dbAvePow)/dbMaxPow, fNear); CPythonBackground::Instance().SetViewDistanceSet(0, fDistance); } // 거리 강제 설정시 else { CPythonBackground::Instance().SetViewDistanceSet(0, float(s_iForceSightRange)); } } else { // 10000 폴리곤 보다 적을때는 가장 멀리 보이게 한다 CPythonBackground::Instance().SetViewDistanceSet(0, 25600.0f); } } return true; } // 40250 PythonApplicationCursor.cpp. PORT: the members live here until the application object exists // (initial values from the constructor and CreateCursors); the host draws no hardware cursor, so every // shape in [0, CURSOR_COUNT) counts as loaded in place of m_CursorHandleMap. PyObject* s_poMouseHandler = NULL; // m_poMouseHandler namespace { int s_iCursorNum = CPythonApplication::CURSOR_SHAPE_NORMAL; // m_iCursorNum int s_iContinuousCursorNum = CPythonApplication::CURSOR_SHAPE_NORMAL; // m_iContinuousCursorNum BOOL s_bCursorVisible = TRUE; // m_bCursorVisible bool s_bLiarCursorOn = false; // m_bLiarCursorOn int s_iCursorMode = CPythonApplication::CURSOR_MODE_HARDWARE; // m_iCursorMode } void CPythonApplication::SetCursorVisible(BOOL bFlag, bool bLiarCursorOn) { s_bCursorVisible = bFlag; // PORT: a touch screen has no cursor, not even the stand-in 40250 draws while the real one is hidden. s_bLiarCursorOn = bLiarCursorOn && !PythonBoot::TouchInput(); // PORT: 40250 also counts ShowCursor up or down in hardware mode; the host has no OS cursor to hide. } BOOL CPythonApplication::GetCursorVisible() { return s_bCursorVisible; } bool CPythonApplication::GetLiarCursorOn() { return s_bLiarCursorOn; } int CPythonApplication::GetCursorMode() { return s_iCursorMode; } int CPythonApplication::GetCursorNum() { return s_iCursorNum; } BOOL CPythonApplication::__IsContinuousChangeTypeCursor(int iCursorNum) { switch (iCursorNum) { case CURSOR_SHAPE_NORMAL: case CURSOR_SHAPE_ATTACK: case CURSOR_SHAPE_TARGET: case CURSOR_SHAPE_MAGIC: case CURSOR_SHAPE_BUY: case CURSOR_SHAPE_SELL: return TRUE; break; } return FALSE; } BOOL CPythonApplication::SetCursorNum(int iCursorNum) { if (CURSOR_SHAPE_NORMAL == iCursorNum) { if (!__IsContinuousChangeTypeCursor(s_iCursorNum)) { iCursorNum = s_iContinuousCursorNum; } } else { if (__IsContinuousChangeTypeCursor(s_iCursorNum)) { s_iContinuousCursorNum = s_iCursorNum; } } if (CURSOR_MODE_HARDWARE == s_iCursorMode) { // PORT: m_CursorHandleMap.find(iCursorNum) and SetCursor(hCursor). if (iCursorNum < 0 || iCursorNum >= CURSOR_COUNT) return FALSE; } s_iCursorNum = iCursorNum; PyCallClassMemberFunc(s_poMouseHandler, "ChangeCursor", Py_BuildValue("(i)", s_iCursorNum)); return TRUE; } void CPythonApplication::SetCursorMode(int iMode) { switch (iMode) { case CURSOR_MODE_HARDWARE: s_iCursorMode = CURSOR_MODE_HARDWARE; break; case CURSOR_MODE_SOFTWARE: s_iCursorMode = CURSOR_MODE_SOFTWARE; break; } } // 40250 PythonApplication.cpp:871. void CPythonApplication::SetMouseHandler(PyObject* poMouseHandler) { s_poMouseHandler = poMouseHandler; } void CPythonApplication::SetGlobalCenterPosition(LONG x, LONG y) { // 40250 PythonApplication.cpp:1284: the background owns the global-to-local map offset. CPythonBackground& background = CPythonBackground::Instance(); background.GlobalPositionToLocalPosition(x, y); SetCenterPosition(x, y, background.GetHeight(x, y)); } void CPythonApplication::SetFPS(int) {} namespace { DWORD s_server_start_msec = 0; time_t s_server_time = 0; time_t s_local_start_time = 0; } void SetPlatformServerTime(time_t server_time) { s_server_start_msec = ELTimer_GetMSec(); s_server_time = server_time; s_local_start_time = time(nullptr); } time_t GetPlatformServerTime() { return static_cast(ELTimer_GetMSec() - s_server_start_msec) + s_server_time; } time_t GetPlatformServerTimeStamp() { return (time(nullptr) - s_local_start_time) + s_server_time; } void CPythonApplication::SetServerTime(time_t server_time) { SetPlatformServerTime(server_time); } time_t CPythonApplication::GetServerTime() { return GetPlatformServerTime(); } time_t CPythonApplication::GetServerTimeStamp() { return GetPlatformServerTimeStamp(); } void CPythonApplication::SetConnectData(const char*, int) { MT_PLATFORM_STUB(); } void CPythonApplication::GetConnectData(std::string& ip, int& port) { MT_PLATFORM_STUB(); ip.clear(); port = 0; } // 40250 PythonApplication.cpp:1377. void CPythonApplication::SetForceSightRange(int iRange) { s_iForceSightRange = iRange; } int CPythonApplication::CheckDeviceState() { return DEVICE_STATE_OK; } bool CPythonApplication::CreateDevice(int width, int height, int Windowed, int bit, int frequency) { static CGraphicDevice s_grpDevice; return s_grpDevice.Create(NULL, width, height, Windowed ? true : false, bit, frequency) == CGraphicDevice::CREATE_OK; } void CPythonApplication::NotifyHack(const char* c_szFormat, ...) { char szBuf[1024]; va_list args; va_start(args, c_szFormat); vsnprintf(szBuf, sizeof(szBuf), c_szFormat, args); va_end(args); CPythonNetworkStream::Instance().NotifyHack(szBuf); } // 40250 PythonApplication.cpp:394 void CPythonApplication::SkipRenderBuffering(DWORD dwSleepMSec) { m_dwBufSleepSkipTime=ELTimer_GetMSec()+dwSleepMSec; } void CPythonApplication::UpdateClientRect() { unsigned w = 0, h = 0; UIRenderGetSize(&w, &h); UI::CWindowManager::Instance().SetResolution(w, h); } int CPythonApplication::GetWidth() { unsigned w = 0, h = 0; UIRenderGetSize(&w, &h); return (int)w; } int CPythonApplication::GetHeight() { unsigned w = 0, h = 0; UIRenderGetSize(&w, &h); return (int)h; } void CPythonApplication::Clear() { CPythonSystem::Instance().Clear(); } void CPythonApplication::Destroy() { } void CMovieMan::PlayLogo(const char*) { MT_PLATFORM_STUB(); } BOOL PERF_CHECKER_RENDER_GAME = FALSE; double g_specularSpd = 0; // 40250 UserInterface/PythonApplication.cpp, verbatim. // SUPPORT_NEW_KOREA_SERVER bool LoadLocaleData(const char* localePath) { NANOBEGIN CPythonNonPlayer& rkNPCMgr = CPythonNonPlayer::Instance(); CItemManager& rkItemMgr = CItemManager::Instance(); CPythonSkill& rkSkillMgr = CPythonSkill::Instance(); CPythonNetworkStream& rkNetStream = CPythonNetworkStream::Instance(); char szItemList[256]; char szItemProto[256]; char szItemDesc[256]; char szMobProto[256]; char szSkillDescFileName[256]; char szSkillTableFileName[256]; char szInsultList[256]; snprintf(szItemList, sizeof(szItemList) , "%s/item_list.txt", localePath); snprintf(szItemProto, sizeof(szItemProto), "%s/item_proto", localePath); snprintf(szItemDesc, sizeof(szItemDesc), "%s/itemdesc.txt", localePath); snprintf(szMobProto, sizeof(szMobProto), "%s/mob_proto", localePath); snprintf(szSkillDescFileName, sizeof(szSkillDescFileName), "%s/SkillDesc.txt", localePath); snprintf(szSkillTableFileName, sizeof(szSkillTableFileName), "%s/SkillTable.txt", localePath); snprintf(szInsultList, sizeof(szInsultList), "%s/insult.txt", localePath); rkNPCMgr.Destroy(); rkItemMgr.Destroy(); rkSkillMgr.Destroy(); if (!rkItemMgr.LoadItemList(szItemList)) { TraceError("LoadLocaleData - LoadItemList(%s) Error", szItemList); } if (!rkItemMgr.LoadItemTable(szItemProto)) { TraceError("LoadLocaleData - LoadItemProto(%s) Error", szItemProto); return false; } if (!rkItemMgr.LoadItemDesc(szItemDesc)) { Tracenf("LoadLocaleData - LoadItemDesc(%s) Error", szItemDesc); } if (!rkNPCMgr.LoadNonPlayerData(szMobProto)) { TraceError("LoadLocaleData - LoadMobProto(%s) Error", szMobProto); return false; } if (!rkSkillMgr.RegisterSkillDesc(szSkillDescFileName)) { TraceError("LoadLocaleData - RegisterSkillDesc(%s) Error", szMobProto); return false; } if (!rkSkillMgr.RegisterSkillTable(szSkillTableFileName)) { TraceError("LoadLocaleData - RegisterSkillTable(%s) Error", szMobProto); return false; } if (!rkNetStream.LoadInsultList(szInsultList)) { Tracenf("CPythonApplication - CPythonNetworkStream::LoadInsultList(%s)", szInsultList); } if (LocaleService_IsYMIR()) { char szEmpireTextConvFile[256]; for (DWORD dwEmpireID=1; dwEmpireID<=3; ++dwEmpireID) { sprintf(szEmpireTextConvFile, "%s/lang%d.cvt", localePath, dwEmpireID); if (!rkNetStream.LoadConvertTable(dwEmpireID, szEmpireTextConvFile)) { TraceError("LoadLocaleData - CPythonNetworkStream::LoadConvertTable(%d, %s) FAILURE", dwEmpireID, szEmpireTextConvFile); } } } NANOEND return true; }