diff --git a/dGame/dComponents/ModelComponent.cpp b/dGame/dComponents/ModelComponent.cpp index 5af8bd51..52682efb 100644 --- a/dGame/dComponents/ModelComponent.cpp +++ b/dGame/dComponents/ModelComponent.cpp @@ -15,6 +15,8 @@ ModelComponent::ModelComponent(Entity* parent) : Component(parent) { m_OriginalPosition = m_Parent->GetDefaultPosition(); m_OriginalRotation = m_Parent->GetDefaultRotation(); + m_IsPaused = false; + m_IsPickable = false; m_userModelID = m_Parent->GetVarAs(u"userModelID"); RegisterMsg(MessageType::Game::REQUEST_USE, this, &ModelComponent::OnRequestUse); @@ -27,6 +29,8 @@ bool ModelComponent::OnRequestUse(GameMessages::GameMsg& msg) { } void ModelComponent::Update(float deltaTime) { + if (m_IsPaused) return; + for (auto& behavior : m_Behaviors) { behavior.Update(deltaTime, *this); } @@ -59,6 +63,11 @@ void ModelComponent::LoadBehaviors() { } } +void ModelComponent::Resume() { + m_Dirty = true; + m_IsPaused = false; +} + void ModelComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { // ItemComponent Serialization. Pets do not get this serialization. if (!m_Parent->HasComponent(eReplicaComponentType::PET)) { @@ -70,14 +79,14 @@ void ModelComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialU //actual model component: outBitStream.Write1(); // Yes we are writing model info - outBitStream.Write1(); // Is pickable + outBitStream.Write(m_IsPickable); // Is pickable outBitStream.Write(2); // Physics type outBitStream.Write(m_OriginalPosition); // Original position outBitStream.Write(m_OriginalRotation); // Original rotation outBitStream.Write1(); // We are writing behavior info outBitStream.Write(m_Behaviors.size()); // Number of behaviors - outBitStream.Write0(); // Is this model paused + outBitStream.Write(m_IsPaused); // Is this model paused if (bIsInitialUpdate) outBitStream.Write0(); // We are not writing model editing info } diff --git a/dGame/dComponents/ModelComponent.h b/dGame/dComponents/ModelComponent.h index 65a10631..90f824e3 100644 --- a/dGame/dComponents/ModelComponent.h +++ b/dGame/dComponents/ModelComponent.h @@ -62,7 +62,7 @@ public: /** * Main gateway for all behavior messages to be passed to their respective behaviors. - * + * * @tparam Msg The message type to pass * @param args the arguments of the message to be deserialized */ @@ -71,7 +71,7 @@ public: static_assert(std::is_base_of_v, "Msg must be a BehaviorMessageBase"); Msg msg{ args }; for (auto&& behavior : m_Behaviors) { - if (behavior.GetBehaviorId() == msg.GetBehaviorId()) { + if (behavior.GetBehaviorId() == msg.GetBehaviorId()) { behavior.HandleMsg(msg); return; } @@ -112,14 +112,24 @@ public: void SendBehaviorListToClient(AMFArrayValue& args) const; void SendBehaviorBlocksToClient(int32_t behaviorToSend, AMFArrayValue& args) const; - + void VerifyBehaviors(); std::array, 5> GetBehaviorsForSave() const; const std::vector& GetBehaviors() const { return m_Behaviors; }; + void SetIsPickable(bool pickable) { m_Dirty = m_IsPickable == pickable; m_IsPickable = pickable; } + + void Pause() { m_Dirty = true; m_IsPaused = true; } + + void Resume(); private: + bool m_Dirty{}; + + bool m_IsPickable{}; + + bool m_IsPaused{}; /** * The behaviors of the model * Note: This is a vector because the order of the behaviors matters when serializing to the client. diff --git a/dGame/dComponents/PropertyManagementComponent.cpp b/dGame/dComponents/PropertyManagementComponent.cpp index d7be22ac..33998716 100644 --- a/dGame/dComponents/PropertyManagementComponent.cpp +++ b/dGame/dComponents/PropertyManagementComponent.cpp @@ -221,6 +221,8 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) { } void PropertyManagementComponent::OnStartBuilding() { + m_IsBuilding = true; + auto* ownerEntity = GetOwner(); if (ownerEntity == nullptr) return; @@ -253,9 +255,20 @@ void PropertyManagementComponent::OnStartBuilding() { // Push equipped items if (inventoryComponent) inventoryComponent->PushEquippedItems(); + + for (auto modelID : models | std::views::keys) { + auto* model = Game::entityManager->GetEntity(modelID); + if (model) { + auto* modelComponent = model->GetComponent(); + if (modelComponent) modelComponent->Pause(); + Game::entityManager->SerializeEntity(model); + } + } } void PropertyManagementComponent::OnFinishBuilding() { + m_IsBuilding = false; + auto* ownerEntity = GetOwner(); if (ownerEntity == nullptr) return; @@ -265,6 +278,15 @@ void PropertyManagementComponent::OnFinishBuilding() { UpdateApprovedStatus(false); Save(); + + for (auto modelID : models | std::views::keys) { + auto* model = Game::entityManager->GetEntity(modelID); + if (model) { + auto* modelComponent = model->GetComponent(); + if (modelComponent) modelComponent->Resume(); + Game::entityManager->SerializeEntity(model); + } + } } void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const NiPoint3 position, NiQuaternion rotation) { @@ -316,6 +338,8 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N Entity* newEntity = Game::entityManager->CreateEntity(info); if (newEntity != nullptr) { Game::entityManager->ConstructEntity(newEntity); + auto* modelComponent = newEntity->GetComponent(); + if (modelComponent) modelComponent->Pause(); // Make sure the propMgmt doesn't delete our model after the server dies // Trying to do this after the entity is constructed. Shouldn't really change anything but @@ -361,6 +385,8 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N info.nodes[0]->config.push_back(new LDFData(u"componentWhitelist", 1)); auto* model = spawner->Spawn(); + auto* modelComponent = model->GetComponent(); + if (modelComponent) modelComponent->Pause(); models.insert_or_assign(model->GetObjectID(), spawnerId); diff --git a/dGame/dComponents/PropertyManagementComponent.h b/dGame/dComponents/PropertyManagementComponent.h index 6a9ed09d..700b3f02 100644 --- a/dGame/dComponents/PropertyManagementComponent.h +++ b/dGame/dComponents/PropertyManagementComponent.h @@ -239,4 +239,6 @@ private: * The privacy setting before it was changed, saved to set back after a player finishes building */ PropertyPrivacyOption originalPrivacyOption = PropertyPrivacyOption::Private; + + bool m_IsBuilding{}; }; diff --git a/dGame/dPropertyBehaviors/Strip.cpp b/dGame/dPropertyBehaviors/Strip.cpp index 3877b618..8a22184e 100644 --- a/dGame/dPropertyBehaviors/Strip.cpp +++ b/dGame/dPropertyBehaviors/Strip.cpp @@ -107,15 +107,11 @@ void Strip::SpawnDrop(LOT dropLOT, Entity& entity) { } } -void Strip::Update(float deltaTime, ModelComponent& modelComponent) { - m_PausedTime -= deltaTime; - if (m_PausedTime > 0.0f) return; - m_PausedTime = 0.0f; +void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) { auto& entity = *modelComponent.GetParent(); auto& nextAction = GetNextAction(); auto number = nextAction.GetValueParameterDouble(); auto numberAsInt = static_cast(number); - if (GetNextAction().GetType() == "SpawnStromling") { Spawn(10495, entity); } else if (GetNextAction().GetType() == "SpawnPirate") { @@ -142,12 +138,30 @@ void Strip::Update(float deltaTime, ModelComponent& modelComponent) { } else if (nextAction.GetType() == "Wait") { m_PausedTime = number; } else { + LOG("Tried to play action (%s) which is not supported.", nextAction.GetType().data()); return; } IncrementAction(); } +void Strip::Update(float deltaTime, ModelComponent& modelComponent) { + m_PausedTime -= deltaTime; + if (m_PausedTime > 0.0f) return; + + m_PausedTime = 0.0f; + auto& entity = *modelComponent.GetParent(); + auto& nextAction = GetNextAction(); + + // Check for starting blocks and if not a starting block proc this blocks action + if (nextAction.GetType() == "OnInteract") { + modelComponent.SetIsPickable(true); + Game::entityManager->SerializeEntity(entity); + } else { // should be a normal block + ProcNormalAction(deltaTime, modelComponent); + } +} + void Strip::SendBehaviorBlocksToClient(AMFArrayValue& args) const { m_Position.SendBehaviorBlocksToClient(args); diff --git a/dGame/dPropertyBehaviors/Strip.h b/dGame/dPropertyBehaviors/Strip.h index 511d2b6c..11b48682 100644 --- a/dGame/dPropertyBehaviors/Strip.h +++ b/dGame/dPropertyBehaviors/Strip.h @@ -33,6 +33,7 @@ public: void Spawn(LOT object, Entity& entity); void Update(float deltaTime, ModelComponent& modelComponent); void SpawnDrop(LOT dropLOT, Entity& entity); + void ProcNormalAction(float deltaTime, ModelComponent& modelComponent); private: float m_PausedTime{ 0.0f }; size_t m_NextActionIndex{ 0 };