mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-08-06 10:44:08 +00:00
feat: Property behaviors partially functional (#1759)
* most of gameplay tab works * smash unsmash and wait working * Add pausing of models and behaviors * working basic behaviors * play sound functioning * add resetting * Fix asynchronous actions executing other strips actions * Add comments, remove dead code etc. * Skip Smashes if they coincide with a UnSmash Remove debug logs Comment on return
This commit is contained in:
@@ -10,12 +10,50 @@
|
||||
#include "SimplePhysicsComponent.h"
|
||||
|
||||
#include "Database.h"
|
||||
#include "DluAssert.h"
|
||||
|
||||
ModelComponent::ModelComponent(Entity* parent) : Component(parent) {
|
||||
m_OriginalPosition = m_Parent->GetDefaultPosition();
|
||||
m_OriginalRotation = m_Parent->GetDefaultRotation();
|
||||
m_IsPaused = false;
|
||||
m_NumListeningInteract = 0;
|
||||
|
||||
m_userModelID = m_Parent->GetVarAs<LWOOBJID>(u"userModelID");
|
||||
RegisterMsg(MessageType::Game::REQUEST_USE, this, &ModelComponent::OnRequestUse);
|
||||
RegisterMsg(MessageType::Game::RESET_MODEL_TO_DEFAULTS, this, &ModelComponent::OnResetModelToDefaults);
|
||||
}
|
||||
|
||||
bool ModelComponent::OnResetModelToDefaults(GameMessages::GameMsg& msg) {
|
||||
auto& reset = static_cast<GameMessages::ResetModelToDefaults&>(msg);
|
||||
for (auto& behavior : m_Behaviors) behavior.HandleMsg(reset);
|
||||
GameMessages::UnSmash unsmash;
|
||||
unsmash.target = GetParent()->GetObjectID();
|
||||
unsmash.duration = 0.0f;
|
||||
unsmash.Send(UNASSIGNED_SYSTEM_ADDRESS);
|
||||
m_NumListeningInteract = 0;
|
||||
m_NumActiveUnSmash = 0;
|
||||
m_Dirty = true;
|
||||
Game::entityManager->SerializeEntity(GetParent());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModelComponent::OnRequestUse(GameMessages::GameMsg& msg) {
|
||||
bool toReturn = false;
|
||||
if (!m_IsPaused) {
|
||||
auto& requestUse = static_cast<GameMessages::RequestUse&>(msg);
|
||||
for (auto& behavior : m_Behaviors) behavior.HandleMsg(requestUse);
|
||||
toReturn = true;
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
void ModelComponent::Update(float deltaTime) {
|
||||
if (m_IsPaused) return;
|
||||
|
||||
for (auto& behavior : m_Behaviors) {
|
||||
behavior.Update(deltaTime, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelComponent::LoadBehaviors() {
|
||||
@@ -29,9 +67,9 @@ void ModelComponent::LoadBehaviors() {
|
||||
LOG_DEBUG("Loading behavior %d", behaviorId.value());
|
||||
auto& inserted = m_Behaviors.emplace_back();
|
||||
inserted.SetBehaviorId(*behaviorId);
|
||||
|
||||
|
||||
const auto behaviorStr = Database::Get()->GetBehavior(behaviorId.value());
|
||||
|
||||
|
||||
tinyxml2::XMLDocument behaviorXml;
|
||||
auto res = behaviorXml.Parse(behaviorStr.c_str(), behaviorStr.size());
|
||||
LOG_DEBUG("Behavior %i %d: %s", res, behaviorId.value(), behaviorStr.c_str());
|
||||
@@ -45,6 +83,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)) {
|
||||
@@ -56,14 +99,14 @@ void ModelComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialU
|
||||
|
||||
//actual model component:
|
||||
outBitStream.Write1(); // Yes we are writing model info
|
||||
outBitStream.Write0(); // Is pickable
|
||||
outBitStream.Write(m_NumListeningInteract > 0); // Is pickable
|
||||
outBitStream.Write<uint32_t>(2); // Physics type
|
||||
outBitStream.Write(m_OriginalPosition); // Original position
|
||||
outBitStream.Write(m_OriginalRotation); // Original rotation
|
||||
|
||||
outBitStream.Write1(); // We are writing behavior info
|
||||
outBitStream.Write<uint32_t>(0); // Number of behaviors
|
||||
outBitStream.Write1(); // Is this model paused
|
||||
outBitStream.Write<uint32_t>(m_Behaviors.size()); // Number of behaviors
|
||||
outBitStream.Write(m_IsPaused); // Is this model paused
|
||||
if (bIsInitialUpdate) outBitStream.Write0(); // We are not writing model editing info
|
||||
}
|
||||
|
||||
@@ -135,3 +178,28 @@ std::array<std::pair<int32_t, std::string>, 5> ModelComponent::GetBehaviorsForSa
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
void ModelComponent::AddInteract() {
|
||||
LOG_DEBUG("Adding interact %i", m_NumListeningInteract);
|
||||
m_Dirty = true;
|
||||
m_NumListeningInteract++;
|
||||
}
|
||||
|
||||
void ModelComponent::RemoveInteract() {
|
||||
DluAssert(m_NumListeningInteract > 0);
|
||||
LOG_DEBUG("Removing interact %i", m_NumListeningInteract);
|
||||
m_Dirty = true;
|
||||
m_NumListeningInteract--;
|
||||
}
|
||||
|
||||
void ModelComponent::AddUnSmash() {
|
||||
LOG_DEBUG("Adding UnSmash %i", m_NumActiveUnSmash);
|
||||
m_NumActiveUnSmash++;
|
||||
}
|
||||
|
||||
void ModelComponent::RemoveUnSmash() {
|
||||
// Players can assign an UnSmash without a Smash so an assert would be bad here
|
||||
if (m_NumActiveUnSmash == 0) return;
|
||||
LOG_DEBUG("Removing UnSmash %i", m_NumActiveUnSmash);
|
||||
m_NumActiveUnSmash--;
|
||||
}
|
||||
|
@@ -30,6 +30,10 @@ public:
|
||||
ModelComponent(Entity* parent);
|
||||
|
||||
void LoadBehaviors();
|
||||
void Update(float deltaTime) override;
|
||||
|
||||
bool OnRequestUse(GameMessages::GameMsg& msg);
|
||||
bool OnResetModelToDefaults(GameMessages::GameMsg& msg);
|
||||
|
||||
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
||||
|
||||
@@ -59,7 +63,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
|
||||
*/
|
||||
@@ -68,7 +72,7 @@ public:
|
||||
static_assert(std::is_base_of_v<BehaviorMessageBase, Msg>, "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;
|
||||
}
|
||||
@@ -109,12 +113,35 @@ public:
|
||||
void SendBehaviorListToClient(AMFArrayValue& args) const;
|
||||
|
||||
void SendBehaviorBlocksToClient(int32_t behaviorToSend, AMFArrayValue& args) const;
|
||||
|
||||
|
||||
void VerifyBehaviors();
|
||||
|
||||
std::array<std::pair<int32_t, std::string>, 5> GetBehaviorsForSave() const;
|
||||
|
||||
const std::vector<PropertyBehavior>& GetBehaviors() const { return m_Behaviors; };
|
||||
|
||||
void AddInteract();
|
||||
void RemoveInteract();
|
||||
|
||||
void Pause() { m_Dirty = true; m_IsPaused = true; }
|
||||
|
||||
void AddUnSmash();
|
||||
void RemoveUnSmash();
|
||||
bool IsUnSmashing() const { return m_NumActiveUnSmash != 0; }
|
||||
|
||||
void Resume();
|
||||
private:
|
||||
// Number of Actions that are awaiting an UnSmash to finish.
|
||||
uint32_t m_NumActiveUnSmash{};
|
||||
|
||||
// Whether or not this component needs to have its extra data serialized.
|
||||
bool m_Dirty{};
|
||||
|
||||
// The number of strips listening for a RequestUse GM to come in.
|
||||
uint32_t m_NumListeningInteract{};
|
||||
|
||||
// Whether or not the model is paused and should reject all interactions regarding behaviors.
|
||||
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.
|
||||
|
@@ -255,6 +255,18 @@ 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<ModelComponent>();
|
||||
if (modelComponent) modelComponent->Pause();
|
||||
Game::entityManager->SerializeEntity(model);
|
||||
GameMessages::ResetModelToDefaults reset;
|
||||
reset.target = modelID;
|
||||
model->HandleMsg(reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyManagementComponent::OnFinishBuilding() {
|
||||
@@ -267,6 +279,18 @@ 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<ModelComponent>();
|
||||
if (modelComponent) modelComponent->Resume();
|
||||
Game::entityManager->SerializeEntity(model);
|
||||
GameMessages::ResetModelToDefaults reset;
|
||||
reset.target = modelID;
|
||||
model->HandleMsg(reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const NiPoint3 position, NiQuaternion rotation) {
|
||||
@@ -318,6 +342,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<ModelComponent>();
|
||||
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
|
||||
@@ -363,6 +389,8 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N
|
||||
info.nodes[0]->config.push_back(new LDFData<int>(u"componentWhitelist", 1));
|
||||
|
||||
auto* model = spawner->Spawn();
|
||||
auto* modelComponent = model->GetComponent<ModelComponent>();
|
||||
if (modelComponent) modelComponent->Pause();
|
||||
|
||||
models.insert_or_assign(model->GetObjectID(), spawnerId);
|
||||
|
||||
|
Reference in New Issue
Block a user