Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5e8e3f3
Fix marker screen detection and click events
MohabCodeX Aug 14, 2025
96d6533
Update
MohabCodeX Aug 14, 2025
03c6f61
Merge branch 'multitheftauto:master' into fix/client-side-entity
MohabCodeX Aug 16, 2025
a52e31c
update
MohabCodeX Aug 16, 2025
5929998
Refactor
MohabCodeX Aug 19, 2025
4ba63eb
Merge branch 'multitheftauto:master' into fix/client-side-entity
MohabCodeX Aug 20, 2025
148684c
Add marker click detection
MohabCodeX Aug 20, 2025
a468c71
Update
MohabCodeX Aug 20, 2025
beb6f94
Merge branch 'master' into fix/client-side-entity
MohabCodeX Aug 20, 2025
bcf244b
Update Client/mods/deathmatch/logic/CClientEntity.cpp
MohabCodeX Aug 20, 2025
98a9267
Refactor
MohabCodeX Aug 21, 2025
eb7bde5
Refactor
MohabCodeX Aug 21, 2025
74cbc2b
Merge branch 'master' into fix/client-side-entity
MohabCodeX Aug 21, 2025
5abe1e6
Merge branch 'master' into fix/client-side-entity
MohabCodeX Aug 21, 2025
2e75412
format
MohabCodeX Aug 21, 2025
41cea25
Merge branch 'master' into fix/client-side-entity
MohabCodeX Aug 22, 2025
148ecfb
Merge branch 'master' into fix/client-side-entity
MohabCodeX Aug 22, 2025
1a01ce0
Merge branch 'master' into fix/client-side-entity
MohabCodeX Aug 25, 2025
5266bf9
Merge branch 'master' into fix/client-side-entity
MohabCodeX Aug 26, 2025
e3c8b36
Merge branch 'master' into fix/client-side-entity
MohabCodeX Aug 31, 2025
5da2734
Merge branch 'master' into fix/client-side-entity
MohabCodeX Aug 31, 2025
6ed365f
Merge branch 'master' into fix/client-side-entity
MohabCodeX Sep 3, 2025
0f609ac
Refactor marker click handling
MohabCodeX Sep 3, 2025
7e0eaf7
Remove gta-reversed submodule
MohabCodeX Sep 3, 2025
05c5cef
Merge branch 'master' into fix/client-side-entity
MohabCodeX Sep 5, 2025
d27e8b9
Merge branch 'master' into fix/client-side-entity
MohabCodeX Sep 5, 2025
ea42a23
Merge branch 'master' into fix/client-side-entity
MohabCodeX Sep 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Client/mods/deathmatch/logic/CClientEntity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,13 @@ bool CClientEntity::IsOnScreen()
{
return pEntity->IsOnScreen();
}

if (GetType() == CCLIENTMARKER)
{
CClientMarker* marker = static_cast<CClientMarker*>(this);
return marker->IsClientSideOnScreen();
}

return false;
}

Expand Down
1 change: 1 addition & 0 deletions Client/mods/deathmatch/logic/CClientEntity.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ enum eClientEntityType

class CEntity;
class CClientColShape;
class CClientMarker;
class CClientPed;
class CCustomData;
class CElementGroup;
Expand Down
87 changes: 76 additions & 11 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*****************************************************************************/

#include "StdInc.h"
#include <limits>
#include <net/SyncStructures.h>
#include <game/C3DMarkers.h>
#include <game/CAnimBlendAssocGroup.h>
Expand Down Expand Up @@ -75,6 +76,10 @@ CVector g_vecBulletFireEndPosition;
#define DOUBLECLICK_TIMEOUT 330
#define DOUBLECLICK_MOVE_THRESHOLD 10.0f

// Ray casting constants for click detection
constexpr float CLICK_RAY_DEPTH = 300.0f; // Screen-to-world ray projection depth
constexpr float MAX_CLICK_DISTANCE = 6000.0f; // Maximum distance for closest marker comparison

static constexpr long long TIME_DISCORD_UPDATE_RATE = 15000;

CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo())
Expand Down Expand Up @@ -2337,6 +2342,48 @@ void CClientGame::ProcessServerControlBind(CControlFunctionBind* pBind)
m_pNetAPI->RPC(KEY_BIND, bitStream.pBitStream);
}

CClientMarker* CClientGame::GetClickedMarker(const CVector& vecOrigin, const CVector& vecTarget, float& fDistance) const
{
if (!m_pMarkerManager)
return nullptr;

CVector rayDirection = (vecTarget - vecOrigin);
rayDirection.Normalize();
CClientMarker* closestMarker = nullptr;
float closestDistance = MAX_CLICK_DISTANCE;

for (auto* marker : m_pMarkerManager->m_Markers)
{
if (!marker || !marker->IsStreamedIn() || !marker->IsVisible())
continue;

if (!marker->IsClientSideOnScreen())
continue;

const CSphere boundingSphere = marker->GetWorldBoundingSphere();

const CVector toSphere = boundingSphere.vecPosition - vecOrigin;
const float projection = toSphere.DotProduct(&rayDirection);

if (projection <= 0.0f)
continue;

const CVector closestPoint = vecOrigin + rayDirection * projection;
const float distanceToRay = (boundingSphere.vecPosition - closestPoint).Length();

if (distanceToRay <= boundingSphere.fRadius && projection < closestDistance)
{
closestDistance = projection;
closestMarker = marker;
}
}

if (closestMarker)
fDistance = closestDistance;

return closestMarker;
}

bool CClientGame::ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
bool bCursorForcedVisible = g_pCore->IsCursorForcedVisible();
Expand Down Expand Up @@ -2386,7 +2433,7 @@ bool CClientGame::ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wPa

CVector2D vecCursorPosition((float)iX, (float)iY);

CVector vecOrigin, vecTarget, vecScreen((float)iX, (float)iY, 300.0f);
CVector vecOrigin, vecTarget, vecScreen((float)iX, (float)iY, CLICK_RAY_DEPTH);
g_pCore->GetGraphics()->CalcWorldCoors(&vecScreen, &vecTarget);

// Grab the camera position
Expand All @@ -2404,32 +2451,50 @@ bool CClientGame::ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wPa

CVector vecCollision;
ElementID CollisionEntityID = INVALID_ELEMENT_ID;
CClientEntity* pCollisionEntity = NULL;
CClientEntity* collisionEntity = nullptr;
float closestDistance = std::numeric_limits<float>::max();

// Check standard entity collision distance
if (bCollision && pColPoint)
{
vecCollision = pColPoint->GetPosition();
closestDistance = (vecCollision - vecOrigin).Length();

if (pGameEntity)
{
CPools* pPools = g_pGame->GetPools();
CClientEntity* pEntity = pPools->GetClientEntity((DWORD*)pGameEntity->GetInterface());
if (pEntity)
{
pCollisionEntity = pEntity;
collisionEntity = pEntity;
if (!pEntity->IsLocalEntity())
CollisionEntityID = pEntity->GetID();
}
}
}
else

// Check marker collision and compare distances
float markerDistance = std::numeric_limits<float>::max();
CClientMarker* clickedMarker = GetClickedMarker(vecOrigin, vecTarget, markerDistance);

// Use marker if it's closer than any entity collision
if (clickedMarker && markerDistance < closestDistance)
{
collisionEntity = clickedMarker;
if (!clickedMarker->IsLocalEntity())
CollisionEntityID = clickedMarker->GetID();
clickedMarker->GetPosition(vecCollision);
closestDistance = markerDistance;
}
else if (!bCollision || !pColPoint)
{
// No entity collision found, use target position
vecCollision = vecTarget;
}

// Destroy the colpoint so we don't get a leak
if (pColPoint)
{
pColPoint->Destroy();
}

const char* szButton = NULL;
const char* szState = NULL;
Expand Down Expand Up @@ -2478,8 +2543,8 @@ bool CClientGame::ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wPa
Arguments.PushNumber(vecCollision.fX);
Arguments.PushNumber(vecCollision.fY);
Arguments.PushNumber(vecCollision.fZ);
if (pCollisionEntity)
Arguments.PushElement(pCollisionEntity);
if (collisionEntity)
Arguments.PushElement(collisionEntity);
else
Arguments.PushBoolean(false);
m_pRootEntity->CallEvent("onClientClick", Arguments, false);
Expand Down Expand Up @@ -2522,8 +2587,8 @@ bool CClientGame::ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wPa
DoubleClickArguments.PushNumber(vecCollision.fX);
DoubleClickArguments.PushNumber(vecCollision.fY);
DoubleClickArguments.PushNumber(vecCollision.fZ);
if (pCollisionEntity)
DoubleClickArguments.PushElement(pCollisionEntity);
if (collisionEntity)
DoubleClickArguments.PushElement(collisionEntity);
else
DoubleClickArguments.PushBoolean(false);
m_pRootEntity->CallEvent("onClientDoubleClick", DoubleClickArguments, false);
Expand Down Expand Up @@ -2552,7 +2617,7 @@ bool CClientGame::ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wPa
CVector2D vecResolution = g_pCore->GetGUI()->GetResolution();
CVector2D vecCursorPosition(((float)iX) / vecResolution.fX, ((float)iY) / vecResolution.fY);

CVector vecTarget, vecScreen((float)iX, (float)iY, 300.0f);
CVector vecTarget, vecScreen((float)iX, (float)iY, CLICK_RAY_DEPTH);
g_pCore->GetGraphics()->CalcWorldCoors(&vecScreen, &vecTarget);

// Call the onClientCursorMove event
Expand Down
1 change: 1 addition & 0 deletions Client/mods/deathmatch/logic/CClientGame.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ class CClientGame
void ProcessServerControlBind(CControlFunctionBind* pBind);

bool ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
CClientMarker* GetClickedMarker(const CVector& vecOrigin, const CVector& vecTarget, float& fDistance) const;
bool AreCursorEventsEnabled() { return m_bCursorEventsEnabled; }
void SetCursorEventsEnabled(bool bCursorEventsEnabled) { m_bCursorEventsEnabled = bCursorEventsEnabled; }

Expand Down
40 changes: 39 additions & 1 deletion Client/mods/deathmatch/logic/CClientMarker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ extern CClientGame* g_pClientGame;
#define M_PI 3.14159265358979323846
#endif

// Threshold for determining if a marker is considered on-screen.
// The value 0.1f represents the minimum depth (Z value in screen coordinates) at which a marker is visible.
// Markers with a screen Z value below this threshold are considered off-screen.
constexpr float CLIENT_MARKER_ONSCREEN_THRESHOLD = 0.1f;

unsigned int CClientMarker::m_uiStreamedInMarkers = 0;

CClientMarker::CClientMarker(CClientManager* pManager, ElementID ID, int iMarkerType) : ClassInit(this), CClientStreamElement(pManager->GetMarkerStreamer(), ID)
Expand Down Expand Up @@ -322,7 +327,7 @@ void CClientMarker::SetSize(float fSize)
break;
}
}

m_pMarker->SetSize(fSize);
}

Expand Down Expand Up @@ -540,3 +545,36 @@ void CClientMarker::SetIgnoreAlphaLimits(bool ignore)
{
m_pMarker->SetIgnoreAlphaLimits(ignore);
}

bool CClientMarker::IsClientSideOnScreen()
{
if (!IsStreamedIn() || !IsVisible())
return false;

CVector position;
GetPosition(position);

CVector screen;
g_pCore->GetGraphics()->CalcScreenCoors(&position, &screen);

if (screen.fZ <= CLIENT_MARKER_ONSCREEN_THRESHOLD)
return false;

float resWidth = static_cast<float>(g_pCore->GetGraphics()->GetViewportWidth());
float resHeight = static_cast<float>(g_pCore->GetGraphics()->GetViewportHeight());

CSphere boundingSphere = GetWorldBoundingSphere();
CVector edgePos = boundingSphere.vecPosition;
edgePos.fX += boundingSphere.fRadius;

CVector edgeScreen;
g_pCore->GetGraphics()->CalcScreenCoors(&edgePos, &edgeScreen);

if (edgeScreen.fZ <= CLIENT_MARKER_ONSCREEN_THRESHOLD)
return true;

float screenRadius = fabs(edgeScreen.fX - screen.fX);

return (screen.fX + screenRadius) >= 0.0f && (screen.fX - screenRadius) <= resWidth &&
(screen.fY + screenRadius) >= 0.0f && (screen.fY - screenRadius) <= resHeight;
}
2 changes: 2 additions & 0 deletions Client/mods/deathmatch/logic/CClientMarker.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class CClientMarker final : public CClientStreamElement, private CClientColCallb

static bool IsLimitReached();

bool IsClientSideOnScreen();

CClientColShape* GetColShape() { return m_pCollision; }

void Callback_OnCollision(CClientColShape& Shape, CClientEntity& Entity);
Expand Down