diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp index b46e2678b..177017201 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp @@ -35,6 +35,7 @@ ProbeRecord tempProbe; RepairRecord tempRepair; ScriptRecord tempScript; StaticRecord tempStatic; +SoundRecord tempSound; BaseOverrides tempOverrides; @@ -84,6 +85,7 @@ void RecordsDynamicFunctions::ClearRecords() noexcept WorldstateFunctions::writeWorldstate.repairRecords.clear(); WorldstateFunctions::writeWorldstate.scriptRecords.clear(); WorldstateFunctions::writeWorldstate.staticRecords.clear(); + WorldstateFunctions::writeWorldstate.soundRecords.clear(); } unsigned short RecordsDynamicFunctions::GetRecordType() noexcept @@ -398,6 +400,8 @@ void RecordsDynamicFunctions::SetRecordId(const char* id) noexcept tempScript.data.mId = id; else if (writeRecordsType == mwmp::RECORD_TYPE::STATIC) tempStatic.data.mId = id; + else if (writeRecordsType == mwmp::RECORD_TYPE::SOUND) + tempSound.data.mId = id; else LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set id for record type %i which lacks that property", writeRecordsType); } @@ -452,6 +456,8 @@ void RecordsDynamicFunctions::SetRecordBaseId(const char* baseId) noexcept tempScript.baseId = baseId; else if (writeRecordsType == mwmp::RECORD_TYPE::STATIC) tempStatic.baseId = baseId; + else if (writeRecordsType == mwmp::RECORD_TYPE::SOUND) + tempSound.baseId = baseId; else LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set baseId for record type %i which lacks that property", writeRecordsType); } @@ -1411,6 +1417,8 @@ void RecordsDynamicFunctions::SetRecordSound(const char* sound) noexcept if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) tempLight.data.mSound = sound; + else if (writeRecordsType == mwmp::RECORD_TYPE::SOUND) + tempSound.data.mSound = sound; else { LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set sound for record type %i which lacks that property", writeRecordsType); @@ -1420,6 +1428,51 @@ void RecordsDynamicFunctions::SetRecordSound(const char* sound) noexcept tempOverrides.hasSound = true; } +void RecordsDynamicFunctions::SetRecordVolume(double volume) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::SOUND) + tempSound.data.mData.mVolume = volume; + else + { + LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set sound for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasVolume = true; +} + +void RecordsDynamicFunctions::SetRecordMinRange(double minRange) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::SOUND) + tempSound.data.mData.mMinRange = minRange; + else + { + LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set sound for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasMinRange = true; +} + +void RecordsDynamicFunctions::SetRecordMaxRange(double maxRange) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::SOUND) + tempSound.data.mData.mMinRange = maxRange; + else + { + LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set sound for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasMaxRange = true; +} + void RecordsDynamicFunctions::SetRecordOpenSound(const char* sound) noexcept { unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; @@ -1718,6 +1771,12 @@ void RecordsDynamicFunctions::AddRecord() noexcept WorldstateFunctions::writeWorldstate.staticRecords.push_back(tempStatic); tempStatic = {}; } + else if (writeRecordsType == mwmp::RECORD_TYPE::SOUND) + { + tempSound.baseOverrides = tempOverrides; + WorldstateFunctions::writeWorldstate.soundRecords.push_back(tempSound); + tempSound = {}; + } effectCount = 0; tempOverrides = {}; diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp index 3c0e7180d..c36a4500a 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp @@ -99,6 +99,8 @@ {"SetRecordAIServices", RecordsDynamicFunctions::SetRecordAIServices},\ \ {"SetRecordSound", RecordsDynamicFunctions::SetRecordSound},\ + {"SetRecordMinRange", RecordsDynamicFunctions::SetRecordMinRange},\ + {"SetRecordMaxRange", RecordsDynamicFunctions::SetRecordMaxRange},\ {"SetRecordOpenSound", RecordsDynamicFunctions::SetRecordOpenSound},\ {"SetRecordCloseSound", RecordsDynamicFunctions::SetRecordCloseSound},\ \ @@ -849,6 +851,33 @@ public: */ static void SetRecordSound(const char* sound) noexcept; + /** + * \brief Set the volume of the temporary record stored on the server for the currently + * specified record type. + * + * \param volume The volume of the record. + * \return void + */ + static void SetRecordVolume(double volume) noexcept; + + /** + * \brief Set the minimum range of the temporary record stored on the server for the currently + * specified record type. + * + * \param volume The minimum range of the record. + * \return void + */ + static void SetRecordMinRange(double minRange) noexcept; + + /** + * \brief Set the maximum range of the temporary record stored on the server for the currently + * specified record type. + * + * \param volume The maximum range of the record. + * \return void + */ + static void SetRecordMaxRange(double maxRange) noexcept; + /** * \brief Set the opening sound of the temporary record stored on the server for the * currently specified record type. diff --git a/apps/openmw/mwmp/RecordHelper.cpp b/apps/openmw/mwmp/RecordHelper.cpp index 94a17a057..5a867c1b6 100644 --- a/apps/openmw/mwmp/RecordHelper.cpp +++ b/apps/openmw/mwmp/RecordHelper.cpp @@ -1461,3 +1461,49 @@ void RecordHelper::overrideRecord(const mwmp::WeaponRecord& record) if (isExistingId) world->updatePtrsWithRefId(recordData.mId); } + +void RecordHelper::overrideRecord(const mwmp::SoundRecord& record) { + const ESM::Sound& recordData = record.data; + + if (recordData.mId.empty()) + { + LOG_APPEND(TimedLog::LOG_INFO, "-- Ignoring record override with no id provided"); + return; + } + + bool isExistingId = doesRecordIdExist(recordData.mId); + MWBase::World* world = MWBase::Environment::get().getWorld(); + + if (record.baseId.empty()) + { + world->getModifiableStore().overrideRecord(recordData); + } + else if (doesRecordIdExist(record.baseId)) + { + const ESM::Sound* baseData = world->getStore().get().search(record.baseId); + ESM::Sound finalData = *baseData; + finalData.mId = recordData.mId; + + if (record.baseOverrides.hasSound) + finalData.mSound = recordData.mSound; + + if (record.baseOverrides.hasVolume) + finalData.mData.mVolume = recordData.mData.mVolume; + + if (record.baseOverrides.hasMinRange) + finalData.mData.mMinRange = recordData.mData.mMinRange; + + if (record.baseOverrides.hasMaxRange) + finalData.mData.mMaxRange = recordData.mData.mMaxRange; + + world->getModifiableStore().overrideRecord(finalData); + } + else + { + LOG_APPEND(TimedLog::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str()); + return; + } + + if (isExistingId) + world->updatePtrsWithRefId(recordData.mId); +} diff --git a/apps/openmw/mwmp/RecordHelper.hpp b/apps/openmw/mwmp/RecordHelper.hpp index 6d5c61e33..b6ca21e38 100644 --- a/apps/openmw/mwmp/RecordHelper.hpp +++ b/apps/openmw/mwmp/RecordHelper.hpp @@ -30,6 +30,7 @@ namespace RecordHelper void overrideRecord(const mwmp::SpellRecord& record); void overrideRecord(const mwmp::StaticRecord& record); void overrideRecord(const mwmp::WeaponRecord& record); + void overrideRecord(const mwmp::SoundRecord& record); template void overrideRecord(const RecordType &record) diff --git a/apps/openmw/mwmp/Worldstate.cpp b/apps/openmw/mwmp/Worldstate.cpp index 7efbcf6fc..0c5752edd 100644 --- a/apps/openmw/mwmp/Worldstate.cpp +++ b/apps/openmw/mwmp/Worldstate.cpp @@ -316,6 +316,18 @@ void Worldstate::addRecords() RecordHelper::overrideRecord(record); } } + else if (recordsType == mwmp::RECORD_TYPE::SOUND) + { + for (auto&& record : soundRecords) + { + bool hasBaseId = !record.baseId.empty(); + + LOG_APPEND(TimedLog::LOG_INFO, "- sound record %s\n-- baseId is %s", record.data.mId.c_str(), + hasBaseId ? record.baseId.c_str() : "empty"); + + RecordHelper::overrideRecord(record); + } + } } bool Worldstate::containsExploredMapTile(int cellX, int cellY) diff --git a/components/openmw-mp/Base/BaseWorldstate.hpp b/components/openmw-mp/Base/BaseWorldstate.hpp index 8810e3d4f..4c80339d5 100644 --- a/components/openmw-mp/Base/BaseWorldstate.hpp +++ b/components/openmw-mp/Base/BaseWorldstate.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -57,7 +58,8 @@ namespace mwmp SCRIPT, SPELL, STATIC, - WEAPON + WEAPON, + SOUND }; // When using an existing record as a base, this struct tracks which changes @@ -138,6 +140,10 @@ namespace mwmp bool hasCloseSound = false; bool hasScriptText = false; + + bool hasVolume = false; + bool hasMinRange = false; + bool hasMaxRange = false; }; struct ActivatorRecord @@ -307,6 +313,13 @@ namespace mwmp BaseOverrides baseOverrides; }; + struct SoundRecord + { + ESM::Sound data; + std::string baseId; + BaseOverrides baseOverrides; + }; + static const int maxImageDataSize = 1800; struct MapTile @@ -393,6 +406,7 @@ namespace mwmp std::vector probeRecords; std::vector repairRecords; std::vector scriptRecords; + std::vector soundRecords; std::vector spellRecords; std::vector staticRecords; std::vector weaponRecords; diff --git a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp index ed28b55be..6badd51dd 100644 --- a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp +++ b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp @@ -68,6 +68,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *newBitstream, bool send) worldstate->recordsCount = Utils::getVectorSize(worldstate->scriptRecords); else if (worldstate->recordsType == mwmp::RECORD_TYPE::STATIC) worldstate->recordsCount = Utils::getVectorSize(worldstate->staticRecords); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::SOUND) + worldstate->recordsCount = Utils::getVectorSize(worldstate->soundRecords); else { LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Processed invalid ID_RECORD_DYNAMIC packet about unimplemented recordsType %i", @@ -134,6 +136,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *newBitstream, bool send) Utils::resetVector(worldstate->scriptRecords, worldstate->recordsCount); else if (worldstate->recordsType == mwmp::RECORD_TYPE::STATIC) Utils::resetVector(worldstate->staticRecords, worldstate->recordsCount); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::SOUND) + Utils::resetVector(worldstate->soundRecords, worldstate->recordsCount); } if (worldstate->recordsType == mwmp::RECORD_TYPE::SPELL) @@ -847,6 +851,29 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *newBitstream, bool send) } } } + else if (worldstate->recordsType == mwmp::RECORD_TYPE::SOUND) + { + for (auto&& record : worldstate->soundRecords) + { + auto& recordData = record.data; + + RW(record.baseId, send, true); + RW(recordData.mId, send, true); + RW(recordData.mSound, send, true); + RW(recordData.mData.mVolume, send, true); + RW(recordData.mData.mMinRange, send, true); + RW(recordData.mData.mMaxRange, send, true); + + if (!record.baseId.empty()) + { + auto&& overrides = record.baseOverrides; + RW(overrides.hasSound, send); + RW(overrides.hasVolume, send); + RW(overrides.hasMinRange, send); + RW(overrides.hasMaxRange, send); + } + } + } } void PacketRecordDynamic::ProcessEffects(ESM::EffectList &effectList, bool send)