diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 49343f0c9e..d83e619a2f 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -138,6 +138,26 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) m_Glitches[GLITCH_QUICKSTAND] = false; m_Glitches[GLITCH_KICKOUTOFVEHICLE_ONMODELREPLACE] = false; m_Glitches[GLITCH_VEHICLE_RAPID_STOP] = false; + + + for (int i = 0; i < NUM_GLITCHES; i++) + { + m_PlayerGlitches[i] = false; + m_bHasPlayerGlitchOverride[i] = false; + } + + + m_GlitchNames["quickreload"] = GLITCH_QUICKRELOAD; + m_GlitchNames["fastfire"] = GLITCH_FASTFIRE; + m_GlitchNames["fastmove"] = GLITCH_FASTMOVE; + m_GlitchNames["crouchbug"] = GLITCH_CROUCHBUG; + m_GlitchNames["highcloserangedamage"] = GLITCH_CLOSEDAMAGE; + m_GlitchNames["hitanim"] = GLITCH_HITANIM; + m_GlitchNames["fastsprint"] = GLITCH_FASTSPRINT; + m_GlitchNames["baddrivebyhitbox"] = GLITCH_BADDRIVEBYHITBOX; + m_GlitchNames["quickstand"] = GLITCH_QUICKSTAND; + m_GlitchNames["kickoutofvehicle_onmodelreplace"] = GLITCH_KICKOUTOFVEHICLE_ONMODELREPLACE; + m_GlitchNames["vehicle_rapid_stop"] = GLITCH_VEHICLE_RAPID_STOP; g_pMultiplayer->SetRapidVehicleStopFixEnabled(true); g_pMultiplayer->DisableBadDrivebyHitboxes(true); @@ -5992,12 +6012,9 @@ bool CClientGame::SetGlitchEnabled(unsigned char ucGlitch, bool bEnabled) if (ucGlitch < NUM_GLITCHES && bEnabled != m_Glitches[ucGlitch]) { m_Glitches[ucGlitch] = bEnabled; - if (ucGlitch == GLITCH_QUICKRELOAD) - g_pMultiplayer->DisableQuickReload(!bEnabled); - if (ucGlitch == GLITCH_CLOSEDAMAGE) - g_pMultiplayer->DisableCloseRangeDamage(!bEnabled); - if (ucGlitch == GLITCH_VEHICLE_RAPID_STOP) - g_pMultiplayer->SetRapidVehicleStopFixEnabled(!bEnabled); + + // Calculate and apply effective state + ApplyEffectiveGlitchState(ucGlitch); return true; } return false; @@ -6008,6 +6025,83 @@ bool CClientGame::IsGlitchEnabled(unsigned char ucGlitch) return ucGlitch < NUM_GLITCHES && m_Glitches[ucGlitch]; } +bool CClientGame::RequestPlayerGlitchEnabled(const std::string& strGlitchName, bool bEnabled) +{ + // Find the glitch index for validation + auto it = m_GlitchNames.find(strGlitchName); + if (it == m_GlitchNames.end()) + return false; + + unsigned char ucGlitch = it->second; + if (ucGlitch >= NUM_GLITCHES) + return false; + + // Send request to server (don't apply locally yet) + if (auto stream = g_pNet->AllocateNetBitStream()) + { + stream->Write(strGlitchName); + stream->WriteBit(bEnabled); + g_pNet->SendPacket(PACKET_ID_PLAYER_GLITCH_REQUEST, stream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); + g_pNet->DeallocateNetBitStream(stream); + } + + return true; +} + +bool CClientGame::SetPlayerGlitchEnabled(const std::string& strGlitchName, bool bEnabled) +{ + auto it = m_GlitchNames.find(strGlitchName); + if (it == m_GlitchNames.end()) + return false; + + unsigned char ucGlitch = it->second; + if (ucGlitch >= NUM_GLITCHES) + return false; + + // Check if state is actually changing + if (m_bHasPlayerGlitchOverride[ucGlitch] && m_PlayerGlitches[ucGlitch] == bEnabled) + return true; + + // Set per-player override + m_PlayerGlitches[ucGlitch] = bEnabled; + m_bHasPlayerGlitchOverride[ucGlitch] = true; + + // Apply effective state to game engine + ApplyEffectiveGlitchState(ucGlitch); + return true; +} + +bool CClientGame::IsPlayerGlitchEnabled(const std::string& strGlitchName) +{ + auto it = m_GlitchNames.find(strGlitchName); + if (it == m_GlitchNames.end()) + return false; + + unsigned char ucGlitch = it->second; + if (ucGlitch >= NUM_GLITCHES) + return false; + + if (m_bHasPlayerGlitchOverride[ucGlitch]) + return m_PlayerGlitches[ucGlitch]; + + return m_Glitches[ucGlitch]; +} + +void CClientGame::ApplyEffectiveGlitchState(unsigned char ucGlitch) +{ + if (ucGlitch >= NUM_GLITCHES) + return; + + bool bEffectiveState = m_bHasPlayerGlitchOverride[ucGlitch] ? m_PlayerGlitches[ucGlitch] : m_Glitches[ucGlitch]; + + if (ucGlitch == GLITCH_QUICKRELOAD) + g_pMultiplayer->DisableQuickReload(!bEffectiveState); + else if (ucGlitch == GLITCH_CLOSEDAMAGE) + g_pMultiplayer->DisableCloseRangeDamage(!bEffectiveState); + else if (ucGlitch == GLITCH_VEHICLE_RAPID_STOP) + g_pMultiplayer->SetRapidVehicleStopFixEnabled(!bEffectiveState); +} + bool CClientGame::SetWorldSpecialProperty(const WorldSpecialProperty property, const bool enabled) noexcept { switch (property) diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index 0c33091763..4a4148a29a 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -416,6 +416,15 @@ class CClientGame bool SetGlitchEnabled(unsigned char cGlitch, bool bEnabled); bool IsGlitchEnabled(unsigned char cGlitch); + bool RequestPlayerGlitchEnabled(const std::string& strGlitchName, bool bEnabled); + bool SetPlayerGlitchEnabled(const std::string& strGlitchName, bool bEnabled); + bool IsPlayerGlitchEnabled(const std::string& strGlitchName); + +private: + void ApplyEffectiveGlitchState(unsigned char ucGlitch); + +public: + bool SetWorldSpecialProperty(const WorldSpecialProperty property, const bool enabled) noexcept; bool IsWorldSpecialProperty(const WorldSpecialProperty property); @@ -783,6 +792,9 @@ class CClientGame DWORD m_dwWanted; SFixedArray m_Glitches; + SFixedArray m_PlayerGlitches; + SFixedArray m_bHasPlayerGlitchOverride; + std::map m_GlitchNames; // Clouds Enabled bool m_bCloudsEnabled; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaWorldDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaWorldDefs.cpp index caa53e4c67..8d09c70ba1 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaWorldDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaWorldDefs.cpp @@ -149,7 +149,11 @@ void CLuaWorldDefs::LoadFunctions() {"isTimeFrozen", ArgumentParser}, {"isVolumetricShadowsEnabled", ArgumentParser}, {"isDynamicPedShadowsEnabled", ArgumentParser}, - {"testSphereAgainstWorld", ArgumentParser}}; + {"testSphereAgainstWorld", ArgumentParser}, + + // Per-player glitch functions + {"setPlayerGlitchEnabled", SetPlayerGlitchEnabled}, + {"isPlayerGlitchEnabled", IsPlayerGlitchEnabled}}; // Add functions for (const auto& [name, func] : functions) @@ -2352,3 +2356,50 @@ CLuaMultiReturnRequestPlayerGlitchEnabled(strGlitch, bEnabled)) + { + lua_pushboolean(luaVM, true); + return 1; + } + } + else + m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); + + lua_pushboolean(luaVM, false); + return 1; +} + +int CLuaWorldDefs::IsPlayerGlitchEnabled(lua_State* luaVM) +{ + // bool isPlayerGlitchEnabled ( string glitchName ) + SString strGlitch; + + CScriptArgReader argStream(luaVM); + argStream.ReadString(strGlitch); + + if (!argStream.HasErrors()) + { + bool bEnabled = g_pClientGame->IsPlayerGlitchEnabled(strGlitch); + lua_pushboolean(luaVM, bEnabled); + return 1; + } + else + m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); + + lua_pushboolean(luaVM, false); + return 1; +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaWorldDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaWorldDefs.h index 5668ca6dd4..90379e48ed 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaWorldDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaWorldDefs.h @@ -149,4 +149,8 @@ class CLuaWorldDefs : public CLuaDefs static void RemoveGameWorld(); static void RestoreGameWorld(); + + + LUA_DECLARE(SetPlayerGlitchEnabled); + LUA_DECLARE(IsPlayerGlitchEnabled); }; diff --git a/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp index 65b1fe589a..56b7f5eb49 100644 --- a/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp @@ -39,6 +39,7 @@ void CWorldRPCs::LoadFunctions() AddHandler(SET_FPS_LIMIT, SetFPSLimit, "SetFPSLimit"); AddHandler(SET_GARAGE_OPEN, SetGarageOpen, "SetGarageOpen"); AddHandler(SET_GLITCH_ENABLED, SetGlitchEnabled, "SetGlitchEnabled"); + AddHandler(SET_PLAYER_GLITCH_ENABLED, SetPlayerGlitchEnabled, "SetPlayerGlitchEnabled"); AddHandler(SET_JETPACK_WEAPON_ENABLED, SetJetpackWeaponEnabled, "SetJetpackWeaponEnabled"); AddHandler(SET_CLOUDS_ENABLED, SetCloudsEnabled, "SetCloudsEnabled"); AddHandler(SET_TRAFFIC_LIGHT_STATE, SetTrafficLightState, "SetTrafficLightState"); @@ -241,6 +242,17 @@ void CWorldRPCs::SetGlitchEnabled(NetBitStreamInterface& bitStream) g_pClientGame->SetGlitchEnabled(eGlitch, (ucIsEnabled == 1)); } +void CWorldRPCs::SetPlayerGlitchEnabled(NetBitStreamInterface& bitStream) +{ + SString strGlitchName; + bool bEnabled; + + if (bitStream.Read(strGlitchName) && bitStream.ReadBit(bEnabled)) + { + g_pClientGame->SetPlayerGlitchEnabled(strGlitchName, bEnabled); + } +} + void CWorldRPCs::SetJetpackWeaponEnabled(NetBitStreamInterface& bitStream) { unsigned char ucWeaponID = 0; diff --git a/Client/mods/deathmatch/logic/rpc/CWorldRPCs.h b/Client/mods/deathmatch/logic/rpc/CWorldRPCs.h index 5c5c4514f1..f9913865d5 100644 --- a/Client/mods/deathmatch/logic/rpc/CWorldRPCs.h +++ b/Client/mods/deathmatch/logic/rpc/CWorldRPCs.h @@ -37,6 +37,7 @@ class CWorldRPCs : public CRPCFunctions DECLARE_RPC(SetFPSLimit); DECLARE_RPC(SetGarageOpen); DECLARE_RPC(SetGlitchEnabled); + DECLARE_RPC(SetPlayerGlitchEnabled); DECLARE_RPC(SetJetpackWeaponEnabled); DECLARE_RPC(SetCloudsEnabled); DECLARE_RPC(SetTrafficLightState); diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 486ea42963..c4856cc95b 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -59,6 +59,7 @@ #include "packets/CPlayerListPacket.h" #include "packets/CPlayerClothesPacket.h" #include "packets/CPlayerWorldSpecialPropertyPacket.h" +#include "packets/CPlayerGlitchRequestPacket.h" #include "packets/CServerInfoSyncPacket.h" #include "packets/CLuaPacket.h" #include "../utils/COpenPortsTester.h" @@ -1328,6 +1329,12 @@ bool CGame::ProcessPacket(CPacket& Packet) return true; } + case PACKET_ID_PLAYER_GLITCH_REQUEST: + { + Packet_PlayerGlitchRequest(static_cast(Packet)); + return true; + } + default: break; } @@ -1480,6 +1487,12 @@ void CGame::InitialDataStream(CPlayer& Player) CLuaArguments Arguments; Player.CallEvent("onPlayerJoin", Arguments); + // Send the joining player's own glitch states (if any were set before joining) + if (Player.IsJoined()) + { + Player.SendAllPlayerGlitchStates(); + } + marker.Set("onPlayerJoin"); // Register them on the lightweight sync manager. @@ -4186,6 +4199,33 @@ void CGame::Packet_PlayerWorldSpecialProperty(CPlayerWorldSpecialPropertyPacket& player->CallEvent("onPlayerChangesWorldSpecialProperty", arguments, nullptr); } +void CGame::Packet_PlayerGlitchRequest(CPlayerGlitchRequestPacket& packet) noexcept +{ + CPlayer* pPlayer = packet.GetSourcePlayer(); + if (!pPlayer) + return; + + const std::string& strGlitchName = packet.GetGlitchName(); + const bool bEnabled = packet.IsEnabled(); + + + if (!IsGlitch(strGlitchName)) + return; + + + if (pPlayer->SetPlayerGlitchEnabled(strGlitchName, bEnabled)) + { + + pPlayer->SendPlayerGlitchState(strGlitchName); + + + CLuaArguments arguments; + arguments.PushString(strGlitchName); + arguments.PushBoolean(bEnabled); + pPlayer->CallEvent("onPlayerGlitchStateChange", arguments, nullptr); + } +} + void CGame::Packet_PlayerModInfo(CPlayerModInfoPacket& Packet) { CPlayer* pPlayer = Packet.GetSourcePlayer(); diff --git a/Server/mods/deathmatch/logic/CGame.h b/Server/mods/deathmatch/logic/CGame.h index af491039d0..03c8ab306d 100644 --- a/Server/mods/deathmatch/logic/CGame.h +++ b/Server/mods/deathmatch/logic/CGame.h @@ -430,6 +430,7 @@ class CGame bool IsGlitchEnabled(eGlitchType cGlitch); eGlitchType GetGlitchIndex(const std::string& strGlitch) { return m_GlitchNames[strGlitch]; } bool IsGlitch(const std::string& strGlitch) { return m_GlitchNames.count(strGlitch) > 0; } + const std::map& GetGlitchNames() const { return m_GlitchNames; } bool IsWorldSpecialPropertyEnabled(WorldSpecialProperty property) { return m_WorldSpecialProps[property]; } void SetWorldSpecialPropertyEnabled(WorldSpecialProperty property, bool isEnabled) { m_WorldSpecialProps[property] = isEnabled; } @@ -523,6 +524,7 @@ class CGame void Packet_PlayerNetworkStatus(class CPlayerNetworkStatusPacket& Packet); void Packet_PlayerResourceStart(class CPlayerResourceStartPacket& Packet); void Packet_PlayerWorldSpecialProperty(class CPlayerWorldSpecialPropertyPacket& packet) noexcept; + void Packet_PlayerGlitchRequest(class CPlayerGlitchRequestPacket& packet) noexcept; static void PlayerCompleteConnect(CPlayer* pPlayer); diff --git a/Server/mods/deathmatch/logic/CPacketTranslator.cpp b/Server/mods/deathmatch/logic/CPacketTranslator.cpp index 2d12509c50..eba9b5e460 100644 --- a/Server/mods/deathmatch/logic/CPacketTranslator.cpp +++ b/Server/mods/deathmatch/logic/CPacketTranslator.cpp @@ -49,6 +49,7 @@ #include "packets/CPlayerNetworkStatusPacket.h" #include "packets/CPlayerResourceStartPacket.h" #include "packets/CPlayerWorldSpecialPropertyPacket.h" +#include "packets/CPlayerGlitchRequestPacket.h" CPacketTranslator::CPacketTranslator(CPlayerManager* pPlayerManager) { @@ -217,6 +218,10 @@ CPacket* CPacketTranslator::Translate(const NetServerPlayerID& Socket, ePacketID pTemp = new CPlayerWorldSpecialPropertyPacket; break; + case PACKET_ID_PLAYER_GLITCH_REQUEST: + pTemp = new CPlayerGlitchRequestPacket; + break; + default: break; } diff --git a/Server/mods/deathmatch/logic/CPerfStat.RPCPacketUsage.cpp b/Server/mods/deathmatch/logic/CPerfStat.RPCPacketUsage.cpp index cdebcedcc2..a6987403fd 100644 --- a/Server/mods/deathmatch/logic/CPerfStat.RPCPacketUsage.cpp +++ b/Server/mods/deathmatch/logic/CPerfStat.RPCPacketUsage.cpp @@ -149,6 +149,7 @@ ADD_ENUM1(SET_FPS_LIMIT) ADD_ENUM1(SET_GARAGE_OPEN) ADD_ENUM1(RESET_MAP_INFO) ADD_ENUM1(SET_GLITCH_ENABLED) +ADD_ENUM1(SET_PLAYER_GLITCH_ENABLED) ADD_ENUM1(SET_CLOUDS_ENABLED) ADD_ENUM1(REMOVE_ELEMENT_DATA) ADD_ENUM1(SET_VEHICLE_HANDLING) diff --git a/Server/mods/deathmatch/logic/CPlayer.cpp b/Server/mods/deathmatch/logic/CPlayer.cpp index e772b87b2d..b9128af063 100644 --- a/Server/mods/deathmatch/logic/CPlayer.cpp +++ b/Server/mods/deathmatch/logic/CPlayer.cpp @@ -120,6 +120,13 @@ CPlayer::CPlayer(CPlayerManager* pPlayerManager, class CScriptDebugging* pScript m_LastReceivedSyncTimer.SetUseModuleTickCount(true); m_ConnectedTimer.SetUseModuleTickCount(true); m_bIsLeavingServer = false; + + // Initialize per-player glitch states + for (int i = 0; i < NUM_GLITCHES; i++) + { + m_PlayerGlitches[i] = false; + m_bHasPlayerGlitchOverride[i] = false; + } } CPlayer::~CPlayer() @@ -1158,6 +1165,120 @@ CPlayer* GetDeletedMapKey(CPlayer**) // // ///////////////////////////////////////////////////////////////// +bool CPlayer::SetPlayerGlitchEnabled(const std::string& strGlitchName, bool bEnabled) +{ + if (!g_pGame->IsGlitch(strGlitchName)) + return false; + + eGlitchType eGlitch = g_pGame->GetGlitchIndex(strGlitchName); + if (eGlitch >= NUM_GLITCHES) + return false; + + m_PlayerGlitches[eGlitch] = bEnabled; + m_bHasPlayerGlitchOverride[eGlitch] = true; + + return true; +} + +bool CPlayer::IsPlayerGlitchEnabled(const std::string& strGlitchName) const +{ + if (!g_pGame->IsGlitch(strGlitchName)) + return false; + + eGlitchType eGlitch = g_pGame->GetGlitchIndex(strGlitchName); + if (eGlitch >= NUM_GLITCHES) + return false; + + if (m_bHasPlayerGlitchOverride[eGlitch]) + return m_PlayerGlitches[eGlitch]; + + return g_pGame->IsGlitchEnabled(eGlitch); +} + +bool CPlayer::HasPlayerGlitchOverride(const std::string& strGlitchName) const +{ + if (!g_pGame->IsGlitch(strGlitchName)) + return false; + + eGlitchType eGlitch = g_pGame->GetGlitchIndex(strGlitchName); + if (eGlitch >= NUM_GLITCHES) + return false; + + return m_bHasPlayerGlitchOverride[eGlitch]; +} + +void CPlayer::SendPlayerGlitchState(const std::string& strGlitchName) const +{ + if (!g_pGame->IsGlitch(strGlitchName)) + return; + + eGlitchType eGlitch = g_pGame->GetGlitchIndex(strGlitchName); + if (eGlitch >= NUM_GLITCHES) + return; + + bool bEffectiveState = IsPlayerGlitchEnabled(strGlitchName); + + CBitStream BitStream; + BitStream.pBitStream->Write(strGlitchName); + BitStream.pBitStream->WriteBit(bEffectiveState); + Send(CLuaPacket(SET_PLAYER_GLITCH_ENABLED, *BitStream.pBitStream)); +} + +void CPlayer::SendAllPlayerGlitchStates(CPlayer* pTarget) const +{ + CPlayer* pSendTo = pTarget ? pTarget : const_cast(this); + + if (pSendTo != this) + return; + + for (int i = 0; i < NUM_GLITCHES; i++) + { + if (m_bHasPlayerGlitchOverride[i]) + { + std::string strGlitchName; + for (const auto& pair : g_pGame->GetGlitchNames()) + { + if (pair.second == (eGlitchType)i) + { + strGlitchName = pair.first; + break; + } + } + + if (!strGlitchName.empty()) + { + SendPlayerGlitchState(strGlitchName); + } + } + } +} + +void CPlayer::ResetPlayerGlitchOverrides() +{ + for (int i = 0; i < NUM_GLITCHES; i++) + { + if (m_bHasPlayerGlitchOverride[i]) + { + m_bHasPlayerGlitchOverride[i] = false; + + std::string strGlitchName; + for (const auto& pair : g_pGame->GetGlitchNames()) + { + if (pair.second == (eGlitchType)i) + { + strGlitchName = pair.first; + break; + } + } + + if (!strGlitchName.empty()) + { + SendPlayerGlitchState(strGlitchName); + } + } + } +} + CPlayerBitStream::CPlayerBitStream(CPlayer* pPlayer) { pBitStream = g_pNetServer->AllocateNetServerBitStream(pPlayer->GetBitStreamVersion()); diff --git a/Server/mods/deathmatch/logic/CPlayer.h b/Server/mods/deathmatch/logic/CPlayer.h index 97e944b767..9a53fb8777 100644 --- a/Server/mods/deathmatch/logic/CPlayer.h +++ b/Server/mods/deathmatch/logic/CPlayer.h @@ -262,6 +262,13 @@ class CPlayer final : public CPed, public CClient bool GetTeleported() const noexcept { return m_teleported; } void SetTeleported(bool state) noexcept { m_teleported = state; } + bool SetPlayerGlitchEnabled(const std::string& strGlitchName, bool bEnabled); + bool IsPlayerGlitchEnabled(const std::string& strGlitchName) const; + bool HasPlayerGlitchOverride(const std::string& strGlitchName) const; + void SendPlayerGlitchState(const std::string& strGlitchName) const; + void SendAllPlayerGlitchStates(CPlayer* pTarget = nullptr) const; + void ResetPlayerGlitchOverrides(); + protected: bool ReadSpecialData(const int iLine) override { return true; } @@ -342,7 +349,9 @@ class CPlayer final : public CPed, public CClient private: SLightweightSyncData m_lightweightSyncData; - + SFixedArray m_PlayerGlitches; + SFixedArray m_bHasPlayerGlitchOverride; + void WriteCameraModePacket(); void WriteCameraPositionPacket(); diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 14644dc109..ac472f29ed 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -11254,6 +11254,36 @@ bool CStaticFunctionDefinitions::IsGlitchEnabled(const std::string& strGlitchNam return false; } +bool CStaticFunctionDefinitions::SetPlayerGlitchEnabled(CPlayer* pPlayer, const std::string& strGlitchName, bool bEnabled) +{ + assert(pPlayer); + + if (g_pGame->IsGlitch(strGlitchName)) + { + + if (pPlayer->SetPlayerGlitchEnabled(strGlitchName, bEnabled)) + { + + pPlayer->SendPlayerGlitchState(strGlitchName); + return true; + } + } + + return false; +} + +bool CStaticFunctionDefinitions::IsPlayerGlitchEnabled(CPlayer* pPlayer, const std::string& strGlitchName, bool& bEnabled) +{ + assert(pPlayer); + + if (g_pGame->IsGlitch(strGlitchName)) + { + bEnabled = pPlayer->IsPlayerGlitchEnabled(strGlitchName); + return true; + } + return false; +} + bool CStaticFunctionDefinitions::IsWorldSpecialPropertyEnabled(WorldSpecialProperty property) { return g_pGame->IsWorldSpecialPropertyEnabled(property); diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h index c0d46d5a7e..bc423e67f0 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -629,6 +629,8 @@ class CStaticFunctionDefinitions static bool SetGarageOpen(unsigned char ucGarageID, bool bIsOpen); static bool SetGlitchEnabled(const std::string& strGlitchName, bool bEnabled); static bool IsGlitchEnabled(const std::string& strGlitchName, bool& bEnabled); + static bool SetPlayerGlitchEnabled(CPlayer* pPlayer, const std::string& strGlitchName, bool bEnabled); + static bool IsPlayerGlitchEnabled(CPlayer* pPlayer, const std::string& strGlitchName, bool& bEnabled); static bool GetJetpackWeaponEnabled(eWeaponType weaponType, bool& bEnabled); static bool SetJetpackWeaponEnabled(eWeaponType weaponType, bool bEnabled); static bool SetCloudsEnabled(bool bEnabled); diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaWorldDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaWorldDefs.cpp index c46e1872bc..26d6b68305 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaWorldDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaWorldDefs.cpp @@ -56,6 +56,7 @@ void CLuaWorldDefs::LoadFunctions() {"setMinuteDuration", setMinuteDuration}, {"setGarageOpen", setGarageOpen}, {"setGlitchEnabled", setGlitchEnabled}, + {"setPlayerGlitchEnabled", setPlayerGlitchEnabled}, {"setCloudsEnabled", setCloudsEnabled}, {"setTrafficLightState", setTrafficLightState}, {"setTrafficLightsLocked", setTrafficLightsLocked}, @@ -92,6 +93,7 @@ void CLuaWorldDefs::LoadFunctions() // Check {"isGarageOpen", isGarageOpen}, {"isGlitchEnabled", isGlitchEnabled}, + {"isPlayerGlitchEnabled", isPlayerGlitchEnabled}, {"isWorldSpecialPropertyEnabled", ArgumentParserWarn}, {"areTrafficLightsLocked", areTrafficLightsLocked}}; @@ -1223,6 +1225,33 @@ int CLuaWorldDefs::setGlitchEnabled(lua_State* luaVM) return 1; } +int CLuaWorldDefs::setPlayerGlitchEnabled(lua_State* luaVM) +{ + + CPlayer* pPlayer; + SString strGlitch; + bool bEnabled; + + CScriptArgReader argStream(luaVM); + argStream.ReadUserData(pPlayer); + argStream.ReadString(strGlitch); + argStream.ReadBool(bEnabled); + + if (!argStream.HasErrors()) + { + if (CStaticFunctionDefinitions::SetPlayerGlitchEnabled(pPlayer, strGlitch, bEnabled)) + { + lua_pushboolean(luaVM, true); + return 1; + } + } + else + m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); + + lua_pushboolean(luaVM, false); + return 1; +} + int CLuaWorldDefs::isGlitchEnabled(lua_State* luaVM) { // bool isGlitchEnabled ( string glitchName ) @@ -1247,6 +1276,32 @@ int CLuaWorldDefs::isGlitchEnabled(lua_State* luaVM) return 1; } +int CLuaWorldDefs::isPlayerGlitchEnabled(lua_State* luaVM) +{ + // bool isPlayerGlitchEnabled ( player thePlayer, string glitchName ) + CPlayer* pPlayer; + SString strGlitch; + + CScriptArgReader argStream(luaVM); + argStream.ReadUserData(pPlayer); + argStream.ReadString(strGlitch); + + if (!argStream.HasErrors()) + { + bool bEnabled; + if (CStaticFunctionDefinitions::IsPlayerGlitchEnabled(pPlayer, strGlitch, bEnabled)) + { + lua_pushboolean(luaVM, bEnabled); + return 1; + } + } + else + m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); + + lua_pushboolean(luaVM, false); + return 1; +} + int CLuaWorldDefs::setJetpackWeaponEnabled(lua_State* luaVM) { eWeaponType weaponType; diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaWorldDefs.h b/Server/mods/deathmatch/logic/luadefs/CLuaWorldDefs.h index 49032579b3..f8e463770e 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaWorldDefs.h +++ b/Server/mods/deathmatch/logic/luadefs/CLuaWorldDefs.h @@ -28,6 +28,7 @@ class CLuaWorldDefs : public CLuaDefs LUA_DECLARE(getMinuteDuration); LUA_DECLARE(isGarageOpen); LUA_DECLARE(isGlitchEnabled); + LUA_DECLARE(isPlayerGlitchEnabled); LUA_DECLARE(setJetpackWeaponEnabled); LUA_DECLARE(getJetpackWeaponEnabled); LUA_DECLARE(getCloudsEnabled); @@ -63,6 +64,7 @@ class CLuaWorldDefs : public CLuaDefs LUA_DECLARE(setMinuteDuration); LUA_DECLARE(setGarageOpen); LUA_DECLARE(setGlitchEnabled); + LUA_DECLARE(setPlayerGlitchEnabled); LUA_DECLARE(setCloudsEnabled); LUA_DECLARE(setTrafficLightState); LUA_DECLARE(setTrafficLightsLocked); diff --git a/Server/mods/deathmatch/logic/packets/CPlayerGlitchRequestPacket.cpp b/Server/mods/deathmatch/logic/packets/CPlayerGlitchRequestPacket.cpp new file mode 100644 index 0000000000..ca2395e72d --- /dev/null +++ b/Server/mods/deathmatch/logic/packets/CPlayerGlitchRequestPacket.cpp @@ -0,0 +1,17 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: mods/deathmatch/logic/packets/CPlayerGlitchRequestPacket.cpp + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#include "CPlayerGlitchRequestPacket.h" + +bool CPlayerGlitchRequestPacket::Read(NetBitStreamInterface& stream) noexcept +{ + return stream.Read(m_glitchName) && stream.ReadBit(m_enabled); +} \ No newline at end of file diff --git a/Server/mods/deathmatch/logic/packets/CPlayerGlitchRequestPacket.h b/Server/mods/deathmatch/logic/packets/CPlayerGlitchRequestPacket.h new file mode 100644 index 0000000000..8909d89b3f --- /dev/null +++ b/Server/mods/deathmatch/logic/packets/CPlayerGlitchRequestPacket.h @@ -0,0 +1,34 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: mods/deathmatch/logic/packets/CPlayerGlitchRequestPacket.h + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +#include +#include +#include "CPacket.h" + +class CPlayerGlitchRequestPacket final : public CPacket +{ +public: + CPlayerGlitchRequestPacket() noexcept {} + + ePacketID GetPacketID() const noexcept { return PACKET_ID_PLAYER_GLITCH_REQUEST; } + unsigned long GetFlags() const noexcept { return PACKET_HIGH_PRIORITY | PACKET_RELIABLE | PACKET_SEQUENCED; } + virtual ePacketOrdering GetPacketOrdering() const noexcept { return PACKET_ORDERING_DEFAULT; } + + bool Read(NetBitStreamInterface& stream) noexcept; + + const std::string& GetGlitchName() const noexcept { return m_glitchName; } + bool IsEnabled() const noexcept { return m_enabled; } + +private: + std::string m_glitchName; + bool m_enabled{}; +}; \ No newline at end of file diff --git a/Shared/mods/deathmatch/logic/Enums.cpp b/Shared/mods/deathmatch/logic/Enums.cpp index 8bb99db974..2d80298bb4 100644 --- a/Shared/mods/deathmatch/logic/Enums.cpp +++ b/Shared/mods/deathmatch/logic/Enums.cpp @@ -233,4 +233,5 @@ ADD_ENUM1(PACKET_ID_SERVER_INFO_SYNC) ADD_ENUM1(PACKET_ID_DISCORD_JOIN) ADD_ENUM1(PACKET_ID_PLAYER_RESOURCE_START) ADD_ENUM1(PACKET_ID_PLAYER_WORLD_SPECIAL_PROPERTY) +ADD_ENUM1(PACKET_ID_PLAYER_GLITCH_REQUEST) IMPLEMENT_ENUM_END("ePacketID") diff --git a/Shared/sdk/net/Packets.h b/Shared/sdk/net/Packets.h index 2f587cad14..64ef3e736f 100644 --- a/Shared/sdk/net/Packets.h +++ b/Shared/sdk/net/Packets.h @@ -177,5 +177,6 @@ enum ePacketID PACKET_ID_SERVER_INFO_SYNC, PACKET_ID_DISCORD_JOIN, PACKET_ID_PLAYER_RESOURCE_START, - PACKET_ID_PLAYER_WORLD_SPECIAL_PROPERTY + PACKET_ID_PLAYER_WORLD_SPECIAL_PROPERTY, + PACKET_ID_PLAYER_GLITCH_REQUEST }; diff --git a/Shared/sdk/net/rpc_enums.h b/Shared/sdk/net/rpc_enums.h index 84c7518bc4..0b3c88b0cb 100644 --- a/Shared/sdk/net/rpc_enums.h +++ b/Shared/sdk/net/rpc_enums.h @@ -170,6 +170,7 @@ enum eElementRPCFunctions SET_GARAGE_OPEN, RESET_MAP_INFO, SET_GLITCH_ENABLED, + SET_PLAYER_GLITCH_ENABLED, SET_CLOUDS_ENABLED, REMOVE_ELEMENT_DATA,