From 96bfdb8140ae0b3edd96bce65127827b235210f4 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 18 Dec 2023 23:44:23 +0300 Subject: [PATCH] Fix custom models and setElementModel --- .../mods/deathmatch/logic/CClientBuilding.cpp | 9 +++ .../mods/deathmatch/logic/CClientBuilding.h | 3 + Client/mods/deathmatch/logic/CClientModel.cpp | 32 +++++++-- .../logic/CStaticFunctionDefinitions.cpp | 67 +++++++++---------- .../logic/luadefs/CLuaBuildingDefs.cpp | 3 + 5 files changed, 76 insertions(+), 38 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientBuilding.cpp b/Client/mods/deathmatch/logic/CClientBuilding.cpp index daa2716403..f769fbe794 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.cpp +++ b/Client/mods/deathmatch/logic/CClientBuilding.cpp @@ -51,6 +51,15 @@ void CClientBuilding::SetInterior(uint8_t ucInterior) { m_interior = ucInterior; Recreate(); +} + +void CClientBuilding::SetModel(uint16_t model) +{ + if (CClientObjectManager::IsValidModel(model)) + { + m_usModelId = model; + Recreate(); + } } void CClientBuilding::Create() diff --git a/Client/mods/deathmatch/logic/CClientBuilding.h b/Client/mods/deathmatch/logic/CClientBuilding.h index c2d4e92291..23f63d296e 100644 --- a/Client/mods/deathmatch/logic/CClientBuilding.h +++ b/Client/mods/deathmatch/logic/CClientBuilding.h @@ -32,6 +32,9 @@ class CClientBuilding : public CClientEntity void SetInterior(uint8_t ucInterior) override; + uint16_t GetModel() { return m_usModelId; }; + void SetModel(uint16_t ulModel); + eClientEntityType GetType() const { return CCLIENTBUILDING; } private: diff --git a/Client/mods/deathmatch/logic/CClientModel.cpp b/Client/mods/deathmatch/logic/CClientModel.cpp index e42ee3a695..a30bdabe0e 100644 --- a/Client/mods/deathmatch/logic/CClientModel.cpp +++ b/Client/mods/deathmatch/logic/CClientModel.cpp @@ -122,6 +122,13 @@ void CClientModel::RestoreEntitiesUsingThisModel() void CClientModel::RestoreDFF(CModelInfo* pModelInfo) { + auto callElementChangeEvent = [](auto &element, unsigned short usParentID, auto modelId) { + CLuaArguments Arguments; + Arguments.PushNumber(modelId); + Arguments.PushNumber(usParentID); + element.CallEvent("onClientElementModelChange", Arguments, true); + }; + auto unloadModelsAndCallEvents = [&](auto iterBegin, auto iterEnd, unsigned short usParentID, auto setElementModelLambda) { for (auto iter = iterBegin; iter != iterEnd; iter++) { @@ -135,10 +142,21 @@ void CClientModel::RestoreDFF(CModelInfo* pModelInfo) setElementModelLambda(element); - CLuaArguments Arguments; - Arguments.PushNumber(m_iModelID); - Arguments.PushNumber(usParentID); - element.CallEvent("onClientElementModelChange", Arguments, true); + callElementChangeEvent(element, usParentID, m_iModelID); + } + }; + + auto unloadModelsAndCallEventsNonStreamed = [&](auto iterBegin, auto iterEnd, unsigned short usParentID, auto setElementModelLambda) + { + for (auto iter = iterBegin; iter != iterEnd; iter++) + { + auto& element = **iter; + + if (element.GetModel() != m_iModelID) + continue; + + setElementModelLambda(element); + callElementChangeEvent(element, usParentID, m_iModelID); } }; @@ -166,6 +184,12 @@ void CClientModel::RestoreDFF(CModelInfo* pModelInfo) unloadModelsAndCallEvents(pPickupManager->IterBegin(), pPickupManager->IterEnd(), usParentID, [=](auto& element) { element.SetModel(usParentID); }); + // Restore buildings + CClientBuildingManager* pBuildingsManager = g_pClientGame->GetManager()->GetBuildingManager(); + + unloadModelsAndCallEventsNonStreamed(pBuildingsManager->IterBegin(), pBuildingsManager->IterEnd(), usParentID, + [=](auto& element) { element.SetModel(usParentID); }); + // Restore COL g_pClientGame->GetManager()->GetColModelManager()->RestoreModel(m_iModelID); break; diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index ffc4466a33..3782356db3 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -1461,6 +1461,26 @@ bool CStaticFunctionDefinitions::SetElementModel(CClientEntity& Entity, unsigned { RUN_CHILDREN(SetElementModel(**iter, usModel)) + auto callOnChangeEvent = [](auto &element, uint16_t usCurrentModel, uint16_t usModel) { + CLuaArguments Arguments; + Arguments.PushNumber(usCurrentModel); + Arguments.PushNumber(usModel); + bool bContinue = element.CallEvent("onClientElementModelChange", Arguments, true); + + // Check for another call to setElementModel + if (usModel != element.GetModel()) + return false; + + if (!bContinue) + { + // Change canceled + element.SetModel(usCurrentModel); + return false; + } + + return true; + }; + switch (Entity.GetType()) { case CCLIENTPED: @@ -1476,23 +1496,7 @@ bool CStaticFunctionDefinitions::SetElementModel(CClientEntity& Entity, unsigned if (!Ped.SetModel(usModel)) return false; - CLuaArguments Arguments; - Arguments.PushNumber(usCurrentModel); - Arguments.PushNumber(usModel); - bool bContinue = Ped.CallEvent("onClientElementModelChange", Arguments, true); - - // Check for another call to setElementModel - if (usModel != Ped.GetModel()) - return false; - - if (!bContinue) - { - // Change canceled - Ped.SetModel(usCurrentModel); - return false; - } - - break; + return callOnChangeEvent(Ped, usCurrentModel, usModel); } case CCLIENTVEHICLE: { @@ -1539,23 +1543,22 @@ bool CStaticFunctionDefinitions::SetElementModel(CClientEntity& Entity, unsigned Object.SetModel(usModel); - CLuaArguments Arguments; - Arguments.PushNumber(usCurrentModel); - Arguments.PushNumber(usModel); - bool bContinue = Object.CallEvent("onClientElementModelChange", Arguments, true); + return callOnChangeEvent(Object, usCurrentModel, usModel); + } + case CCLIENTBUILDING: + { + CClientBuilding& Object = static_cast(Entity); + const unsigned short usCurrentModel = Object.GetModel(); - // Check for another call to setElementModel - if (usModel != Object.GetModel()) + if (usCurrentModel == usModel) return false; - if (!bContinue) - { - // Change canceled - Object.SetModel(usCurrentModel); + if (!CClientObjectManager::IsValidModel(usModel)) return false; - } - break; + Object.SetModel(usModel); + + return callOnChangeEvent(Object, usCurrentModel, usModel); } case CCLIENTPROJECTILE: { @@ -1570,11 +1573,7 @@ bool CStaticFunctionDefinitions::SetElementModel(CClientEntity& Entity, unsigned Projectile.SetModel(usModel); - CLuaArguments Arguments; - Arguments.PushNumber(usCurrentModel); - Arguments.PushNumber(usModel); - Projectile.CallEvent("onClientElementModelChange", Arguments, true); - break; + return callOnChangeEvent(Projectile, usCurrentModel, usModel); } default: return false; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index 6501bc763e..c4422770cb 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -40,6 +40,9 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 if (!pResource) return false; + if (!CClientObjectManager::IsValidModel(modelId)) + throw std::invalid_argument("Invalid model id"); + // Grab the resource root entity CClientEntity* pRoot = pResource->GetResourceDynamicEntity();