Skip to content
Draft
Show file tree
Hide file tree
Changes from 9 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* pMarker = static_cast<CClientMarker*>(this);
return pMarker->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
82 changes: 78 additions & 4 deletions Client/mods/deathmatch/logic/CClientGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ CVector g_vecBulletFireEndPosition;
#define DOUBLECLICK_TIMEOUT 330
#define DOUBLECLICK_MOVE_THRESHOLD 10.0f

// Ray casting constants for marker click detection
constexpr float MARKER_CLICK_RAY_DEPTH = 300.0f; // Screen-to-world ray projection depth
constexpr float MARKER_CLICK_MAX_DISTANCE = 99999.9f; // 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 @@ -2325,6 +2329,57 @@ void CClientGame::ProcessServerControlBind(CControlFunctionBind* pBind)
m_pNetAPI->RPC(KEY_BIND, bitStream.pBitStream);
}

CClientMarker* CClientGame::CheckMarkerClick(float fScreenX, float fScreenY, float& fDistance)
{
if (!m_pMarkerManager)
return nullptr;

CCamera* pCamera = g_pGame->GetCamera();
CMatrix matCamera;
pCamera->GetMatrix(&matCamera);
CVector vecOrigin = matCamera.vPos;

CVector vecTarget, vecScreen(fScreenX, fScreenY, MARKER_CLICK_RAY_DEPTH);
g_pCore->GetGraphics()->CalcWorldCoors(&vecScreen, &vecTarget);

CVector vecRayDir = vecTarget - vecOrigin;
vecRayDir.Normalize();

CClientMarker* pClosestMarker = nullptr;
float fClosestDist = MARKER_CLICK_MAX_DISTANCE;

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

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

CSphere boundingSphere = pMarker->GetWorldBoundingSphere();

CVector vecToSphere = boundingSphere.vecPosition - vecOrigin;
float fProjection = vecToSphere.DotProduct(&vecRayDir);

if (fProjection <= 0.0f)
continue;

CVector vecClosestPoint = vecOrigin + vecRayDir * fProjection;
float fDistanceToRay = (boundingSphere.vecPosition - vecClosestPoint).Length();

if (fDistanceToRay <= boundingSphere.fRadius && fProjection < fClosestDist)
{
fClosestDist = fProjection;
pClosestMarker = pMarker;
}
}

if (pClosestMarker)
fDistance = fClosestDist;

return pClosestMarker;
}

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

CVector vecCollision;
ElementID CollisionEntityID = INVALID_ELEMENT_ID;
CClientEntity* pCollisionEntity = NULL;
CClientEntity* pCollisionEntity = nullptr;

if (bCollision && pColPoint)
{
vecCollision = pColPoint->GetPosition();
Expand All @@ -2415,9 +2471,7 @@ bool CClientGame::ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wPa

// 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 @@ -2457,6 +2511,25 @@ bool CClientGame::ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wPa
if (std::isnan(vecCollision.fZ))
vecCollision.fZ = 0;

float fMarkerDistance = 0.0f;
CClientMarker* pClickedMarker = CheckMarkerClick(static_cast<float>(iX), static_cast<float>(iY), fMarkerDistance);
if (pClickedMarker)
{
CVector vecMarkerPosition;
pClickedMarker->GetPosition(vecMarkerPosition);

CLuaArguments MarkerArguments;
MarkerArguments.PushString(szButton);
MarkerArguments.PushString(szState);
MarkerArguments.PushNumber(vecCursorPosition.fX);
MarkerArguments.PushNumber(vecCursorPosition.fY);
MarkerArguments.PushNumber(vecMarkerPosition.fX);
MarkerArguments.PushNumber(vecMarkerPosition.fY);
MarkerArguments.PushNumber(vecMarkerPosition.fZ);
MarkerArguments.PushNumber(fMarkerDistance);
pClickedMarker->CallEvent("onClientMarkerClick", MarkerArguments, false);
}

// Call the event for the client
CLuaArguments Arguments;
Arguments.PushString(szButton);
Expand Down Expand Up @@ -2540,7 +2613,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, MARKER_CLICK_RAY_DEPTH);
g_pCore->GetGraphics()->CalcWorldCoors(&vecScreen, &vecTarget);

// Call the onClientCursorMove event
Expand Down Expand Up @@ -2739,6 +2812,7 @@ void CClientGame::AddBuiltInEvents()
// Marker events
m_Events.AddEvent("onClientMarkerHit", "entity, matchingDimension", nullptr, false);
m_Events.AddEvent("onClientMarkerLeave", "entity, matchingDimension", nullptr, false);
m_Events.AddEvent("onClientMarkerClick", "button, state, screenX, screenY, worldX, worldY, worldZ, distance", nullptr, false);

m_Events.AddEvent("onClientPlayerMarkerHit", "marker, matchingDimension", nullptr, false);
m_Events.AddEvent("onClientPlayerMarkerLeave", "marker, matchingDimension", nullptr, false);
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 @@ -381,6 +381,7 @@ class CClientGame
void ProcessServerControlBind(CControlFunctionBind* pBind);

bool ProcessMessageForCursorEvents(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
CClientMarker* CheckMarkerClick(float fScreenX, float fScreenY, float& fDistance);
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 vecPosition;
GetPosition(vecPosition);

CVector vecScreen;
g_pCore->GetGraphics()->CalcScreenCoors(&vecPosition, &vecScreen);

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

float fResWidth = static_cast<float>(g_pCore->GetGraphics()->GetViewportWidth());
float fResHeight = static_cast<float>(g_pCore->GetGraphics()->GetViewportHeight());

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

CVector vecEdgeScreen;
g_pCore->GetGraphics()->CalcScreenCoors(&vecEdgePos, &vecEdgeScreen);

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

float fScreenRadius = fabs(vecEdgeScreen.fX - vecScreen.fX);

return (vecScreen.fX + fScreenRadius) >= 0.0f && (vecScreen.fX - fScreenRadius) <= fResWidth &&
(vecScreen.fY + fScreenRadius) >= 0.0f && (vecScreen.fY - fScreenRadius) <= fResHeight;
}
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