From cefdfc696a8c843ee53261cb45e048cff26a235a Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Sun, 6 Aug 2023 15:38:12 -0500 Subject: [PATCH] fix: Implement proper Sound trigger component serialization (#1160) * cleanup * more cleanup and fully implement the sound trigger and racing sound trigger * more cleanup, and better defaults * fixes and tested * update initializor for guid and when to load sound guids * make racing sound trigger it's own component * fix type * Remove global move serializes --------- Co-authored-by: David Markowitz --- dGame/Entity.cpp | 9 ++ .../dComponents/RacingSoundTriggerComponent.h | 15 ++ dGame/dComponents/SoundTriggerComponent.cpp | 143 ++++++++++-------- dGame/dComponents/SoundTriggerComponent.h | 86 ++++++----- dGame/dUtilities/GUID.cpp | 26 ++-- dGame/dUtilities/GUID.h | 22 ++- 6 files changed, 188 insertions(+), 113 deletions(-) create mode 100644 dGame/dComponents/RacingSoundTriggerComponent.h diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index e3bacb8b..237cfa73 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -71,6 +71,7 @@ #include "ShootingGalleryComponent.h" #include "RailActivatorComponent.h" #include "LUPExhibitComponent.h" +#include "RacingSoundTriggerComponent.h" #include "TriggerComponent.h" #include "eGameMasterLevel.h" #include "eReplicaComponentType.h" @@ -318,6 +319,9 @@ void Entity::Initialize() { if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) { auto* comp = new SoundTriggerComponent(this); m_Components.insert(std::make_pair(eReplicaComponentType::SOUND_TRIGGER, comp)); + } else if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_SOUND_TRIGGER, -1) != -1) { + auto* comp = new RacingSoundTriggerComponent(this); + m_Components.insert(std::make_pair(eReplicaComponentType::RACING_SOUND_TRIGGER, comp)); } //Also check for the collectible id: @@ -1060,6 +1064,11 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } + RacingSoundTriggerComponent* racingSoundTriggerComponent; + if (TryGetComponent(eReplicaComponentType::RACING_SOUND_TRIGGER, racingSoundTriggerComponent)) { + racingSoundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags); + } + BuffComponent* buffComponent; if (TryGetComponent(eReplicaComponentType::BUFF, buffComponent)) { buffComponent->Serialize(outBitStream, bIsInitialUpdate, flags); diff --git a/dGame/dComponents/RacingSoundTriggerComponent.h b/dGame/dComponents/RacingSoundTriggerComponent.h new file mode 100644 index 00000000..0f79c67f --- /dev/null +++ b/dGame/dComponents/RacingSoundTriggerComponent.h @@ -0,0 +1,15 @@ +#ifndef __RACINGSOUNDTRIGGERCOMPONENT__H__ +#define __RACINGSOUNDTRIGGERCOMPONENT__H__ + +#include "SoundTriggerComponent.h" +#include "eReplicaComponentType.h" + +class Entity; + +class RacingSoundTriggerComponent : public SoundTriggerComponent { +public: + inline static const eReplicaComponentType ComponentType = eReplicaComponentType::RACING_SOUND_TRIGGER; + RacingSoundTriggerComponent(Entity* parent) : SoundTriggerComponent(parent){}; +}; + +#endif //!__RACINGSOUNDTRIGGERCOMPONENT__H__ diff --git a/dGame/dComponents/SoundTriggerComponent.cpp b/dGame/dComponents/SoundTriggerComponent.cpp index 21d30948..823d3ff4 100644 --- a/dGame/dComponents/SoundTriggerComponent.cpp +++ b/dGame/dComponents/SoundTriggerComponent.cpp @@ -1,93 +1,114 @@ #include "SoundTriggerComponent.h" -#include "EntityManager.h" #include "Game.h" +#include "dLogger.h" +void MusicCue::Serialize(RakNet::BitStream* outBitStream){ + outBitStream->Write(name.size()); + outBitStream->Write(name.c_str(), name.size()); + outBitStream->Write(result); + outBitStream->Write(boredomTime); +} + +void MusicParameter::Serialize(RakNet::BitStream* outBitStream){ + outBitStream->Write(name.size()); + outBitStream->Write(name.c_str(), name.size()); + outBitStream->Write(value); +} + +void GUIDResults::Serialize(RakNet::BitStream* outBitStream){ + guid.Serialize(outBitStream); + outBitStream->Write(result); +} + +void MixerProgram::Serialize(RakNet::BitStream* outBitStream){ + outBitStream->Write(name.size()); + outBitStream->Write(name.c_str(), name.size()); + outBitStream->Write(result); +} SoundTriggerComponent::SoundTriggerComponent(Entity* parent) : Component(parent) { + const auto musicCueName = parent->GetVar(u"NDAudioMusicCue_Name"); - const auto musicCueBoredomTime = parent->GetVar(u"NDAudioMusicCue_BoredomTime"); + if (!musicCueName.empty()) { + auto newCue = MusicCue(musicCueName); + const auto musicCueBoredomTime = parent->GetVar(u"NDAudioMusicCue_BoredomTime"); + if (musicCueBoredomTime) newCue.boredomTime = musicCueBoredomTime; + this->m_MusicCues.push_back(newCue); + } - this->musicCues.push_back({ - musicCueName, - 1, - musicCueBoredomTime - }); + const auto musicParameterName = parent->GetVar(u"NDAudioMusicParameter_Name"); + if (!musicParameterName.empty()) { + auto newParams = MusicParameter(musicParameterName); + const auto musicParameterValue = parent->GetVar(u"NDAudioMusicParameter_Value"); + if (musicParameterValue) newParams.value = musicParameterValue; + this->m_MusicParameters.push_back(newParams); + } - const auto mixerName = parent->GetVar(u"NDAudioMixerProgram_Name"); - this->mixerPrograms.push_back(mixerName); + const auto guidString = parent->GetVar(u"NDAudioEventGUID"); + if (!guidString.empty()) + this->m_2DAmbientSounds.push_back(GUIDResults(guidString)); const auto guid2String = parent->GetVar(u"NDAudioEventGUID2"); - if (!guid2String.empty()) { - this->guids.emplace_back(guid2String); - } -} + if (!guid2String.empty()) + this->m_3DAmbientSounds.push_back(GUIDResults(guid2String)); -SoundTriggerComponent::~SoundTriggerComponent() = default; + const auto mixerName = parent->GetVar(u"NDAudioMixerProgram_Name"); + if (!mixerName.empty()) this->m_MixerPrograms.push_back(MixerProgram(mixerName)); +} void SoundTriggerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - if (bIsInitialUpdate) - dirty = true; - - outBitStream->Write(dirty); - - if (dirty) { - outBitStream->Write(this->musicCues.size()); - for (const auto& musicCue : this->musicCues) { - outBitStream->Write(musicCue.name.size()); - outBitStream->Write(musicCue.name.c_str(), musicCue.name.size()); - outBitStream->Write(musicCue.result); - outBitStream->Write(musicCue.boredomTime); + outBitStream->Write(this->m_Dirty || bIsInitialUpdate); + if (this->m_Dirty || bIsInitialUpdate) { + outBitStream->Write(this->m_MusicCues.size()); + for (auto& musicCue : this->m_MusicCues) { + musicCue.Serialize(outBitStream); } - // Unknown part - outBitStream->Write(0); - - // GUID part - outBitStream->Write(this->guids.size()); - - for (const auto guid : this->guids) { - outBitStream->Write(guid.GetData1()); - outBitStream->Write(guid.GetData2()); - outBitStream->Write(guid.GetData3()); - for (const auto& guidSubPart : guid.GetData4()) { - outBitStream->Write(guidSubPart); - } - outBitStream->Write(1); // Unknown + outBitStream->Write(this->m_MusicParameters.size()); + for (auto& musicParam : this->m_MusicParameters) { + musicParam.Serialize(outBitStream); } - // Mixer program part - outBitStream->Write(this->mixerPrograms.size()); - for (const auto& mixerProgram : mixerPrograms) { - outBitStream->Write(mixerProgram.size()); - outBitStream->Write(mixerProgram.c_str(), mixerProgram.size()); - outBitStream->Write(1); // Unknown + outBitStream->Write(this->m_2DAmbientSounds.size()); + for (auto twoDAmbientSound : this->m_2DAmbientSounds) { + twoDAmbientSound.Serialize(outBitStream); } - dirty = false; + outBitStream->Write(this->m_3DAmbientSounds.size()); + for (auto threeDAmbientSound : this->m_3DAmbientSounds) { + threeDAmbientSound.Serialize(outBitStream); + } + + outBitStream->Write(this->m_MixerPrograms.size()); + for (auto& mixerProgram : this->m_MixerPrograms) { + mixerProgram.Serialize(outBitStream); + } + + if (!bIsInitialUpdate) this->m_Dirty = false; } } -void SoundTriggerComponent::ActivateMusicCue(const std::string& name) { - if (std::find_if(this->musicCues.begin(), this->musicCues.end(), [name](const MusicCue& musicCue) { +void SoundTriggerComponent::ActivateMusicCue(const std::string& name, float bordemTime) { + const auto musicCue = std::find_if(this->m_MusicCues.begin(), this->m_MusicCues.end(), [name](const MusicCue& musicCue) { return musicCue.name == name; - }) == this->musicCues.end()) { - this->musicCues.push_back({ - name, - 1, - -1.0f - }); - dirty = true; + } + ); + + if (musicCue == this->m_MusicCues.end()) { + this->m_MusicCues.push_back(MusicCue(name, bordemTime)); + this->m_Dirty = true; Game::entityManager->SerializeEntity(m_Parent); } } void SoundTriggerComponent::DeactivateMusicCue(const std::string& name) { - const auto musicCue = std::find_if(this->musicCues.begin(), this->musicCues.end(), [name](const MusicCue& musicCue) { + const auto musicCue = std::find_if(this->m_MusicCues.begin(), this->m_MusicCues.end(), [name](const MusicCue& musicCue) { return musicCue.name == name; - }); + } + ); - if (musicCue != this->musicCues.end()) { - this->musicCues.erase(musicCue); - dirty = true; + if (musicCue != this->m_MusicCues.end()) { + this->m_MusicCues.erase(musicCue); + this->m_Dirty = true; Game::entityManager->SerializeEntity(m_Parent); } } diff --git a/dGame/dComponents/SoundTriggerComponent.h b/dGame/dComponents/SoundTriggerComponent.h index 954d8495..6d42a2e3 100644 --- a/dGame/dComponents/SoundTriggerComponent.h +++ b/dGame/dComponents/SoundTriggerComponent.h @@ -5,55 +5,73 @@ #include "Component.h" #include "eReplicaComponentType.h" -/** - * Music that should be played by the client - */ struct MusicCue { std::string name; uint32_t result; float boredomTime; + + MusicCue(std::string name, float boredomTime = -1.0, uint32_t result = 1){ + this->name = name; + this->result = result; + this->boredomTime = boredomTime; + }; + + void Serialize(RakNet::BitStream* outBitStream); }; -/** - * Handles specific music triggers like the instruments in Red Block - * Credits to https://github.com/SimonNitzsche/OpCrux-Server/blob/master/src/Entity/Components/SoundTriggerComponent.hpp - */ +struct MusicParameter { + std::string name; + float value; + + MusicParameter(std::string name, float value = 0.0){ + this->name = name; + this->value = value; + } + + void Serialize(RakNet::BitStream* outBitStream); +}; + +struct GUIDResults{ + GUID guid; + uint32_t result; + + GUIDResults(std::string guidString, uint32_t result = 1){ + this->guid = GUID(guidString); + this->result = result; + } + + void Serialize(RakNet::BitStream* outBitStream); +}; + +struct MixerProgram{ + std::string name; + uint32_t result; + + MixerProgram(std::string name, uint32_t result = 0){ + this->name = name; + this->result = result; + } + + void Serialize(RakNet::BitStream* outBitStream); +}; + + class SoundTriggerComponent : public Component { public: static const eReplicaComponentType ComponentType = eReplicaComponentType::SOUND_TRIGGER; explicit SoundTriggerComponent(Entity* parent); - ~SoundTriggerComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - - /** - * Activates a music cue, making it played by any client in range - * @param name the name of the music to play - */ - void ActivateMusicCue(const std::string& name); - - /** - * Deactivates a music cue (if active) - * @param name name of the music to deactivate - */ + void ActivateMusicCue(const std::string& name, float bordemTime = -1.0); void DeactivateMusicCue(const std::string& name); private: - /** - * Currently active cues - */ - std::vector musicCues = {}; + std::vector m_MusicCues = {}; + std::vector m_MusicParameters = {}; + std::vector m_2DAmbientSounds = {}; + std::vector m_3DAmbientSounds = {}; + std::vector m_MixerPrograms = {}; - /** - * Currently active mixer programs - */ - std::vector mixerPrograms = {}; - - /** - * GUID found in the LDF - */ - std::vector guids = {}; - bool dirty = false; + bool m_Dirty = false; }; diff --git a/dGame/dUtilities/GUID.cpp b/dGame/dUtilities/GUID.cpp index 57f76a81..50ac8b03 100644 --- a/dGame/dUtilities/GUID.cpp +++ b/dGame/dUtilities/GUID.cpp @@ -1,6 +1,11 @@ #include "GUID.h" +namespace { + const std::string EMPTY_GUID = "{00000000-0000-0000-0000-000000000000}"; +} + GUID::GUID(const std::string& guid) { + if(guid == EMPTY_GUID) return; sscanf(guid.c_str(), "{%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx}", &this->data1, &this->data2, &this->data3, @@ -8,20 +13,13 @@ GUID::GUID(const std::string& guid) { &this->data4[4], &this->data4[5], &this->data4[6], &this->data4[7]); } -uint32_t GUID::GetData1() const { - return data1; -} - -uint16_t GUID::GetData2() const { - return data2; -} - -uint16_t GUID::GetData3() const { - return data3; -} - -std::array GUID::GetData4() const { - return data4; +void GUID::Serialize(RakNet::BitStream* outBitStream) { + outBitStream->Write(GetData1()); + outBitStream->Write(GetData2()); + outBitStream->Write(GetData3()); + for (const auto& guidSubPart : GetData4()) { + outBitStream->Write(guidSubPart); + } } GUID::GUID() = default; diff --git a/dGame/dUtilities/GUID.h b/dGame/dUtilities/GUID.h index 2d958c10..38e57a6a 100644 --- a/dGame/dUtilities/GUID.h +++ b/dGame/dUtilities/GUID.h @@ -7,10 +7,24 @@ class GUID { public: explicit GUID(); explicit GUID(const std::string& guid); - uint32_t GetData1() const; - uint16_t GetData2() const; - uint16_t GetData3() const; - std::array GetData4() const; + void Serialize(RakNet::BitStream* outBitStream); + + uint32_t GetData1() const { + return data1; + } + + uint16_t GetData2() const { + return data2; + } + + uint16_t GetData3() const { + return data3; + } + + std::array GetData4() const { + return data4; + } + private: uint32_t data1 = 0; uint16_t data2 = 0;