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 <EmosewaMC@gmail.com>
This commit is contained in:
Aaron Kimbrell 2023-08-06 15:38:12 -05:00 committed by GitHub
parent 7e2747a2d2
commit cefdfc696a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 188 additions and 113 deletions

View File

@ -71,6 +71,7 @@
#include "ShootingGalleryComponent.h" #include "ShootingGalleryComponent.h"
#include "RailActivatorComponent.h" #include "RailActivatorComponent.h"
#include "LUPExhibitComponent.h" #include "LUPExhibitComponent.h"
#include "RacingSoundTriggerComponent.h"
#include "TriggerComponent.h" #include "TriggerComponent.h"
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
@ -318,6 +319,9 @@ void Entity::Initialize() {
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) { if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) {
auto* comp = new SoundTriggerComponent(this); auto* comp = new SoundTriggerComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::SOUND_TRIGGER, comp)); 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: //Also check for the collectible id:
@ -1060,6 +1064,11 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags); soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
} }
RacingSoundTriggerComponent* racingSoundTriggerComponent;
if (TryGetComponent(eReplicaComponentType::RACING_SOUND_TRIGGER, racingSoundTriggerComponent)) {
racingSoundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
}
BuffComponent* buffComponent; BuffComponent* buffComponent;
if (TryGetComponent(eReplicaComponentType::BUFF, buffComponent)) { if (TryGetComponent(eReplicaComponentType::BUFF, buffComponent)) {
buffComponent->Serialize(outBitStream, bIsInitialUpdate, flags); buffComponent->Serialize(outBitStream, bIsInitialUpdate, flags);

View File

@ -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__

View File

@ -1,93 +1,114 @@
#include "SoundTriggerComponent.h" #include "SoundTriggerComponent.h"
#include "EntityManager.h"
#include "Game.h" #include "Game.h"
#include "dLogger.h"
void MusicCue::Serialize(RakNet::BitStream* outBitStream){
outBitStream->Write<uint8_t>(name.size());
outBitStream->Write(name.c_str(), name.size());
outBitStream->Write(result);
outBitStream->Write(boredomTime);
}
void MusicParameter::Serialize(RakNet::BitStream* outBitStream){
outBitStream->Write<uint8_t>(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<uint8_t>(name.size());
outBitStream->Write(name.c_str(), name.size());
outBitStream->Write(result);
}
SoundTriggerComponent::SoundTriggerComponent(Entity* parent) : Component(parent) { SoundTriggerComponent::SoundTriggerComponent(Entity* parent) : Component(parent) {
const auto musicCueName = parent->GetVar<std::string>(u"NDAudioMusicCue_Name"); const auto musicCueName = parent->GetVar<std::string>(u"NDAudioMusicCue_Name");
const auto musicCueBoredomTime = parent->GetVar<float>(u"NDAudioMusicCue_BoredomTime"); if (!musicCueName.empty()) {
auto newCue = MusicCue(musicCueName);
const auto musicCueBoredomTime = parent->GetVar<float>(u"NDAudioMusicCue_BoredomTime");
if (musicCueBoredomTime) newCue.boredomTime = musicCueBoredomTime;
this->m_MusicCues.push_back(newCue);
}
this->musicCues.push_back({ const auto musicParameterName = parent->GetVar<std::string>(u"NDAudioMusicParameter_Name");
musicCueName, if (!musicParameterName.empty()) {
1, auto newParams = MusicParameter(musicParameterName);
musicCueBoredomTime const auto musicParameterValue = parent->GetVar<float>(u"NDAudioMusicParameter_Value");
}); if (musicParameterValue) newParams.value = musicParameterValue;
this->m_MusicParameters.push_back(newParams);
}
const auto mixerName = parent->GetVar<std::string>(u"NDAudioMixerProgram_Name"); const auto guidString = parent->GetVar<std::string>(u"NDAudioEventGUID");
this->mixerPrograms.push_back(mixerName); if (!guidString.empty())
this->m_2DAmbientSounds.push_back(GUIDResults(guidString));
const auto guid2String = parent->GetVar<std::string>(u"NDAudioEventGUID2"); const auto guid2String = parent->GetVar<std::string>(u"NDAudioEventGUID2");
if (!guid2String.empty()) { if (!guid2String.empty())
this->guids.emplace_back(guid2String); this->m_3DAmbientSounds.push_back(GUIDResults(guid2String));
}
}
SoundTriggerComponent::~SoundTriggerComponent() = default; const auto mixerName = parent->GetVar<std::string>(u"NDAudioMixerProgram_Name");
if (!mixerName.empty()) this->m_MixerPrograms.push_back(MixerProgram(mixerName));
}
void SoundTriggerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { void SoundTriggerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
if (bIsInitialUpdate) outBitStream->Write(this->m_Dirty || bIsInitialUpdate);
dirty = true; if (this->m_Dirty || bIsInitialUpdate) {
outBitStream->Write<uint8_t>(this->m_MusicCues.size());
outBitStream->Write(dirty); for (auto& musicCue : this->m_MusicCues) {
musicCue.Serialize(outBitStream);
if (dirty) {
outBitStream->Write<uint8_t>(this->musicCues.size());
for (const auto& musicCue : this->musicCues) {
outBitStream->Write<uint8_t>(musicCue.name.size());
outBitStream->Write(musicCue.name.c_str(), musicCue.name.size());
outBitStream->Write<uint32_t>(musicCue.result);
outBitStream->Write<float_t>(musicCue.boredomTime);
} }
// Unknown part outBitStream->Write<uint8_t>(this->m_MusicParameters.size());
outBitStream->Write<uint16_t>(0); for (auto& musicParam : this->m_MusicParameters) {
musicParam.Serialize(outBitStream);
// GUID part
outBitStream->Write<uint8_t>(this->guids.size());
for (const auto guid : this->guids) {
outBitStream->Write<uint32_t>(guid.GetData1());
outBitStream->Write<uint16_t>(guid.GetData2());
outBitStream->Write<uint16_t>(guid.GetData3());
for (const auto& guidSubPart : guid.GetData4()) {
outBitStream->Write<uint8_t>(guidSubPart);
}
outBitStream->Write<uint32_t>(1); // Unknown
} }
// Mixer program part outBitStream->Write<uint8_t>(this->m_2DAmbientSounds.size());
outBitStream->Write<uint8_t>(this->mixerPrograms.size()); for (auto twoDAmbientSound : this->m_2DAmbientSounds) {
for (const auto& mixerProgram : mixerPrograms) { twoDAmbientSound.Serialize(outBitStream);
outBitStream->Write<uint8_t>(mixerProgram.size());
outBitStream->Write(mixerProgram.c_str(), mixerProgram.size());
outBitStream->Write<uint32_t>(1); // Unknown
} }
dirty = false; outBitStream->Write<uint8_t>(this->m_3DAmbientSounds.size());
for (auto threeDAmbientSound : this->m_3DAmbientSounds) {
threeDAmbientSound.Serialize(outBitStream);
}
outBitStream->Write<uint8_t>(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) { void SoundTriggerComponent::ActivateMusicCue(const std::string& name, float bordemTime) {
if (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; return musicCue.name == name;
}) == this->musicCues.end()) { }
this->musicCues.push_back({ );
name,
1, if (musicCue == this->m_MusicCues.end()) {
-1.0f this->m_MusicCues.push_back(MusicCue(name, bordemTime));
}); this->m_Dirty = true;
dirty = true;
Game::entityManager->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
} }
void SoundTriggerComponent::DeactivateMusicCue(const std::string& name) { 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; return musicCue.name == name;
}); }
);
if (musicCue != this->musicCues.end()) { if (musicCue != this->m_MusicCues.end()) {
this->musicCues.erase(musicCue); this->m_MusicCues.erase(musicCue);
dirty = true; this->m_Dirty = true;
Game::entityManager->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
} }

View File

@ -5,55 +5,73 @@
#include "Component.h" #include "Component.h"
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
/**
* Music that should be played by the client
*/
struct MusicCue { struct MusicCue {
std::string name; std::string name;
uint32_t result; uint32_t result;
float boredomTime; 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);
}; };
/** struct MusicParameter {
* Handles specific music triggers like the instruments in Red Block std::string name;
* Credits to https://github.com/SimonNitzsche/OpCrux-Server/blob/master/src/Entity/Components/SoundTriggerComponent.hpp 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 { class SoundTriggerComponent : public Component {
public: public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::SOUND_TRIGGER; static const eReplicaComponentType ComponentType = eReplicaComponentType::SOUND_TRIGGER;
explicit SoundTriggerComponent(Entity* parent); explicit SoundTriggerComponent(Entity* parent);
~SoundTriggerComponent() override;
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
void ActivateMusicCue(const std::string& name, float bordemTime = -1.0);
/**
* 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 DeactivateMusicCue(const std::string& name); void DeactivateMusicCue(const std::string& name);
private: private:
/** std::vector<MusicCue> m_MusicCues = {};
* Currently active cues std::vector<MusicParameter> m_MusicParameters = {};
*/ std::vector<GUIDResults> m_2DAmbientSounds = {};
std::vector<MusicCue> musicCues = {}; std::vector<GUIDResults> m_3DAmbientSounds = {};
std::vector<MixerProgram> m_MixerPrograms = {};
/** bool m_Dirty = false;
* Currently active mixer programs
*/
std::vector<std::string> mixerPrograms = {};
/**
* GUID found in the LDF
*/
std::vector<GUID> guids = {};
bool dirty = false;
}; };

View File

@ -1,6 +1,11 @@
#include "GUID.h" #include "GUID.h"
namespace {
const std::string EMPTY_GUID = "{00000000-0000-0000-0000-000000000000}";
}
GUID::GUID(const std::string& guid) { GUID::GUID(const std::string& guid) {
if(guid == EMPTY_GUID) return;
sscanf(guid.c_str(), sscanf(guid.c_str(),
"{%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx}", "{%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx}",
&this->data1, &this->data2, &this->data3, &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]); &this->data4[4], &this->data4[5], &this->data4[6], &this->data4[7]);
} }
uint32_t GUID::GetData1() const { void GUID::Serialize(RakNet::BitStream* outBitStream) {
return data1; outBitStream->Write(GetData1());
} outBitStream->Write(GetData2());
outBitStream->Write(GetData3());
uint16_t GUID::GetData2() const { for (const auto& guidSubPart : GetData4()) {
return data2; outBitStream->Write(guidSubPart);
} }
uint16_t GUID::GetData3() const {
return data3;
}
std::array<uint8_t, 8> GUID::GetData4() const {
return data4;
} }
GUID::GUID() = default; GUID::GUID() = default;

View File

@ -7,10 +7,24 @@ class GUID {
public: public:
explicit GUID(); explicit GUID();
explicit GUID(const std::string& guid); explicit GUID(const std::string& guid);
uint32_t GetData1() const; void Serialize(RakNet::BitStream* outBitStream);
uint16_t GetData2() const;
uint16_t GetData3() const; uint32_t GetData1() const {
std::array<uint8_t, 8> GetData4() const; return data1;
}
uint16_t GetData2() const {
return data2;
}
uint16_t GetData3() const {
return data3;
}
std::array<uint8_t, 8> GetData4() const {
return data4;
}
private: private:
uint32_t data1 = 0; uint32_t data1 = 0;
uint16_t data2 = 0; uint16_t data2 = 0;