From 071378ec4326408a9520c79c96befca995d097f6 Mon Sep 17 00:00:00 2001 From: FileEX Date: Mon, 15 Jul 2024 13:48:09 +0200 Subject: [PATCH] Checkpoints arrow customization (#3550) Add the ability to change the color and alpha of the checkpoint marker target arrow. By default it is red with alpha 255. --- Client/game_sa/CCheckpointSA.cpp | 40 +++++++++++++++++++ Client/game_sa/CCheckpointSA.h | 13 ++++++ Client/game_sa/CCheckpointsSA.cpp | 11 +++++ Client/game_sa/CCheckpointsSA.h | 1 + Client/game_sa/CGameSA.cpp | 2 + .../deathmatch/logic/CClientCheckpoint.cpp | 22 ++++++++++ .../mods/deathmatch/logic/CClientCheckpoint.h | 7 ++++ .../mods/deathmatch/logic/CPacketHandler.cpp | 13 ++++++ .../logic/CStaticFunctionDefinitions.cpp | 19 +++++++++ .../logic/CStaticFunctionDefinitions.h | 1 + .../logic/luadefs/CLuaMarkerDefs.cpp | 26 ++++++++++++ .../deathmatch/logic/luadefs/CLuaMarkerDefs.h | 4 ++ .../mods/deathmatch/logic/rpc/CMarkerRPCs.cpp | 21 +++++++++- .../mods/deathmatch/logic/rpc/CMarkerRPCs.h | 1 + Client/sdk/game/CCheckpoint.h | 3 ++ Client/sdk/game/CCheckpoints.h | 1 + Server/mods/deathmatch/logic/CMarker.cpp | 21 ++++++++++ Server/mods/deathmatch/logic/CMarker.h | 6 +++ .../logic/CStaticFunctionDefinitions.cpp | 18 +++++++++ .../logic/CStaticFunctionDefinitions.h | 2 + .../logic/luadefs/CLuaMarkerDefs.cpp | 23 +++++++++++ .../deathmatch/logic/luadefs/CLuaMarkerDefs.h | 3 ++ .../logic/packets/CEntityAddPacket.cpp | 11 +++++ Shared/sdk/net/bitstream.h | 3 ++ Shared/sdk/net/rpc_enums.h | 1 + 25 files changed, 272 insertions(+), 1 deletion(-) diff --git a/Client/game_sa/CCheckpointSA.cpp b/Client/game_sa/CCheckpointSA.cpp index a7ebe0d263..0528dbb2ef 100644 --- a/Client/game_sa/CCheckpointSA.cpp +++ b/Client/game_sa/CCheckpointSA.cpp @@ -13,6 +13,10 @@ #include "C3DMarkerSA.h" #include "C3DMarkersSA.h" #include "CCheckpointSA.h" +#include "CCheckpointsSA.h" +#include "CGameSA.h" + +extern CGameSA* pGame; void CCheckpointSA::SetPosition(CVector* vecPosition) { @@ -132,3 +136,39 @@ void CCheckpointSA::Remove() GetInterface()->m_nType = 257; GetInterface()->rwColour = 0; } + +void CCheckpointSA::SetTargetArrowData(const SColor color, float size) noexcept +{ + m_targetArrowColor = color; + m_targetArrowSize = size; +} + +static void __cdecl RenderTargetArrow(CCheckpointSAInterface* pCheckpoint) +{ + CCheckpoint* checkpoint = pGame->GetCheckpoints()->FindMarker(pCheckpoint->m_nIdentifier); + if (!checkpoint) + return; + + CVector* position = checkpoint->GetPosition(); + CVector* direction = checkpoint->GetPointDirection(); + SColor color = checkpoint->GetTargetArrowColor(); + + ((void(__cdecl*)(float, float, float, float, std::uint8_t, std::uint8_t, std::uint8_t, std::uint8_t, float, float, float))C3dMarkers_DirectionArrowSet)(position->fX, position->fY, position->fZ, checkpoint->GetTargetArrowSize(), color.R, color.G, color.B, color.A, -direction->fX, -direction->fY, -direction->fZ); +} + +static void _declspec(naked) HOOK_CCheckpoint__Render() +{ + _asm { + pushad + push esi + call RenderTargetArrow + add esp, 4 + popad + jmp RETURN_CCheckpoint__Render + } +} + +void CCheckpointSA::StaticSetHooks() +{ + EZHookInstall(CCheckpoint__Render); +} diff --git a/Client/game_sa/CCheckpointSA.h b/Client/game_sa/CCheckpointSA.h index 539bf22c93..f06007edbb 100644 --- a/Client/game_sa/CCheckpointSA.h +++ b/Client/game_sa/CCheckpointSA.h @@ -14,6 +14,12 @@ #include #include +#define HOOKPOS_CCheckpoint__Render 0x725E56 +#define HOOKSIZE_CCheckpoint__Render 0x5 +static constexpr std::uint32_t RETURN_CCheckpoint__Render = 0x725E5B; + +#define C3dMarkers_DirectionArrowSet 0x721140 + class CCheckpointSAInterface { public: @@ -36,12 +42,16 @@ class CCheckpointSA : public CCheckpoint { private: CCheckpointSAInterface* internalInterface; + SColor m_targetArrowColor{0xFFFF4040}; + float m_targetArrowSize{0.625f}; public: CCheckpointSA(CCheckpointSAInterface* checkpointInterface) { internalInterface = checkpointInterface; }; CCheckpointSAInterface* GetInterface() { return internalInterface; } + static void StaticSetHooks(); + void SetPosition(CVector* vecPosition); CVector* GetPosition(); void SetPointDirection(CVector* vecPointDirection); @@ -62,4 +72,7 @@ class CCheckpointSA : public CCheckpoint void SetPulseFraction(float fPulseFraction); // doesn't work propperly (not virtualed) float GetPulseFraction(); void Remove(); + SColor GetTargetArrowColor() const noexcept override { return m_targetArrowColor; }; + float GetTargetArrowSize() const noexcept override { return m_targetArrowSize; }; + void SetTargetArrowData(const SColor color, float size) noexcept; }; diff --git a/Client/game_sa/CCheckpointsSA.cpp b/Client/game_sa/CCheckpointsSA.cpp index e0f83f5de5..593d295340 100644 --- a/Client/game_sa/CCheckpointsSA.cpp +++ b/Client/game_sa/CCheckpointsSA.cpp @@ -66,3 +66,14 @@ CCheckpoint* CCheckpointsSA::FindFreeMarker() } return NULL; } + +CCheckpoint* CCheckpointsSA::FindMarker(DWORD identifier) +{ + for (CCheckpointSA* checkpoint : Checkpoints) + { + if (checkpoint->GetIdentifier() == identifier) + return checkpoint; + } + + return nullptr; +} diff --git a/Client/game_sa/CCheckpointsSA.h b/Client/game_sa/CCheckpointsSA.h index 151af329ab..c29c21f6af 100644 --- a/Client/game_sa/CCheckpointsSA.h +++ b/Client/game_sa/CCheckpointsSA.h @@ -35,4 +35,5 @@ class CCheckpointsSA : public CCheckpoints CCheckpoint* CreateCheckpoint(DWORD Identifier, WORD wType, CVector* vecPosition, CVector* vecPointDir, float fSize, float fPulseFraction, const SharedUtil::SColor color); CCheckpoint* FindFreeMarker(); + CCheckpoint* FindMarker(DWORD identifier); }; diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 4a7324fa48..abfb822816 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -58,6 +58,7 @@ #include "D3DResourceSystemSA.h" #include "CIplStoreSA.h" #include "CBuildingRemovalSA.h" +#include "CCheckpointSA.h" extern CGameSA* pGame; @@ -238,6 +239,7 @@ CGameSA::CGameSA() CFileLoaderSA::StaticSetHooks(); D3DResourceSystemSA::StaticSetHooks(); CVehicleSA::StaticSetHooks(); + CCheckpointSA::StaticSetHooks(); } CGameSA::~CGameSA() diff --git a/Client/mods/deathmatch/logic/CClientCheckpoint.cpp b/Client/mods/deathmatch/logic/CClientCheckpoint.cpp index 4ab0a9bdc9..1d4702c46d 100644 --- a/Client/mods/deathmatch/logic/CClientCheckpoint.cpp +++ b/Client/mods/deathmatch/logic/CClientCheckpoint.cpp @@ -27,6 +27,8 @@ CClientCheckpoint::CClientCheckpoint(CClientMarker* pThis) m_dwType = CHECKPOINT_EMPTYTUBE; m_vecDirection.fX = 1.0f; m_bHasTarget = false; + m_TargetArrowColor = SColorRGBA(255, 64, 64, 255); + m_TargetArrowSize = m_fSize * 0.625f; } CClientCheckpoint::~CClientCheckpoint() @@ -261,6 +263,8 @@ void CClientCheckpoint::SetSize(float fSize) { // Set the new size and recreate m_fSize = fSize; + m_TargetArrowSize = fSize * 0.625f; + ReCreate(); } } @@ -352,6 +356,7 @@ void CClientCheckpoint::Create(unsigned long ulIdentifier) { // Set properties m_pCheckpoint->SetRotateRate(0); + ApplyCheckpointTargetArrowProperties(); } } } @@ -385,3 +390,20 @@ void CClientCheckpoint::ReCreateWithSameIdentifier() Create(m_dwIdentifier); } } + +void CClientCheckpoint::SetTargetArrowProperties(const SColor& arrowColor, float size) noexcept +{ + if (m_TargetArrowColor == arrowColor && m_TargetArrowSize == size) + return; + + m_TargetArrowColor = arrowColor; + m_TargetArrowSize = size; + + ApplyCheckpointTargetArrowProperties(); +} + +void CClientCheckpoint::ApplyCheckpointTargetArrowProperties() noexcept +{ + if (m_pCheckpoint && m_uiIcon == CClientCheckpoint::ICON_ARROW) + m_pCheckpoint->SetTargetArrowData(m_TargetArrowColor, m_TargetArrowSize); +} diff --git a/Client/mods/deathmatch/logic/CClientCheckpoint.h b/Client/mods/deathmatch/logic/CClientCheckpoint.h index adafcdf39d..bdb786f511 100644 --- a/Client/mods/deathmatch/logic/CClientCheckpoint.h +++ b/Client/mods/deathmatch/logic/CClientCheckpoint.h @@ -74,6 +74,10 @@ class CClientCheckpoint : public CClientMarkerCommon static bool IconToString(unsigned char ucIcon, SString& strOutString); void ReCreateWithSameIdentifier(); + SColor GetTargetArrowColor() const noexcept { return m_TargetArrowColor; }; + float GetTargetArrowSize() const noexcept { return m_TargetArrowSize; }; + void SetTargetArrowProperties(const SColor& arrowColor, float size) noexcept; + protected: bool IsStreamedIn() { return m_bStreamedIn; }; void StreamIn(); @@ -83,6 +87,7 @@ class CClientCheckpoint : public CClientMarkerCommon void Create(unsigned long ulIdentifier = 0); void Destroy(); void ReCreate(); + void ApplyCheckpointTargetArrowProperties() noexcept; CClientMarkerPtr m_pThis; bool m_bStreamedIn; @@ -95,6 +100,8 @@ class CClientCheckpoint : public CClientMarkerCommon float m_fSize; SColor m_Color; CCheckpoint* m_pCheckpoint; + SColor m_TargetArrowColor; + float m_TargetArrowSize; DWORD m_dwIdentifier; bool m_bHasTarget; diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index af4d8df6f4..af83cb1b72 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -3654,6 +3654,19 @@ void CPacketHandler::Packet_EntityAdd(NetBitStreamInterface& bitStream) pCheckpoint->SetNextPosition(position.data.vecPosition); pCheckpoint->SetIcon(CClientCheckpoint::ICON_ARROW); } + + if (ucType == CClientGame::MARKER_CHECKPOINT && bitStream.Can(eBitStreamVersion::SetMarkerTargetArrowProperties)) + { + SColor color; + float size; + bitStream.Read(color.R); + bitStream.Read(color.G); + bitStream.Read(color.B); + bitStream.Read(color.A); + bitStream.Read(size); + + pCheckpoint->SetTargetArrowProperties(color, size); + } } } } diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 8ad0d5288e..9f81461c2c 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -4926,6 +4926,25 @@ bool CStaticFunctionDefinitions::SetMarkerIcon(CClientEntity& Entity, const char return false; } +bool CStaticFunctionDefinitions::SetMarkerTargetArrowProperties(CClientEntity& Entity, const SColor color, float size) +{ + RUN_CHILDREN(SetMarkerTargetArrowProperties(**iter, color, size)) + + if (!IS_MARKER(&Entity)) + return false; + + CClientMarker& marker = static_cast(Entity); + CClientCheckpoint* checkpoint = marker.GetCheckpoint(); + if (!checkpoint) + return false; + + if (checkpoint->GetIcon() != CClientCheckpoint::ICON_ARROW) + return false; + + checkpoint->SetTargetArrowProperties(color, size); + return true; +} + bool CStaticFunctionDefinitions::GetCameraMatrix(CVector& vecPosition, CVector& vecLookAt, float& fRoll, float& fFOV) { m_pCamera->GetPosition(vecPosition); diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 2ffe1ff0a5..e3a887fc46 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -377,6 +377,7 @@ class CStaticFunctionDefinitions static bool SetMarkerColor(CClientEntity& Entity, const SColor color); static bool SetMarkerTarget(CClientEntity& Entity, const CVector* pTarget); static bool SetMarkerIcon(CClientEntity& Entity, const char* szIcon); + static bool SetMarkerTargetArrowProperties(CClientEntity& Entity, const SColor color, float size); // Camera get funcs static bool GetCameraMatrix(CVector& vecPosition, CVector& vecLookAt, float& fRoll, float& fFOV); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.cpp index 071cad3870..2626280c4b 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.cpp @@ -23,12 +23,14 @@ void CLuaMarkerDefs::LoadFunctions() {"getMarkerColor", GetMarkerColor}, {"getMarkerTarget", GetMarkerTarget}, {"getMarkerIcon", GetMarkerIcon}, + {"getMarkerTargetArrowProperties", ArgumentParser}, {"setMarkerType", SetMarkerType}, {"setMarkerSize", SetMarkerSize}, {"setMarkerColor", SetMarkerColor}, {"setMarkerTarget", SetMarkerTarget}, {"setMarkerIcon", SetMarkerIcon}, + {"setMarkerTargetArrowProperties", ArgumentParser}, {"setCoronaReflectionEnabled", ArgumentParser}, {"isCoronaReflectionEnabled", ArgumentParser}, @@ -417,3 +419,27 @@ bool CLuaMarkerDefs::IsCoronaReflectionEnabled(CClientMarker* pMarker) return pCorona->IsReflectionEnabled(); } + +bool CLuaMarkerDefs::SetMarkerTargetArrowProperties(CClientMarker* marker, std::optional r, std::optional g, std::optional b, std::optional a, std::optional size) +{ + SColor color; + color.R = r.value_or(255); + color.G = g.value_or(64); + color.B = b.value_or(64); + color.A = a.value_or(255); + + return CStaticFunctionDefinitions::SetMarkerTargetArrowProperties(*marker, color, size.value_or(marker->GetSize() * 0.625f)); +} + +std::variant, bool> CLuaMarkerDefs::GetMarkerTargetArrowProperties(CClientMarker* marker) noexcept +{ + CClientCheckpoint* checkpoint = marker->GetCheckpoint(); + if (!checkpoint) + return false; + + if (!checkpoint->HasTarget() || marker->GetMarkerType() != CClientMarker::MARKER_CHECKPOINT) + return false; + + SColor color = checkpoint->GetTargetArrowColor(); + return CLuaMultiReturn(color.R, color.G, color.B, color.A, checkpoint->GetTargetArrowSize()); +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.h index 6f0c1c0abb..3e351490b5 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.h @@ -11,6 +11,7 @@ #pragma once #include "CLuaDefs.h" +#include "lua/CLuaMultiReturn.h" class CLuaMarkerDefs : public CLuaDefs { @@ -35,4 +36,7 @@ class CLuaMarkerDefs : public CLuaDefs static bool SetCoronaReflectionEnabled(CClientMarker* pMarker, bool bEnabled); static bool IsCoronaReflectionEnabled(CClientMarker* pMarker); + + static bool SetMarkerTargetArrowProperties(CClientMarker* marker, std::optional r, std::optional g, std::optional b, std::optional a, std::optional size); + static std::variant, bool> GetMarkerTargetArrowProperties(CClientMarker* marker) noexcept; }; diff --git a/Client/mods/deathmatch/logic/rpc/CMarkerRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CMarkerRPCs.cpp index 25fef9a579..ab7ca26af0 100644 --- a/Client/mods/deathmatch/logic/rpc/CMarkerRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CMarkerRPCs.cpp @@ -19,6 +19,7 @@ void CMarkerRPCs::LoadFunctions() AddHandler(SET_MARKER_SIZE, SetMarkerSize, "SetMarkerSize"); AddHandler(SET_MARKER_TARGET, SetMarkerTarget, "SetMarkerTarget"); AddHandler(SET_MARKER_ICON, SetMarkerIcon, "SetMarkerIcon"); + AddHandler(SET_MARKER_TARGET_ARROW_PROPERTIES, SetMarkerTargetArrowProperties, "SetMarkerTargetArrowProperties"); } void CMarkerRPCs::SetMarkerType(CClientEntity* pSource, NetBitStreamInterface& bitStream) @@ -137,4 +138,22 @@ void CMarkerRPCs::SetMarkerIcon(CClientEntity* pSource, NetBitStreamInterface& b } } } -} \ No newline at end of file +} + +void CMarkerRPCs::SetMarkerTargetArrowProperties(CClientEntity* pSource, NetBitStreamInterface& bitStream) +{ + SColor color; + float size; + if (bitStream.Read(color.R) && bitStream.Read(color.G) && bitStream.Read(color.B) && bitStream.Read(color.A) && bitStream.Read(size)) + { + CClientMarker* marker = m_pMarkerManager->Get(pSource->GetID()); + if (!marker) + return; + + CClientCheckpoint* checkpoint = marker->GetCheckpoint(); + if (!checkpoint) + return; + + checkpoint->SetTargetArrowProperties(color, size); + } +} diff --git a/Client/mods/deathmatch/logic/rpc/CMarkerRPCs.h b/Client/mods/deathmatch/logic/rpc/CMarkerRPCs.h index ae4f27c41c..20dcceff15 100644 --- a/Client/mods/deathmatch/logic/rpc/CMarkerRPCs.h +++ b/Client/mods/deathmatch/logic/rpc/CMarkerRPCs.h @@ -23,4 +23,5 @@ class CMarkerRPCs : public CRPCFunctions DECLARE_ELEMENT_RPC(SetMarkerSize); DECLARE_ELEMENT_RPC(SetMarkerTarget); DECLARE_ELEMENT_RPC(SetMarkerIcon); + DECLARE_ELEMENT_RPC(SetMarkerTargetArrowProperties); }; diff --git a/Client/sdk/game/CCheckpoint.h b/Client/sdk/game/CCheckpoint.h index 66e5e0c371..ce17f92267 100644 --- a/Client/sdk/game/CCheckpoint.h +++ b/Client/sdk/game/CCheckpoint.h @@ -52,4 +52,7 @@ class CCheckpoint virtual void SetCameraRange(float fCameraRange) = 0; virtual float GetPulseFraction() = 0; virtual void Remove() = 0; + virtual SColor GetTargetArrowColor() const noexcept = 0; + virtual float GetTargetArrowSize() const noexcept = 0; + virtual void SetTargetArrowData(const SColor arrowColo, float size) noexcept = 0; }; diff --git a/Client/sdk/game/CCheckpoints.h b/Client/sdk/game/CCheckpoints.h index 7917827339..be9c803a40 100644 --- a/Client/sdk/game/CCheckpoints.h +++ b/Client/sdk/game/CCheckpoints.h @@ -20,4 +20,5 @@ class CCheckpoints virtual CCheckpoint* CreateCheckpoint(DWORD Identifier, WORD wType, CVector* vecPosition, CVector* vecPointDir, float fSize, float fPulseFraction, const SharedUtil::SColor color) = 0; virtual CCheckpoint* FindFreeMarker() = 0; + virtual CCheckpoint* FindMarker(DWORD identifier) = 0; }; diff --git a/Server/mods/deathmatch/logic/CMarker.cpp b/Server/mods/deathmatch/logic/CMarker.cpp index 0fc93ba76f..3000220e4f 100644 --- a/Server/mods/deathmatch/logic/CMarker.cpp +++ b/Server/mods/deathmatch/logic/CMarker.cpp @@ -33,6 +33,8 @@ CMarker::CMarker(CMarkerManager* pMarkerManager, CColManager* pColManager, CElem m_Color = SColorRGBA(255, 255, 255, 255); m_bHasTarget = false; m_ucIcon = ICON_NONE; + m_TargetArrowColor = SColorRGBA(255, 64, 64, 255); + m_TargetArrowSize = m_fSize * 0.625f; // Create our collision object m_pCollision = new CColCircle(pColManager, nullptr, m_vecPosition, m_fSize, true); @@ -261,6 +263,8 @@ void CMarker::SetSize(float fSize) { // Set the new size and update the col object m_fSize = fSize; + m_TargetArrowSize = fSize * 0.625f; + UpdateCollisionObject(m_ucType); // Tell all players @@ -301,6 +305,23 @@ void CMarker::SetIcon(unsigned char ucIcon) } } +void CMarker::SetTargetArrowProperties(const SColor color, float size) noexcept +{ + if (m_TargetArrowColor == color && m_TargetArrowSize == size) + return; + + m_TargetArrowColor = color; + m_TargetArrowSize = size; + + CBitStream BitStream; + BitStream.pBitStream->Write(color.R); + BitStream.pBitStream->Write(color.G); + BitStream.pBitStream->Write(color.B); + BitStream.pBitStream->Write(color.A); + BitStream.pBitStream->Write(size); + BroadcastOnlyVisible(CElementRPCPacket(this, SET_MARKER_TARGET_ARROW_PROPERTIES, *BitStream.pBitStream)); +} + void CMarker::Callback_OnCollision(CColShape& Shape, CElement& Element) { // Do not call on ourselves #7359 diff --git a/Server/mods/deathmatch/logic/CMarker.h b/Server/mods/deathmatch/logic/CMarker.h index 345ed39a47..f89c6154b2 100644 --- a/Server/mods/deathmatch/logic/CMarker.h +++ b/Server/mods/deathmatch/logic/CMarker.h @@ -67,6 +67,10 @@ class CMarker : public CPerPlayerEntity, private CColCallback virtual CSphere GetWorldBoundingSphere(); + SColor GetTargetArrowColor() const noexcept { return m_TargetArrowColor; }; + float GetTargetArrowSize() const noexcept { return m_TargetArrowSize; }; + void SetTargetArrowProperties(const SColor color, float size) noexcept; + protected: bool ReadSpecialData(const int iLine) override; @@ -85,6 +89,8 @@ class CMarker : public CPerPlayerEntity, private CColCallback float m_fSize; SColor m_Color; unsigned char m_ucIcon; + SColor m_TargetArrowColor; + float m_TargetArrowSize; CColShape* m_pCollision; }; diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index c7e9c61131..5bc5250102 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -7854,6 +7854,24 @@ bool CStaticFunctionDefinitions::SetMarkerIcon(CElement* pElement, const char* s return false; } +bool CStaticFunctionDefinitions::SetMarkerTargetArrowProperties(CElement* pElement, const SColor color, float size) +{ + RUN_CHILDREN(SetMarkerTargetArrowProperties(*iter, color, size)) + + if (!IS_MARKER(pElement)) + return false; + + CMarker* marker = static_cast(pElement); + if (!marker) + return false; + + if (!marker->HasTarget() || marker->GetMarkerType() != CMarker::TYPE_CHECKPOINT) + return false; + + marker->SetTargetArrowProperties(color, size); + return true; +} + CBlip* CStaticFunctionDefinitions::CreateBlip(CResource* pResource, const CVector& vecPosition, unsigned char ucIcon, unsigned char ucSize, const SColor color, short sOrdering, unsigned short usVisibleDistance, CElement* pVisibleTo) { diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h index db6fb1874e..9c79a844e6 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -385,6 +385,8 @@ class CStaticFunctionDefinitions static bool SetMarkerTarget(CElement* pElement, const CVector* pTarget); static bool SetMarkerIcon(CElement* pElement, const char* szIcon); + static bool SetMarkerTargetArrowProperties(CElement* Element, const SColor color, float size); + // Blip create/destroy functions static CBlip* CreateBlip(CResource* pResource, const CVector& vecPosition, unsigned char ucIcon, unsigned char ucSize, const SColor color, short sOrdering, unsigned short usVisibleDistance, CElement* pVisibleTo); diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.cpp index 001bc40b66..89ebde311c 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.cpp @@ -12,6 +12,7 @@ #include "CLuaMarkerDefs.h" #include "CStaticFunctionDefinitions.h" #include "CScriptArgReader.h" +#include "lua/CLuaFunctionParser.h" void CLuaMarkerDefs::LoadFunctions() { @@ -26,6 +27,7 @@ void CLuaMarkerDefs::LoadFunctions() {"getMarkerColor", GetMarkerColor}, {"getMarkerTarget", GetMarkerTarget}, {"getMarkerIcon", GetMarkerIcon}, + {"getMarkerTargetArrowProperties", ArgumentParser}, // Marker set functions {"setMarkerType", SetMarkerType}, @@ -33,6 +35,7 @@ void CLuaMarkerDefs::LoadFunctions() {"setMarkerColor", SetMarkerColor}, {"setMarkerTarget", SetMarkerTarget}, {"setMarkerIcon", SetMarkerIcon}, + {"setMarkerTargetArrowProperties", ArgumentParser}, }; // Add functions @@ -410,3 +413,23 @@ int CLuaMarkerDefs::SetMarkerIcon(lua_State* luaVM) lua_pushboolean(luaVM, false); return 1; } + +bool CLuaMarkerDefs::SetMarkerTargetArrowProperties(CMarker* marker, std::optional r, std::optional g, std::optional b, std::optional a, std::optional size) +{ + SColor color; + color.R = r.value_or(255); + color.G = g.value_or(64); + color.B = b.value_or(64); + color.A = a.value_or(255); + + return CStaticFunctionDefinitions::SetMarkerTargetArrowProperties(marker, color, size.value_or(marker->GetSize() * 0.625f)); +} + +std::variant, bool> CLuaMarkerDefs::GetMarkerTargetArrowProperties(CMarker* marker) noexcept +{ + if (!marker->HasTarget() || marker->GetMarkerType() != CMarker::TYPE_CHECKPOINT) + return false; + + SColor color = marker->GetTargetArrowColor(); + return CLuaMultiReturn(color.R, color.G, color.B, color.A, marker->GetTargetArrowSize()); +} diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.h b/Server/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.h index 28e84e5ff5..b73d720184 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.h +++ b/Server/mods/deathmatch/logic/luadefs/CLuaMarkerDefs.h @@ -11,6 +11,7 @@ #pragma once #include "CLuaDefs.h" +#include "lua/CLuaMultiReturn.h" class CLuaMarkerDefs : public CLuaDefs { @@ -35,4 +36,6 @@ class CLuaMarkerDefs : public CLuaDefs LUA_DECLARE(SetMarkerColor); LUA_DECLARE(SetMarkerTarget); LUA_DECLARE(SetMarkerIcon); + static bool SetMarkerTargetArrowProperties(CMarker* marker, std::optional r, std::optional g, std::optional b, std::optional a, std::optional size); + static std::variant, bool> GetMarkerTargetArrowProperties(CMarker* marker) noexcept; }; diff --git a/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp b/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp index ff56896864..0ecf66bfc4 100644 --- a/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CEntityAddPacket.cpp @@ -728,6 +728,17 @@ bool CEntityAddPacket::Write(NetBitStreamInterface& BitStream) const position.data.vecPosition = pMarker->GetTarget(); BitStream.Write(&position); + + if (markerType.data.ucType == CMarker::TYPE_CHECKPOINT && BitStream.Can(eBitStreamVersion::SetMarkerTargetArrowProperties)) + { + SColor color = pMarker->GetTargetArrowColor(); + + BitStream.Write(color.R); + BitStream.Write(color.G); + BitStream.Write(color.B); + BitStream.Write(color.A); + BitStream.Write(pMarker->GetTargetArrowSize()); + } } else BitStream.WriteBit(false); diff --git a/Shared/sdk/net/bitstream.h b/Shared/sdk/net/bitstream.h index e0de0f9172..084ef5dd98 100644 --- a/Shared/sdk/net/bitstream.h +++ b/Shared/sdk/net/bitstream.h @@ -560,6 +560,9 @@ enum class eBitStreamVersion : unsigned short // 2024-06-30 WorldSpecialProperty_TunnelWeatherBlend, + // Add "setMarkerTargetArrowProperties" + // 2024-07-05 + SetMarkerTargetArrowProperties, // This allows us to automatically increment the BitStreamVersion when things are added to this enum. // Make sure you only add things above this comment. diff --git a/Shared/sdk/net/rpc_enums.h b/Shared/sdk/net/rpc_enums.h index e7cb590763..ba27c58bfa 100644 --- a/Shared/sdk/net/rpc_enums.h +++ b/Shared/sdk/net/rpc_enums.h @@ -127,6 +127,7 @@ enum eElementRPCFunctions SET_MARKER_SIZE, SET_MARKER_TARGET, SET_MARKER_ICON, + SET_MARKER_TARGET_ARROW_PROPERTIES, DESTROY_ALL_PICKUPS, SET_PICKUP_TYPE,