feat: complete native client rendering parity updates
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "EterBase/Timer.h"
|
||||
#include "EterLib/Util.h"
|
||||
#include "EterLib/GrpBase.h"
|
||||
#include "EterLib/Camera.h"
|
||||
#include "../EterLib/HostCursor.h"
|
||||
#include "UserInterface/PythonNetworkStream.h"
|
||||
#include "UserInterface/AccountConnector.h"
|
||||
@@ -86,7 +87,11 @@ std::unique_ptr<CEffectManager> g_effect_manager;
|
||||
class GameApplicationAdapter final : public IAbstractApplication
|
||||
{
|
||||
public:
|
||||
void GetMousePosition(POINT* point) override { if (point) *point = {}; }
|
||||
void GetMousePosition(POINT* point) override
|
||||
{
|
||||
if (point)
|
||||
CPythonApplication::Instance().GetMousePosition(point);
|
||||
}
|
||||
float GetGlobalTime() override { return CTimer::Instance().GetCurrentSecond(); }
|
||||
float GetGlobalElapsedTime() override { return CTimer::Instance().GetElapsedSecond(); }
|
||||
void SkipRenderBuffering(DWORD) override {}
|
||||
@@ -144,6 +149,7 @@ struct GameSingletons
|
||||
CPythonSystem pySystem; // last CPythonApplication member (m_pySystem)
|
||||
};
|
||||
std::unique_ptr<GameSingletons> g_game_singletons;
|
||||
bool g_host_hardware_cursor_enabled = false;
|
||||
|
||||
bool fail(std::string* error, const std::string& text)
|
||||
{
|
||||
@@ -229,6 +235,26 @@ void init_2v0_gameplay_stubs();
|
||||
|
||||
namespace PythonBoot
|
||||
{
|
||||
void SetHostHardwareCursorEnabled(bool enabled)
|
||||
{
|
||||
g_host_hardware_cursor_enabled = enabled;
|
||||
}
|
||||
|
||||
bool HostHardwareCursorEnabled()
|
||||
{
|
||||
return g_host_hardware_cursor_enabled;
|
||||
}
|
||||
|
||||
int CursorShape()
|
||||
{
|
||||
return g_game_singletons ? CPythonApplication::Instance().GetCursorNum() : 0;
|
||||
}
|
||||
|
||||
bool CursorVisible()
|
||||
{
|
||||
return !g_game_singletons || CPythonApplication::Instance().GetCursorVisible();
|
||||
}
|
||||
|
||||
std::string CurrentMapName()
|
||||
{
|
||||
if (!g_game_singletons)
|
||||
@@ -255,9 +281,43 @@ void SetUISize(int width, int height)
|
||||
}
|
||||
}
|
||||
|
||||
void update_3d_pick_ray()
|
||||
{
|
||||
if (!g_game_singletons || !g_window_manager)
|
||||
return;
|
||||
if (!CPythonBackground::Instance().IsMapReady())
|
||||
return;
|
||||
long lx = 0, ly = 0;
|
||||
g_window_manager->GetMousePosition(lx, ly);
|
||||
const long sw = g_window_manager->GetScreenWidth();
|
||||
const long sh = g_window_manager->GetScreenHeight();
|
||||
if (sw <= 0 || sh <= 0)
|
||||
return;
|
||||
CScreen s;
|
||||
s.SetPerspective(30.0f, g_window_manager->GetAspect(), 100.0f, CPythonBackground::Instance().GetFarClip());
|
||||
s.UpdateViewMatrix();
|
||||
s.BuildViewFrustum();
|
||||
s.SetCursorPosition(lx, ly, sw, sh);
|
||||
POINT ptMouse{static_cast<LONG>(lx), static_cast<LONG>(ly)};
|
||||
CPythonItem::Instance().Update(ptMouse);
|
||||
CPythonCharacterManager::Instance().Pick();
|
||||
}
|
||||
|
||||
void UIMouseMove(int x, int y)
|
||||
{
|
||||
MtHostSetCursor(x, y);
|
||||
if (g_game_singletons)
|
||||
{
|
||||
CPythonApplication::Instance().OnMouseMove(x, y);
|
||||
if (g_window_manager)
|
||||
{
|
||||
long lx = x, ly = y;
|
||||
g_window_manager->GetMousePosition(lx, ly);
|
||||
MtHostSetCursor(static_cast<int>(lx), static_cast<int>(ly));
|
||||
}
|
||||
update_3d_pick_ray();
|
||||
return;
|
||||
}
|
||||
if (g_window_manager) g_window_manager->RunMouseMove(x, y);
|
||||
}
|
||||
|
||||
@@ -265,16 +325,55 @@ void UIMouseButton(int button, bool pressed, int x, int y)
|
||||
{
|
||||
MtHostSetCursor(x, y);
|
||||
if (!g_window_manager) return;
|
||||
g_window_manager->RunMouseMove(x, y);
|
||||
if (g_game_singletons)
|
||||
CPythonApplication::Instance().OnMouseMove(x, y);
|
||||
else
|
||||
g_window_manager->RunMouseMove(x, y);
|
||||
update_3d_pick_ray();
|
||||
switch (button)
|
||||
{
|
||||
case 1: if (pressed) g_window_manager->RunMouseLeftButtonDown(x, y); else g_window_manager->RunMouseLeftButtonUp(x, y); break;
|
||||
case 2: if (pressed) g_window_manager->RunMouseRightButtonDown(x, y); else g_window_manager->RunMouseRightButtonUp(x, y); break;
|
||||
case 3: if (pressed) g_window_manager->RunMouseMiddleButtonDown(x, y); else g_window_manager->RunMouseMiddleButtonUp(x, y); break;
|
||||
case 1:
|
||||
if (pressed)
|
||||
g_window_manager->RunMouseLeftButtonDown(x, y);
|
||||
else
|
||||
g_window_manager->RunMouseLeftButtonUp(x, y);
|
||||
break;
|
||||
case 2:
|
||||
if (pressed)
|
||||
{
|
||||
g_window_manager->RunMouseRightButtonDown(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_window_manager->RunMouseRightButtonUp(x, y);
|
||||
if (g_game_singletons)
|
||||
{
|
||||
CCamera* pkCmrCur = CCameraManager::Instance().GetCurrentCamera();
|
||||
if (pkCmrCur && pkCmrCur->IsDraging())
|
||||
CPythonApplication::Instance().OnMouseMiddleButtonUp(x, y);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (g_game_singletons)
|
||||
{
|
||||
if (pressed) CPythonApplication::Instance().OnMouseMiddleButtonDown(x, y);
|
||||
else CPythonApplication::Instance().OnMouseMiddleButtonUp(x, y);
|
||||
}
|
||||
if (pressed) g_window_manager->RunMouseMiddleButtonDown(x, y); else g_window_manager->RunMouseMiddleButtonUp(x, y);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void UIMouseWheel(int nLen)
|
||||
{
|
||||
CCameraManager& rkCmrMgr = CCameraManager::Instance();
|
||||
CCamera* pkCmrCur = rkCmrMgr.GetCurrentCamera();
|
||||
if (pkCmrCur)
|
||||
pkCmrCur->Wheel(nLen);
|
||||
}
|
||||
|
||||
// 40250 CPythonApplication::OnKeyDown/OnKeyUp (PythonApplicationEvent.cpp:130-146): ESC first goes
|
||||
// to RunPressEscapeKey (the OnPressEscapeKey chain every dialog closes on), then to RunKeyDown.
|
||||
void UIKey(int key, bool pressed)
|
||||
@@ -282,12 +381,80 @@ void UIKey(int key, bool pressed)
|
||||
if (!g_window_manager) return;
|
||||
if (pressed)
|
||||
{
|
||||
CPythonApplication::Instance().KeyDown(key);
|
||||
if (DIK_ESCAPE == key)
|
||||
g_window_manager->RunPressEscapeKey();
|
||||
g_window_manager->RunKeyDown(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPythonApplication::Instance().KeyUp(key);
|
||||
g_window_manager->RunKeyUp(key);
|
||||
}
|
||||
}
|
||||
|
||||
void SetMoveDirection(float angleDeg, bool moving)
|
||||
{
|
||||
if (!g_game_singletons) return;
|
||||
if (moving)
|
||||
CPythonPlayer::Instance().NEW_MoveToDirection(angleDeg);
|
||||
else
|
||||
CPythonPlayer::Instance().NEW_Stop();
|
||||
}
|
||||
|
||||
void SetAttackKey(bool pressed)
|
||||
{
|
||||
if (!g_game_singletons) return;
|
||||
CPythonPlayer::Instance().SetAttackKeyState(pressed);
|
||||
}
|
||||
|
||||
void CameraBeginDrag(int x, int y)
|
||||
{
|
||||
CCameraManager& rkCmrMgr = CCameraManager::Instance();
|
||||
CCamera* pkCmrCur = rkCmrMgr.GetCurrentCamera();
|
||||
if (pkCmrCur)
|
||||
pkCmrCur->BeginDrag(x, y);
|
||||
}
|
||||
|
||||
void CameraDrag(int x, int y)
|
||||
{
|
||||
CCameraManager& rkCmrMgr = CCameraManager::Instance();
|
||||
CCamera* pkCmrCur = rkCmrMgr.GetCurrentCamera();
|
||||
if (pkCmrCur)
|
||||
{
|
||||
POINT pt;
|
||||
pkCmrCur->Drag(x, y, &pt);
|
||||
}
|
||||
}
|
||||
|
||||
void CameraEndDrag()
|
||||
{
|
||||
CCameraManager& rkCmrMgr = CCameraManager::Instance();
|
||||
CCamera* pkCmrCur = rkCmrMgr.GetCurrentCamera();
|
||||
if (pkCmrCur)
|
||||
pkCmrCur->EndDrag();
|
||||
}
|
||||
|
||||
bool IsPointInsideActiveUI(int x, int y)
|
||||
{
|
||||
if (!g_window_manager) return false;
|
||||
return g_window_manager->IsPointInsideActiveUI(x, y);
|
||||
}
|
||||
|
||||
PlayerStatusInfo GetPlayerStatusInfo()
|
||||
{
|
||||
PlayerStatusInfo info{};
|
||||
if (!g_game_singletons) return info;
|
||||
info.level = CPythonPlayer::Instance().GetStatus(POINT_LEVEL);
|
||||
info.hp = CPythonPlayer::Instance().GetStatus(POINT_HP);
|
||||
info.max_hp = CPythonPlayer::Instance().GetStatus(POINT_MAX_HP);
|
||||
info.sp = CPythonPlayer::Instance().GetStatus(POINT_SP);
|
||||
info.max_sp = CPythonPlayer::Instance().GetStatus(POINT_MAX_SP);
|
||||
info.exp = CPythonPlayer::Instance().GetStatus(POINT_EXP);
|
||||
info.max_exp = CPythonPlayer::Instance().GetStatus(POINT_NEXT_EXP);
|
||||
const char* szName = CPythonPlayer::Instance().GetName();
|
||||
if (szName) info.name = szName;
|
||||
return info;
|
||||
}
|
||||
|
||||
// 40250 CPythonApplication::WindowProcedure (PythonApplicationProcedure.cpp:111-117): WM_CHAR goes to
|
||||
@@ -346,6 +513,14 @@ void UIRender()
|
||||
if (g_window_manager) g_window_manager->Render();
|
||||
}
|
||||
|
||||
bool IsSoftwareCursorVisible()
|
||||
{
|
||||
if (!g_game_singletons)
|
||||
return false;
|
||||
return CPythonApplication::Instance().GetCursorMode() == CPythonApplication::CURSOR_MODE_SOFTWARE &&
|
||||
CPythonApplication::Instance().GetCursorVisible();
|
||||
}
|
||||
|
||||
bool Start(const char* stdlib_path, std::string* error)
|
||||
{
|
||||
if (g_launcher)
|
||||
@@ -647,6 +822,16 @@ void Stop()
|
||||
g_fiber.finished = false;
|
||||
// 40250 Main(): pyLauncher.Clear() runs before app->Destroy()/delete app, so the window manager
|
||||
// (a CPythonApplication member) is still alive while Py_Finalize runs the windows' __del__.
|
||||
if (Py_IsInitialized())
|
||||
{
|
||||
PyGILState_STATE gil = PyGILState_Ensure();
|
||||
PyRun_SimpleString(
|
||||
"import sys\n"
|
||||
"_mm = sys.modules.get('mouseModule')\n"
|
||||
"if _mm and hasattr(_mm, 'mouseController'):\n"
|
||||
" getattr(_mm.mouseController, 'cursorDict', {}).clear()\n");
|
||||
PyGILState_Release(gil);
|
||||
}
|
||||
g_launcher->Clear();
|
||||
g_game_singletons.reset();
|
||||
g_game_application.reset();
|
||||
|
||||
Reference in New Issue
Block a user