Files
m2dev-client-src/src/UserInterface/PythonApplication.cpp
server bfe52a81f9
Some checks failed
build / Windows Build (push) Has been cancelled
Add high-FPS render pacing and telemetry
2026-04-16 10:37:08 +02:00

1463 lines
38 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "StdAfx.h"
#include "eterBase/Error.h"
#include "eterlib/Camera.h"
#include "eterlib/AttributeInstance.h"
#include "gamelib/AreaTerrain.h"
#include "EterGrnLib/Material.h"
#include "resource.h"
#include "GameType.h"
#include "PythonApplication.h"
#include "PythonCharacterManager.h"
#include "ProcessScanner.h"
#include <utf8.h>
#include <cstdarg>
#include <cstdlib>
extern void GrannyCreateSharedDeformBuffer();
extern void GrannyDestroySharedDeformBuffer();
float MIN_FOG = 2400.0f;
double g_specularSpd=0.007f;
CPythonApplication * CPythonApplication::ms_pInstance;
namespace
{
// Match the legacy custom timer cadence of alternating 17 ms and 16 ms.
constexpr double kFixedUpdateMS = 16.5;
constexpr double kMaxCatchUpDelayMS = 250.0;
float ClampInterpolationFactor(float fInterpolation)
{
return std::max(0.0f, std::min(1.0f, fInterpolation));
}
D3DXVECTOR3 LerpVector3(const D3DXVECTOR3& c_rv3Begin, const D3DXVECTOR3& c_rv3End, float fInterpolation)
{
return D3DXVECTOR3(
c_rv3Begin.x + (c_rv3End.x - c_rv3Begin.x) * fInterpolation,
c_rv3Begin.y + (c_rv3End.y - c_rv3Begin.y) * fInterpolation,
c_rv3Begin.z + (c_rv3End.z - c_rv3Begin.z) * fInterpolation);
}
bool IsRenderTelemetryEnabledFromEnvironment()
{
const char* c_szValue = std::getenv("M2_RENDER_TELEMETRY");
if (!c_szValue || !*c_szValue)
return false;
if (0 == _stricmp(c_szValue, "1") || 0 == _stricmp(c_szValue, "true") || 0 == _stricmp(c_szValue, "yes") || 0 == _stricmp(c_szValue, "on"))
return true;
return false;
}
bool TryReadEnvironmentInt(const char* c_szName, int* piValue)
{
if (!piValue)
return false;
const char* c_szValue = std::getenv(c_szName);
if (!c_szValue || !*c_szValue)
return false;
char* pEnd = nullptr;
const long lValue = std::strtol(c_szValue, &pEnd, 10);
if (pEnd == c_szValue || (pEnd && *pEnd))
return false;
*piValue = static_cast<int>(lValue);
return true;
}
void ResetRenderTelemetryTrace()
{
FILE* fp = nullptr;
if (fopen_s(&fp, "log/render_telemetry.txt", "w") != 0 || !fp)
return;
fprintf(fp, "render telemetry\n");
fclose(fp);
}
void AppendRenderTelemetryTrace(const char* c_szFormat, ...)
{
FILE* fp = nullptr;
if (fopen_s(&fp, "log/render_telemetry.txt", "a") != 0 || !fp)
return;
va_list args;
va_start(args, c_szFormat);
vfprintf(fp, c_szFormat, args);
va_end(args);
fputc('\n', fp);
fclose(fp);
}
void FormatRenderTargetFPSLabel(unsigned int iFPS, char* c_szBuffer, size_t uBufferSize)
{
if (!c_szBuffer || 0 == uBufferSize)
return;
if (iFPS > 0)
_snprintf_s(c_szBuffer, uBufferSize, _TRUNCATE, "%u", iFPS);
else
_snprintf_s(c_szBuffer, uBufferSize, _TRUNCATE, "MAX");
}
}
float c_fDefaultCameraRotateSpeed = 1.5f;
float c_fDefaultCameraPitchSpeed = 1.5f;
float c_fDefaultCameraZoomSpeed = 0.05f;
CPythonApplication::CPythonApplication() :
m_bCursorVisible(TRUE),
m_bLiarCursorOn(false),
m_iCursorMode(CURSOR_MODE_HARDWARE),
m_isWindowed(false),
m_isFrameSkipDisable(false),
m_poMouseHandler(NULL),
m_dwUpdateFPS(0),
m_dwRenderFPS(0),
m_fAveRenderTime(0.0f),
m_bRenderTelemetryEnabled(false),
m_bRenderTelemetryHudVisible(false),
m_dwRenderTelemetryIntervalMS(1000),
m_dwRenderTelemetryWindowStartMS(0),
m_dwRenderTelemetryLoopCount(0),
m_dwRenderTelemetryUpdateCount(0),
m_dwRenderTelemetryRenderCount(0),
m_dwRenderTelemetryBlockedRenderCount(0),
m_dwRenderTelemetryLastPresentTime(0),
m_dwRenderTelemetryPresentGapSamples(0),
m_fRenderTelemetryUpdateTimeSumMS(0.0),
m_fRenderTelemetryRenderTimeSumMS(0.0),
m_fRenderTelemetrySleepTimeSumMS(0.0),
m_fRenderTelemetryInterpolationSum(0.0),
m_fRenderTelemetryPresentGapSumMS(0.0),
m_dwCurRenderTime(0),
m_dwCurUpdateTime(0),
m_dwLoad(0),
m_dwFaceCount(0),
m_fGlobalTime(0.0f),
m_fGlobalElapsedTime(0.0f),
m_fRenderInterpolationFactor(0.0f),
m_dwLButtonDownTime(0),
m_dwLastIdleTime(0),
m_IsMovingMainWindow(false)
{
#ifndef _DEBUG
SetEterExceptionHandler();
#endif
CTimer::Instance().UseCustomTime();
m_dwWidth = 800;
m_dwHeight = 600;
ms_pInstance = this;
m_isWindowFullScreenEnable = FALSE;
m_v3CenterPosition = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
m_v3LastCenterPosition = m_v3CenterPosition;
m_dwStartLocalTime = ELTimer_GetMSec();
m_tServerTime = 0;
m_tLocalStartTime = 0;
m_iPort = 0;
m_iFPS = std::max(0, m_pySystem.GetRenderFPS());
m_bRenderTelemetryHudVisible = m_pySystem.IsShowPerformanceHUD();
InitializeRenderRuntimeOverrides();
m_isActivateWnd = false;
m_isMinimizedWnd = true;
m_fRotationSpeed = 0.0f;
m_fPitchSpeed = 0.0f;
m_fZoomSpeed = 0.0f;
m_fFaceSpd=0.0f;
m_dwFaceAccCount=0;
m_dwFaceAccTime=0;
m_dwFaceSpdSum=0;
m_dwFaceSpdCount=0;
m_FlyingManager.SetMapManagerPtr(&m_pyBackground);
m_iCursorNum = CURSOR_SHAPE_NORMAL;
m_iContinuousCursorNum = CURSOR_SHAPE_NORMAL;
m_isSpecialCameraMode = FALSE;
m_fCameraRotateSpeed = c_fDefaultCameraRotateSpeed;
m_fCameraPitchSpeed = c_fDefaultCameraPitchSpeed;
m_fCameraZoomSpeed = c_fDefaultCameraZoomSpeed;
m_iCameraMode = CAMERA_MODE_NORMAL;
m_fBlendCameraStartTime = 0.0f;
m_fBlendCameraBlendTime = 0.0f;
m_iForceSightRange = -1;
CCameraManager::Instance().AddCamera(EVENT_CAMERA_NUMBER);
m_InitialMouseMovingPoint = {};
}
CPythonApplication::~CPythonApplication()
{
}
void CPythonApplication::GetMousePosition(POINT* ppt)
{
CMSApplication::GetMousePosition(ppt);
}
void CPythonApplication::SetMinFog(float fMinFog)
{
MIN_FOG = fMinFog;
}
void CPythonApplication::SetFrameSkip(bool isEnable)
{
if (isEnable)
m_isFrameSkipDisable=false;
else
m_isFrameSkipDisable=true;
}
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);
m_pyNetworkStream.NotifyHack(szBuf);
}
void CPythonApplication::GetInfo(UINT eInfo, std::string* pstInfo)
{
switch (eInfo)
{
case INFO_ACTOR:
m_kChrMgr.GetInfo(pstInfo);
break;
case INFO_EFFECT:
m_kEftMgr.GetInfo(pstInfo);
break;
case INFO_ITEM:
m_pyItem.GetInfo(pstInfo);
break;
case INFO_TEXTTAIL:
m_pyTextTail.GetInfo(pstInfo);
break;
}
}
void CPythonApplication::Abort()
{
TraceError("============================================================================================================");
TraceError("Abort!!!!\n\n");
PostQuitMessage(0);
}
void CPythonApplication::Exit()
{
PostQuitMessage(0);
}
void CPythonApplication::RenderGame()
{
float fAspect = m_kWndMgr.GetAspect();
float fFarClip = m_pyBackground.GetFarClip();
m_pyGraphic.SetPerspective(30.0f, fAspect, 100.0, fFarClip);
ApplyRenderInterpolation();
CCullingManager::Instance().Process();
m_kChrMgr.Deform();
m_pyBackground.RenderCharacterShadowToTexture();
m_pyGraphic.SetGameRenderState();
m_pyGraphic.PushState();
{
long lx, ly;
m_kWndMgr.GetMousePosition(lx, ly);
m_pyGraphic.SetCursorPosition(lx, ly);
}
m_pyBackground.RenderSky();
m_pyBackground.RenderBeforeLensFlare();
m_pyBackground.RenderCloud();
m_pyBackground.BeginEnvironment();
m_pyBackground.Render();
m_pyBackground.SetCharacterDirLight();
m_kChrMgr.Render();
m_pyBackground.SetBackgroundDirLight();
m_pyBackground.RenderWater();
m_pyBackground.RenderSnow();
m_pyBackground.RenderEffect();
m_pyBackground.EndEnvironment();
m_kEftMgr.Render();
m_pyItem.Render();
m_FlyingManager.Render();
m_pyBackground.BeginEnvironment();
m_pyBackground.RenderPCBlocker();
m_pyBackground.EndEnvironment();
m_pyBackground.RenderAfterLensFlare();
}
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;
m_pyPlayer.NEW_GetMainActorPosition(&kPPosMainActor);
m_pyBackground.Update(kPPosMainActor.x, kPPosMainActor.y, kPPosMainActor.z);
m_GameEventManager.SetCenterPosition(kPPosMainActor.x, kPPosMainActor.y, kPPosMainActor.z);
m_GameEventManager.Update();
m_kChrMgr.Update();
m_kEftMgr.Update();
m_kEftMgr.UpdateSound();
m_FlyingManager.Update();
m_pyItem.Update(ptMouse);
m_pyPlayer.Update();
// NOTE : Update µ¿¾È À§Ä¡ °ªÀÌ ¹Ù²î¹Ç·Î ´Ù½Ã ¾ò¾î ¿É´Ï´Ù - [levites]
// ÀÌ ºÎºÐ ¶§¹®¿¡ ¸ÞÀÎ Äɸ¯ÅÍÀÇ Sound°¡ ÀÌÀü À§Ä¡¿¡¼­ Ç÷¹ÀÌ µÇ´Â Çö»óÀÌ ÀÖ¾úÀ½.
m_pyPlayer.NEW_GetMainActorPosition(&kPPosMainActor);
SetCenterPosition(kPPosMainActor.x, kPPosMainActor.y, kPPosMainActor.z);
}
void CPythonApplication::InitializeRenderRuntimeOverrides()
{
m_bRenderTelemetryEnabled = IsRenderTelemetryEnabledFromEnvironment();
int iIntervalMS = 0;
if (TryReadEnvironmentInt("M2_RENDER_TELEMETRY_INTERVAL_MS", &iIntervalMS) && iIntervalMS > 0)
m_dwRenderTelemetryIntervalMS = static_cast<DWORD>(std::min(iIntervalMS, 60000));
if (m_bRenderTelemetryEnabled)
{
ResetRenderTelemetryTrace();
AppendRenderTelemetryTrace("enabled interval_ms=%lu", static_cast<unsigned long>(m_dwRenderTelemetryIntervalMS));
}
int iRenderFPS = 0;
if (TryReadEnvironmentInt("M2_RENDER_FPS", &iRenderFPS))
{
m_iFPS = std::max(0, iRenderFPS);
if (m_bRenderTelemetryEnabled)
AppendRenderTelemetryTrace("env_override target_fps=%u", m_iFPS);
}
char szTargetFPS[16];
FormatRenderTargetFPSLabel(m_iFPS, szTargetFPS, sizeof(szTargetFPS));
m_stRenderTelemetrySummary = "Render telemetry\nTarget FPS: ";
m_stRenderTelemetrySummary += szTargetFPS;
m_stRenderTelemetrySummary += "\nCollecting frame pacing...";
if (IsRenderTelemetrySamplingEnabled())
ResetRenderTelemetryWindow(ELTimer_GetMSec());
}
void CPythonApplication::ResetRenderTelemetryWindow(DWORD dwNow)
{
m_dwRenderTelemetryWindowStartMS = dwNow;
m_dwRenderTelemetryLoopCount = 0;
m_dwRenderTelemetryUpdateCount = 0;
m_dwRenderTelemetryRenderCount = 0;
m_dwRenderTelemetryBlockedRenderCount = 0;
m_dwRenderTelemetryPresentGapSamples = 0;
m_fRenderTelemetryUpdateTimeSumMS = 0.0;
m_fRenderTelemetryRenderTimeSumMS = 0.0;
m_fRenderTelemetrySleepTimeSumMS = 0.0;
m_fRenderTelemetryInterpolationSum = 0.0;
m_fRenderTelemetryPresentGapSumMS = 0.0;
}
void CPythonApplication::FlushRenderTelemetryWindow(DWORD dwNow)
{
if (!IsRenderTelemetrySamplingEnabled() || !m_dwRenderTelemetryWindowStartMS)
return;
const DWORD dwWindowMS = std::max<DWORD>(1, dwNow - m_dwRenderTelemetryWindowStartMS);
const double fWindowMS = static_cast<double>(dwWindowMS);
const double fUpdateFPS = static_cast<double>(m_dwRenderTelemetryUpdateCount) * 1000.0 / fWindowMS;
const double fRenderFPS = static_cast<double>(m_dwRenderTelemetryRenderCount) * 1000.0 / fWindowMS;
const double fAvgUpdateMS = m_dwRenderTelemetryUpdateCount ? (m_fRenderTelemetryUpdateTimeSumMS / static_cast<double>(m_dwRenderTelemetryUpdateCount)) : 0.0;
const double fAvgRenderMS = m_dwRenderTelemetryRenderCount ? (m_fRenderTelemetryRenderTimeSumMS / static_cast<double>(m_dwRenderTelemetryRenderCount)) : 0.0;
const double fAvgSleepMS = m_dwRenderTelemetryLoopCount ? (m_fRenderTelemetrySleepTimeSumMS / static_cast<double>(m_dwRenderTelemetryLoopCount)) : 0.0;
const double fAvgInterpolation = m_dwRenderTelemetryRenderCount ? (m_fRenderTelemetryInterpolationSum / static_cast<double>(m_dwRenderTelemetryRenderCount)) : 0.0;
const double fAvgPresentGapMS = m_dwRenderTelemetryPresentGapSamples ? (m_fRenderTelemetryPresentGapSumMS / static_cast<double>(m_dwRenderTelemetryPresentGapSamples)) : 0.0;
const DWORD dwElapsedMS = dwNow - m_dwStartLocalTime;
char szTargetFPS[16];
char szSummary[256];
FormatRenderTargetFPSLabel(m_iFPS, szTargetFPS, sizeof(szTargetFPS));
_snprintf_s(
szSummary,
sizeof(szSummary),
_TRUNCATE,
"Render %.1f Update %.1f Target %s\nPresent %.1fms Sleep %.1fms CPU %.1f/%.1fms",
fRenderFPS,
fUpdateFPS,
szTargetFPS,
fAvgPresentGapMS,
fAvgSleepMS,
fAvgUpdateMS,
fAvgRenderMS);
m_stRenderTelemetrySummary = szSummary;
if (m_bRenderTelemetryEnabled)
{
AppendRenderTelemetryTrace(
"elapsed_ms=%lu window_ms=%lu target_fps=%u update_fps=%.2f render_fps=%.2f avg_update_ms=%.2f avg_render_ms=%.2f avg_sleep_ms=%.2f avg_present_gap_ms=%.2f avg_interp=%.3f loops=%lu updates=%lu renders=%lu blocked=%lu cur_update_ms=%lu cur_render_ms=%lu",
static_cast<unsigned long>(dwElapsedMS),
static_cast<unsigned long>(dwWindowMS),
m_iFPS,
fUpdateFPS,
fRenderFPS,
fAvgUpdateMS,
fAvgRenderMS,
fAvgSleepMS,
fAvgPresentGapMS,
fAvgInterpolation,
static_cast<unsigned long>(m_dwRenderTelemetryLoopCount),
static_cast<unsigned long>(m_dwRenderTelemetryUpdateCount),
static_cast<unsigned long>(m_dwRenderTelemetryRenderCount),
static_cast<unsigned long>(m_dwRenderTelemetryBlockedRenderCount),
static_cast<unsigned long>(m_dwCurUpdateTime),
static_cast<unsigned long>(m_dwCurRenderTime));
}
ResetRenderTelemetryWindow(dwNow);
}
bool CPythonApplication::IsRenderTelemetrySamplingEnabled() const
{
return m_bRenderTelemetryEnabled || m_bRenderTelemetryHudVisible;
}
void CPythonApplication::RenderPerformanceHUD()
{
if (!m_bRenderTelemetryHudVisible)
return;
CGraphicText* pkDefaultFont = static_cast<CGraphicText*>(DefaultFont_GetResource());
if (!pkDefaultFont)
return;
m_kRenderTelemetryTextLine.SetTextPointer(pkDefaultFont);
m_kRenderTelemetryTextLine.SetOutline(true);
m_kRenderTelemetryTextLine.SetMultiLine(true);
m_kRenderTelemetryTextLine.SetColor(1.0f, 1.0f, 1.0f);
m_kRenderTelemetryTextLine.SetPosition(12.0f, 12.0f);
m_kRenderTelemetryTextLine.SetValueString(m_stRenderTelemetrySummary);
m_kRenderTelemetryTextLine.Update();
m_kRenderTelemetryTextLine.Render();
}
bool CPythonApplication::Process()
{
// m_Profiler.Clear();
DWORD dwStart = ELTimer_GetMSec();
///////////////////////////////////////////////////////////////////////////////////////////////////
static DWORD s_dwUpdateFrameCount = 0;
static DWORD s_dwRenderFrameCount = 0;
static DWORD s_dwFaceCount = 0;
static UINT s_uiLoad = 0;
static DWORD s_dwCheckTime = ELTimer_GetMSec();
static double s_fNextUpdateTime = static_cast<double>(ELTimer_GetMSec());
static double s_fNextRenderTime = static_cast<double>(ELTimer_GetMSec());
static double s_fFixedFrameTime = static_cast<double>(ELTimer_GetMSec());
DWORD dwCurrentTime = ELTimer_GetMSec();
const double fCurrentTime = static_cast<double>(dwCurrentTime);
const bool bSampleRenderTelemetry = IsRenderTelemetrySamplingEnabled();
if (bSampleRenderTelemetry && !m_dwRenderTelemetryWindowStartMS)
ResetRenderTelemetryWindow(dwCurrentTime);
if (bSampleRenderTelemetry)
++m_dwRenderTelemetryLoopCount;
if (ELTimer_GetMSec() - s_dwCheckTime > 1000) [[unlikely]] {
m_dwUpdateFPS = s_dwUpdateFrameCount;
m_dwRenderFPS = s_dwRenderFrameCount;
m_dwLoad = s_uiLoad;
m_dwFaceCount = s_dwFaceCount / std::max(1ul, s_dwRenderFrameCount);
s_dwCheckTime = ELTimer_GetMSec();
s_uiLoad = s_dwFaceCount = s_dwUpdateFrameCount = s_dwRenderFrameCount = 0;
}
if (fCurrentTime - s_fNextUpdateTime > kMaxCatchUpDelayMS)
{
s_fNextUpdateTime = fCurrentTime;
s_fFixedFrameTime = fCurrentTime;
}
if (fCurrentTime - s_fNextRenderTime > kMaxCatchUpDelayMS)
s_fNextRenderTime = fCurrentTime;
int iUpdateCount = 0;
while (fCurrentTime + 0.0001 >= s_fNextUpdateTime)
{
if (!m_isFrameSkipDisable && iUpdateCount >= 5)
{
s_fNextUpdateTime = fCurrentTime;
s_fFixedFrameTime = fCurrentTime;
break;
}
++iUpdateCount;
s_fNextUpdateTime += kFixedUpdateMS;
s_fFixedFrameTime += kFixedUpdateMS;
ELTimer_SetFrameMSecValue(static_cast<DWORD>(s_fFixedFrameTime));
m_v3LastCenterPosition = m_v3CenterPosition;
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime1=ELTimer_GetMSec();
#endif
CTimer& rkTimer=CTimer::Instance();
rkTimer.Advance();
m_fGlobalTime = rkTimer.GetCurrentSecond();
m_fGlobalElapsedTime = rkTimer.GetElapsedSecond();
DWORD updatestart = ELTimer_GetMSec();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime2=ELTimer_GetMSec();
#endif
// Network I/O
m_pyNetworkStream.Process();
//m_pyNetworkDatagram.Process();
m_kGuildMarkUploader.Process();
m_kGuildMarkDownloader.Process();
m_kAccountConnector.Process();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime3=ELTimer_GetMSec();
#endif
//////////////////////
// Input Process
// Keyboard
UpdateKeyboard();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime4=ELTimer_GetMSec();
#endif
// Mouse
POINT Point;
if (GetCursorPos(&Point)) [[likely]] {
ScreenToClient(m_hWnd, &Point);
OnMouseMove(Point.x, Point.y);
}
//////////////////////
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime5=ELTimer_GetMSec();
#endif
//!@# Alt+Tab Áß SetTransfor ¿¡¼­ ƨ±è Çö»ó ÇØ°áÀ» À§ÇØ - [levites]
//if (m_isActivateWnd)
__UpdateCamera();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime6=ELTimer_GetMSec();
#endif
// Update Game Playing
CResourceManager::Instance().Update();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime7=ELTimer_GetMSec();
#endif
OnCameraUpdate();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime8=ELTimer_GetMSec();
#endif
OnMouseUpdate();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime9=ELTimer_GetMSec();
#endif
CGrannyMaterial::TranslateSpecularMatrix(g_specularSpd, g_specularSpd, 0.0f);
OnUIUpdate();
#ifdef __PERFORMANCE_CHECK__
DWORD dwUpdateTime10=ELTimer_GetMSec();
if (dwUpdateTime10-dwUpdateTime1>10)
{
static FILE* fp=fopen("perf_app_update.txt", "w");
fprintf(fp, "AU.Total %d (Time %d)\n", dwUpdateTime9-dwUpdateTime1, ELTimer_GetMSec());
fprintf(fp, "AU.TU %d\n", dwUpdateTime2-dwUpdateTime1);
fprintf(fp, "AU.NU %d\n", dwUpdateTime3-dwUpdateTime2);
fprintf(fp, "AU.KU %d\n", dwUpdateTime4-dwUpdateTime3);
fprintf(fp, "AU.MP %d\n", dwUpdateTime5-dwUpdateTime4);
fprintf(fp, "AU.CP %d\n", dwUpdateTime6-dwUpdateTime5);
fprintf(fp, "AU.RU %d\n", dwUpdateTime7-dwUpdateTime6);
fprintf(fp, "AU.CU %d\n", dwUpdateTime8-dwUpdateTime7);
fprintf(fp, "AU.MU %d\n", dwUpdateTime9-dwUpdateTime8);
fprintf(fp, "AU.UU %d\n", dwUpdateTime10-dwUpdateTime9);
fprintf(fp, "----------------------------------\n");
fflush(fp);
}
#endif
//UpdateÇϴµ¥ °É¸°½Ã°£.delta°ª
m_dwCurUpdateTime = ELTimer_GetMSec() - updatestart;
if (bSampleRenderTelemetry)
{
++m_dwRenderTelemetryUpdateCount;
m_fRenderTelemetryUpdateTimeSumMS += static_cast<double>(m_dwCurUpdateTime);
}
++s_dwUpdateFrameCount;
}
const double fPreviousUpdateTime = s_fNextUpdateTime - kFixedUpdateMS;
m_fRenderInterpolationFactor = ClampInterpolationFactor(static_cast<float>((fCurrentTime - fPreviousUpdateTime) / kFixedUpdateMS));
DWORD dwRenderStartTime = ELTimer_GetMSec();
bool canRender = true;
bool didRender = false;
if (m_isMinimizedWnd) [[unlikely]] {
canRender = false;
}
else [[likely]] {
if (m_pyGraphic.IsLostDevice()) [[unlikely]] {
CPythonBackground& rkBG = CPythonBackground::Instance();
rkBG.ReleaseCharacterShadowTexture();
if (m_pyGraphic.RestoreDevice())
rkBG.CreateCharacterShadowTexture();
else
canRender = false;
}
}
if (canRender) [[likely]]
{
// RestoreLostDevice
CCullingManager::Instance().Update();
if (m_pyGraphic.Begin()) [[likely]] {
m_pyGraphic.ClearDepthBuffer();
#ifdef _DEBUG
m_pyGraphic.SetClearColor(0.3f, 0.3f, 0.3f);
m_pyGraphic.Clear();
#endif
/////////////////////
// Interface
m_pyGraphic.SetInterfaceRenderState();
OnUIRender();
RenderPerformanceHUD();
OnMouseRender();
/////////////////////
m_pyGraphic.End();
m_pyGraphic.Show();
DWORD dwRenderEndTime = ELTimer_GetMSec();
didRender = true;
static DWORD s_dwRenderCheckTime = dwRenderEndTime;
static DWORD s_dwRenderRangeTime = 0;
static DWORD s_dwRenderRangeFrame = 0;
m_dwCurRenderTime = dwRenderEndTime - dwRenderStartTime;
s_dwRenderRangeTime += m_dwCurRenderTime;
++s_dwRenderRangeFrame;
if (dwRenderEndTime-s_dwRenderCheckTime>1000) [[unlikely]] {
m_fAveRenderTime=float(double(s_dwRenderRangeTime)/double(s_dwRenderRangeFrame));
s_dwRenderCheckTime=ELTimer_GetMSec();
s_dwRenderRangeTime=0;
s_dwRenderRangeFrame=0;
}
DWORD dwCurFaceCount=m_pyGraphic.GetFaceCount();
m_pyGraphic.ResetFaceCount();
s_dwFaceCount += dwCurFaceCount;
if (dwCurFaceCount > 5000)
{
m_dwFaceAccCount += dwCurFaceCount;
m_dwFaceAccTime += m_dwCurRenderTime;
m_fFaceSpd=(m_dwFaceAccCount/m_dwFaceAccTime);
// °Å¸® ÀÚµ¿ Á¶Àý
if (-1 == m_iForceSightRange)
{
static float s_fAveRenderTime = 16.0f;
float fRatio=0.3f;
s_fAveRenderTime=(s_fAveRenderTime*(100.0f-fRatio)+std::max(16.0f, (float)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=std::max((float)(fNear+(fFar-fNear)*(dbAvePow)/dbMaxPow), fNear);
m_pyBackground.SetViewDistanceSet(0, fDistance);
}
// °Å¸® °­Á¦ ¼³Á¤½Ã
else
{
m_pyBackground.SetViewDistanceSet(0, float(m_iForceSightRange));
}
}
else
{
// 10000 Æú¸®°ï º¸´Ù ÀûÀ»¶§´Â °¡Àå ¸Ö¸® º¸ÀÌ°Ô ÇÑ´Ù
m_pyBackground.SetViewDistanceSet(0, 25600.0f);
}
++s_dwRenderFrameCount;
if (bSampleRenderTelemetry)
{
++m_dwRenderTelemetryRenderCount;
m_fRenderTelemetryRenderTimeSumMS += static_cast<double>(m_dwCurRenderTime);
m_fRenderTelemetryInterpolationSum += static_cast<double>(m_fRenderInterpolationFactor);
if (m_dwRenderTelemetryLastPresentTime)
{
m_fRenderTelemetryPresentGapSumMS += static_cast<double>(dwRenderEndTime - m_dwRenderTelemetryLastPresentTime);
++m_dwRenderTelemetryPresentGapSamples;
}
m_dwRenderTelemetryLastPresentTime = dwRenderEndTime;
}
}
}
if (bSampleRenderTelemetry && !didRender)
++m_dwRenderTelemetryBlockedRenderCount;
if (m_iFPS > 0)
{
const double fRenderFrameMS = 1000.0 / static_cast<double>(m_iFPS);
s_fNextRenderTime += fRenderFrameMS;
const double fSleepMS = s_fNextRenderTime - static_cast<double>(ELTimer_GetMSec());
if (fSleepMS > 0.999)
{
const UINT uiSleepMS = static_cast<UINT>(fSleepMS);
s_uiLoad -= std::min(s_uiLoad, uiSleepMS);
const DWORD dwSleepStart = ELTimer_GetMSec();
Sleep(static_cast<DWORD>(fSleepMS));
if (bSampleRenderTelemetry)
m_fRenderTelemetrySleepTimeSumMS += static_cast<double>(ELTimer_GetMSec() - dwSleepStart);
}
}
else
{
s_fNextRenderTime = static_cast<double>(ELTimer_GetMSec());
}
s_uiLoad += ELTimer_GetMSec() - dwStart;
const DWORD dwTelemetryNow = ELTimer_GetMSec();
if (bSampleRenderTelemetry && dwTelemetryNow - m_dwRenderTelemetryWindowStartMS >= m_dwRenderTelemetryIntervalMS)
FlushRenderTelemetryWindow(dwTelemetryNow);
//m_Profiler.ProfileByScreen();
return true;
}
void CPythonApplication::ApplyRenderInterpolation()
{
const float fInterpolation = ClampInterpolationFactor(m_fRenderInterpolationFactor);
m_kChrMgr.ApplyRenderInterpolation(fInterpolation);
if (CAMERA_MODE_NORMAL != m_iCameraMode)
return;
if (0.0f != m_kCmrPos.m_fViewDir || 0.0f != m_kCmrPos.m_fCrossDir || 0.0f != m_kCmrPos.m_fUpDir)
return;
CCamera* pCurrentCamera = CCameraManager::Instance().GetCurrentCamera();
if (!pCurrentCamera)
return;
const D3DXVECTOR3 v3CenterPosition = LerpVector3(m_v3LastCenterPosition, m_v3CenterPosition, fInterpolation);
const float fDistance = pCurrentCamera->GetDistance();
const float fPitch = pCurrentCamera->GetPitch();
const float fRotation = pCurrentCamera->GetRoll();
m_pyGraphic.SetPositionCamera(
v3CenterPosition.x,
v3CenterPosition.y,
v3CenterPosition.z + pCurrentCamera->GetTargetHeight(),
fDistance,
fPitch,
fRotation);
}
void CPythonApplication::UpdateClientRect()
{
RECT rcApp;
GetClientRect(&rcApp);
OnSizeChange(rcApp.right - rcApp.left, rcApp.bottom - rcApp.top);
}
void CPythonApplication::SetMouseHandler(PyObject* poMouseHandler)
{
m_poMouseHandler = poMouseHandler;
}
int CPythonApplication::CheckDeviceState()
{
CGraphicDevice::EDeviceState e_deviceState = m_grpDevice.GetDeviceState();
switch (e_deviceState)
{
// µð¹ÙÀ̽º°¡ ¾øÀ¸¸é ÇÁ·Î±×·¥ÀÌ Á¾·á µÇ¾î¾ß ÇÑ´Ù.
case CGraphicDevice::DEVICESTATE_NULL:
return DEVICE_STATE_FALSE;
// DEVICESTATE_BROKENÀÏ ¶§´Â ´ÙÀ½ ·çÇÁ¿¡¼­ º¹±¸ µÉ ¼ö ÀÖµµ·Ï ¸®ÅÏ ÇÑ´Ù.
// ±×³É ÁøÇàÇÒ °æ¿ì DrawPrimitive °°Àº °ÍÀ» Çϸé ÇÁ·Î±×·¥ÀÌ ÅÍÁø´Ù.
case CGraphicDevice::DEVICESTATE_BROKEN:
return DEVICE_STATE_SKIP;
case CGraphicDevice::DEVICESTATE_NEEDS_RESET:
if (!m_grpDevice.Reset())
return DEVICE_STATE_SKIP;
break;
}
return DEVICE_STATE_OK;
}
bool CPythonApplication::CreateDevice(int width, int height, int Windowed, int bit, int frequency)
{
int iRet;
m_grpDevice.InitBackBufferCount(2);
iRet = m_grpDevice.Create(GetWindowHandle(), width, height, Windowed ? true : false, bit, frequency);
switch (iRet)
{
case CGraphicDevice::CREATE_OK:
return true;
case CGraphicDevice::CREATE_REFRESHRATE:
return true;
case CGraphicDevice::CREATE_ENUM:
case CGraphicDevice::CREATE_DETECT:
SET_EXCEPTION(CREATE_NO_APPROPRIATE_DEVICE);
TraceError("CreateDevice: Enum & Detect failed");
return false;
case CGraphicDevice::CREATE_NO_DIRECTX:
SET_EXCEPTION(CREATE_NO_DIRECTX);
TraceError("CreateDevice: DirectX 8.1 or greater required to run game");
return false;
case CGraphicDevice::CREATE_DEVICE:
SET_EXCEPTION(CREATE_DEVICE);
TraceError("CreateDevice: GraphicDevice create failed");
return false;
case CGraphicDevice::CREATE_FORMAT:
SET_EXCEPTION(CREATE_FORMAT);
TraceError("CreateDevice: Change the screen format");
return false;
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:
if (iRet & CGraphicDevice::CREATE_OK)
{
if (iRet & CGraphicDevice::CREATE_NO_TNL)
{
CGrannyLODController::SetMinLODMode(true);
}
return true;
}
SET_EXCEPTION(UNKNOWN_ERROR);
TraceError("CreateDevice: Unknown Error!");
return false;
}
}
void CPythonApplication::SetUserMovingMainWindow(bool flag)
{
if (flag && !GetCursorPos(&m_InitialMouseMovingPoint))
return;
m_IsMovingMainWindow = flag;
}
bool CPythonApplication::IsUserMovingMainWindow() const
{
return m_IsMovingMainWindow;
}
void CPythonApplication::UpdateMainWindowPosition()
{
POINT finalPoint{};
if (GetCursorPos(&finalPoint))
{
LONG xDiff = finalPoint.x - m_InitialMouseMovingPoint.x;
LONG yDiff = finalPoint.y - m_InitialMouseMovingPoint.y;
RECT r{};
GetWindowRect(&r);
SetPosition(r.left + xDiff, r.top + yDiff);
m_InitialMouseMovingPoint = finalPoint;
}
}
void CPythonApplication::Loop()
{
while (1)
{
if (IsUserMovingMainWindow())
UpdateMainWindowPosition();
if (IsMessage())
{
if (!MessageProcess())
break;
}
else
{
if (!Process())
break;
m_dwLastIdleTime=ELTimer_GetMSec();
}
}
}
bool LoadLocaleData(const char* localePath)
{
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", GetLocalePathCommon());
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", GetLocalePathCommon());
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);
}
return true;
}
unsigned __GetWindowMode(bool windowed)
{
if (windowed)
return WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
return WS_POPUP;
}
bool CPythonApplication::Create(PyObject * poSelf, const char * c_szName, int width, int height, int Windowed)
{
// Initialize Game Thread Pool first - required by other systems
CGameThreadPool* pThreadPool = CGameThreadPool::InstancePtr();
if (pThreadPool)
{
pThreadPool->Initialize();
}
NANOBEGIN
Windowed = CPythonSystem::Instance().IsWindowed() ? 1 : 0;
bool bAnotherWindow = false;
std::wstring wWindowName = Utf8ToWide(c_szName ? c_szName : "");
if (FindWindowW(nullptr, wWindowName.c_str()))
bAnotherWindow = true;
m_dwWidth = width;
m_dwHeight = height;
// Window
UINT WindowMode = __GetWindowMode(Windowed ? true : false);
if (!CMSWindow::Create(c_szName, 4, 0, WindowMode, ::LoadIcon( GetInstance(), MAKEINTRESOURCE( IDI_METIN2 ) ), IDC_CURSOR_NORMAL))
{
TraceError("CMSWindow::Create failed");
SET_EXCEPTION(CREATE_WINDOW);
return false;
}
if (m_pySystem.IsUseDefaultIME())
{
CPythonIME::Instance().UseDefaultIME();
}
#if defined(ENABLE_DISCORD_RPC)
m_pyNetworkStream.Discord_Start();
#endif
if (!m_pySystem.IsWindowed())
{
m_isWindowed = false;
m_isWindowFullScreenEnable = TRUE;
__SetFullScreenWindow(GetWindowHandle(), width, height, m_pySystem.GetBPP());
Windowed = true;
}
else
{
AdjustSize(m_pySystem.GetWidth(), m_pySystem.GetHeight());
if (Windowed)
{
m_isWindowed = true;
if (bAnotherWindow)
{
RECT rc;
GetClientRect(&rc);
int windowWidth = rc.right - rc.left;
int windowHeight = (rc.bottom - rc.top);
CMSApplication::SetPosition(GetScreenWidth() - windowWidth, GetScreenHeight() - 60 - windowHeight);
}
SetPosition(-8, 0); //Fix
}
else
{
m_isWindowed = false;
SetPosition(0, 0);
}
}
NANOEND
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Cursor
if (!CreateCursors())
{
TraceError("CMSWindow::Cursors Create Error");
SET_EXCEPTION("CREATE_CURSOR");
return false;
}
if (!m_pySystem.IsNoSoundCard())
{
// Sound
if (!m_SoundEngine.Initialize())
{
TraceError("Failed to initialize sound manager!");
return false; // Is this important enough to stop the client?
}
}
extern bool GRAPHICS_CAPS_SOFTWARE_TILING;
if (!m_pySystem.IsAutoTiling())
GRAPHICS_CAPS_SOFTWARE_TILING = m_pySystem.IsSoftwareTiling();
// Device
if (!CreateDevice(m_pySystem.GetWidth(), m_pySystem.GetHeight(), Windowed, m_pySystem.GetBPP(), m_pySystem.GetFrequency()))
return false;
GrannyCreateSharedDeformBuffer();
if (m_pySystem.IsAutoTiling())
{
if (m_grpDevice.IsFastTNL())
{
m_pyBackground.ReserveSoftwareTilingEnable(false);
}
else
{
m_pyBackground.ReserveSoftwareTilingEnable(true);
}
}
else
{
m_pyBackground.ReserveSoftwareTilingEnable(m_pySystem.IsSoftwareTiling());
}
SetVisibleMode(true);
if (m_isWindowFullScreenEnable)
{
SetWindowPos(GetWindowHandle(), HWND_TOP, 0, 0, width, height, SWP_SHOWWINDOW);
}
if (!InitializeKeyboard(GetWindowHandle()))
return false;
m_pySystem.GetDisplaySettings();
// Mouse
if (m_pySystem.IsSoftwareCursor())
SetCursorMode(CURSOR_MODE_SOFTWARE);
else
SetCursorMode(CURSOR_MODE_HARDWARE);
// Network
if (!m_netDevice.Create())
{
TraceError("NetDevice::Create failed");
SET_EXCEPTION("CREATE_NETWORK");
return false;
}
if (!m_grpDevice.IsFastTNL())
CGrannyLODController::SetMinLODMode(true);
m_pyItem.Create();
// Other Modules
DefaultFont_Startup();
CPythonIME::Instance().Create(GetWindowHandle());
CPythonIME::Instance().SetText("", 0);
CPythonTextTail::Instance().Initialize();
// Light Manager
m_LightManager.Initialize();
CGraphicImageInstance::CreateSystem(32);
// ¹é¾÷
STICKYKEYS sStickKeys;
memset(&sStickKeys, 0, sizeof(sStickKeys));
sStickKeys.cbSize = sizeof(sStickKeys);
SystemParametersInfo( SPI_GETSTICKYKEYS, sizeof(sStickKeys), &sStickKeys, 0 );
m_dwStickyKeysFlag = sStickKeys.dwFlags;
// ¼³Á¤
sStickKeys.dwFlags &= ~(SKF_AVAILABLE|SKF_HOTKEYACTIVE);
SystemParametersInfo( SPI_SETSTICKYKEYS, sizeof(sStickKeys), &sStickKeys, 0 );
// SphereMap
CGrannyMaterial::CreateSphereMap(0, "d:/ymir work/special/spheremap.jpg");
CGrannyMaterial::CreateSphereMap(1, "d:/ymir work/special/spheremap01.jpg");
return true;
}
void CPythonApplication::SetGlobalCenterPosition(int32_t x, int32_t y)
{
CPythonBackground& rkBG=CPythonBackground::Instance();
rkBG.GlobalPositionToLocalPosition(x, y);
float z = CPythonBackground::Instance().GetHeight(x, y);
CPythonApplication::Instance().SetCenterPosition(x, y, z);
}
void CPythonApplication::SetCenterPosition(float fx, float fy, float fz)
{
m_v3CenterPosition.x = +fx;
m_v3CenterPosition.y = -fy;
m_v3CenterPosition.z = +fz;
}
void CPythonApplication::GetCenterPosition(TPixelPosition * pPixelPosition)
{
pPixelPosition->x = +m_v3CenterPosition.x;
pPixelPosition->y = -m_v3CenterPosition.y;
pPixelPosition->z = +m_v3CenterPosition.z;
}
void CPythonApplication::SetServerTime(time_t tTime)
{
m_dwStartLocalTime = ELTimer_GetMSec();
m_tServerTime = tTime;
m_tLocalStartTime = time(0);
}
time_t CPythonApplication::GetServerTime()
{
return (ELTimer_GetMSec() - m_dwStartLocalTime) + m_tServerTime;
}
// 2005.03.28 - MALL ¾ÆÀÌÅÛ¿¡ µé¾îÀÖ´Â ½Ã°£ÀÇ ´ÜÀ§°¡ ¼­¹ö¿¡¼­ time(0) À¸·Î ¸¸µé¾îÁö´Â
// °ªÀ̱⠶§¹®¿¡ ´ÜÀ§¸¦ ¸ÂÃß±â À§ÇØ ½Ã°£ °ü·Ã 󸮸¦ º°µµ·Î Ãß°¡
time_t CPythonApplication::GetServerTimeStamp()
{
return (time(0) - m_tLocalStartTime) + m_tServerTime;
}
float CPythonApplication::GetGlobalTime()
{
return m_fGlobalTime;
}
float CPythonApplication::GetGlobalElapsedTime()
{
return m_fGlobalElapsedTime;
}
void CPythonApplication::SetFPS(int iFPS)
{
m_iFPS = std::max(0, iFPS);
char szTargetFPS[16];
FormatRenderTargetFPSLabel(m_iFPS, szTargetFPS, sizeof(szTargetFPS));
m_stRenderTelemetrySummary = "Render telemetry\nTarget FPS: ";
m_stRenderTelemetrySummary += szTargetFPS;
m_stRenderTelemetrySummary += "\nCollecting frame pacing...";
if (IsRenderTelemetrySamplingEnabled())
ResetRenderTelemetryWindow(ELTimer_GetMSec());
if (m_bRenderTelemetryEnabled)
{
AppendRenderTelemetryTrace(
"set_fps elapsed_ms=%lu target_fps=%u",
static_cast<unsigned long>(ELTimer_GetMSec() - m_dwStartLocalTime),
m_iFPS);
}
}
void CPythonApplication::SetPerformanceHUDVisible(bool isVisible)
{
m_bRenderTelemetryHudVisible = isVisible;
if (IsRenderTelemetrySamplingEnabled())
ResetRenderTelemetryWindow(ELTimer_GetMSec());
else
m_dwRenderTelemetryWindowStartMS = 0;
if (m_bRenderTelemetryEnabled)
{
AppendRenderTelemetryTrace(
"set_hud elapsed_ms=%lu visible=%u",
static_cast<unsigned long>(ELTimer_GetMSec() - m_dwStartLocalTime),
m_bRenderTelemetryHudVisible ? 1u : 0u);
}
}
int CPythonApplication::GetWidth()
{
return m_dwWidth;
}
int CPythonApplication::GetHeight()
{
return m_dwHeight;
}
void CPythonApplication::SetConnectData(const char * c_szIP, int iPort)
{
m_strIP = c_szIP;
m_iPort = iPort;
}
void CPythonApplication::GetConnectData(std::string & rstIP, int & riPort)
{
rstIP = m_strIP;
riPort = m_iPort;
}
void CPythonApplication::EnableSpecialCameraMode()
{
m_isSpecialCameraMode = TRUE;
}
void CPythonApplication::SetCameraSpeed(int iPercentage)
{
m_fCameraRotateSpeed = c_fDefaultCameraRotateSpeed * float(iPercentage) / 100.0f;
m_fCameraPitchSpeed = c_fDefaultCameraPitchSpeed * float(iPercentage) / 100.0f;
m_fCameraZoomSpeed = c_fDefaultCameraZoomSpeed * float(iPercentage) / 100.0f;
}
void CPythonApplication::SetForceSightRange(int iRange)
{
m_iForceSightRange = iRange;
}
void CPythonApplication::Clear()
{
m_pySystem.Clear();
}
void CPythonApplication::Destroy()
{
// SphereMap
CGrannyMaterial::DestroySphereMap();
m_kRenderTelemetryTextLine.Destroy();
m_kWndMgr.Destroy();
CPythonSystem::Instance().SaveConfig();
DestroyCollisionInstanceSystem();
m_pySystem.SaveInterfaceStatus();
m_pyEventManager.Destroy();
m_FlyingManager.Destroy();
m_pyMiniMap.Destroy();
m_pyTextTail.Destroy();
m_pyChat.Destroy();
m_kChrMgr.Destroy();
m_RaceManager.Destroy();
m_pyItem.Destroy();
m_kItemMgr.Destroy();
m_pyBackground.Destroy();
m_kEftMgr.Destroy();
m_LightManager.Destroy();
// Game Thread Pool
CGameThreadPool::Instance().Destroy();
// DEFAULT_FONT
DefaultFont_Cleanup();
// END_OF_DEFAULT_FONT
GrannyDestroySharedDeformBuffer();
m_pyGraphic.Destroy();
#if defined(ENABLE_DISCORD_RPC)
m_pyNetworkStream.Discord_Close();
#endif
//m_pyNetworkDatagram.Destroy();
m_pyRes.Destroy();
m_kGuildMarkDownloader.Disconnect();
CGrannyModelInstance::DestroySystem();
CGraphicImageInstance::DestroySystem();
m_grpDevice.Destroy();
//CSpeedTreeForestDirectX::Instance().Clear();
CAttributeInstance::DestroySystem();
CTextFileLoader::DestroySystem();
DestroyCursors();
CMSApplication::Destroy();
STICKYKEYS sStickKeys;
memset(&sStickKeys, 0, sizeof(sStickKeys));
sStickKeys.cbSize = sizeof(sStickKeys);
sStickKeys.dwFlags = m_dwStickyKeysFlag;
SystemParametersInfo( SPI_SETSTICKYKEYS, sizeof(sStickKeys), &sStickKeys, 0 );
}