diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp index 8defb7014..129a1fd25 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp @@ -33,6 +33,7 @@ ProbeRecord tempProbe; RepairRecord tempRepair; LightRecord tempLight; CellRecord tempCell; +ScriptRecord tempScript; BaseOverrides tempOverrides; @@ -80,6 +81,7 @@ void RecordsDynamicFunctions::ClearRecords() noexcept WorldstateFunctions::writeWorldstate.repairRecords.clear(); WorldstateFunctions::writeWorldstate.lightRecords.clear(); WorldstateFunctions::writeWorldstate.cellRecords.clear(); + WorldstateFunctions::writeWorldstate.scriptRecords.clear(); } unsigned short RecordsDynamicFunctions::GetRecordType() noexcept @@ -380,6 +382,8 @@ void RecordsDynamicFunctions::SetRecordId(const char* id) noexcept tempRepair.data.mId = id; else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) tempLight.data.mId = id; + else if (writeRecordsType == mwmp::RECORD_TYPE::SCRIPT) + tempScript.data.mId = id; else LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set id for record type %i which lacks that property", writeRecordsType); } @@ -430,6 +434,8 @@ void RecordsDynamicFunctions::SetRecordBaseId(const char* baseId) noexcept tempLight.baseId = baseId; else if (writeRecordsType == mwmp::RECORD_TYPE::CELL) tempCell.baseId = baseId; + else if (writeRecordsType == mwmp::RECORD_TYPE::SCRIPT) + tempScript.baseId = baseId; else LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set baseId for record type %i which lacks that property", writeRecordsType); } @@ -1373,6 +1379,21 @@ void RecordsDynamicFunctions::SetRecordCloseSound(const char* sound) noexcept tempOverrides.hasCloseSound = true; } +void RecordsDynamicFunctions::SetRecordScriptText(const char* scriptText) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::SCRIPT) + tempScript.data.mScriptText = scriptText; + else + { + LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set close sound for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasScriptText = true; +} + void RecordsDynamicFunctions::SetRecordIdByIndex(unsigned int index, const char* id) noexcept { unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; @@ -1606,6 +1627,12 @@ void RecordsDynamicFunctions::AddRecord() noexcept WorldstateFunctions::writeWorldstate.cellRecords.push_back(tempCell); tempCell = {}; } + else if (writeRecordsType == mwmp::RECORD_TYPE::SCRIPT) + { + tempScript.baseOverrides = tempOverrides; + WorldstateFunctions::writeWorldstate.scriptRecords.push_back(tempScript); + tempScript = {}; + } effectCount = 0; tempOverrides = {}; diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp index 8160484b8..b3391bc02 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp @@ -97,6 +97,8 @@ {"SetRecordOpenSound", RecordsDynamicFunctions::SetRecordOpenSound},\ {"SetRecordCloseSound", RecordsDynamicFunctions::SetRecordCloseSound},\ \ + {"SetRecordScriptText", RecordsDynamicFunctions::SetRecordScriptText},\ + \ {"SetRecordIdByIndex", RecordsDynamicFunctions::SetRecordIdByIndex},\ {"SetRecordEnchantmentIdByIndex", RecordsDynamicFunctions::SetRecordEnchantmentIdByIndex},\ \ @@ -824,6 +826,15 @@ public: */ static void SetRecordCloseSound(const char* sound) noexcept; + /** + * \brief Set the script text of the temporary record stored on the server for the + * currently specified record type. + * + * \param sound The script text of the record. + * \return void + */ + static void SetRecordScriptText(const char* scriptText) noexcept; + /** * \brief Set the id of the record at a certain index in the records stored on the server. * diff --git a/apps/openmw/mwmp/RecordHelper.cpp b/apps/openmw/mwmp/RecordHelper.cpp index 90214f913..2b1a1d45f 100644 --- a/apps/openmw/mwmp/RecordHelper.cpp +++ b/apps/openmw/mwmp/RecordHelper.cpp @@ -1185,6 +1185,40 @@ void RecordHelper::overrideRecord(const mwmp::RepairRecord& record) world->updatePtrsWithRefId(recordData.mId); } +void RecordHelper::overrideRecord(const mwmp::ScriptRecord& record) +{ + const ESM::Script &recordData = record.data; + + if (recordData.mId.empty()) + { + LOG_APPEND(TimedLog::LOG_INFO, "-- Ignoring record override with no id provided"); + return; + } + + MWBase::World *world = MWBase::Environment::get().getWorld(); + + if (record.baseId.empty()) + { + world->getModifiableStore().overrideRecord(recordData); + } + else if (doesRecordIdExist(record.baseId)) + { + const ESM::Script *baseData = world->getStore().get().search(record.baseId); + ESM::Script finalData = *baseData; + finalData.mId = recordData.mId; + + if (record.baseOverrides.hasScriptText) + finalData.mScriptText = recordData.mScriptText; + + world->getModifiableStore().overrideRecord(finalData); + } + else + { + LOG_APPEND(TimedLog::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str()); + return; + } +} + void RecordHelper::overrideRecord(const mwmp::SpellRecord& record) { const ESM::Spell &recordData = record.data; diff --git a/apps/openmw/mwmp/RecordHelper.hpp b/apps/openmw/mwmp/RecordHelper.hpp index 5e7655c3a..fdad79844 100644 --- a/apps/openmw/mwmp/RecordHelper.hpp +++ b/apps/openmw/mwmp/RecordHelper.hpp @@ -25,6 +25,7 @@ namespace RecordHelper void overrideRecord(const mwmp::PotionRecord& record); void overrideRecord(const mwmp::ProbeRecord& record); void overrideRecord(const mwmp::RepairRecord& record); + void overrideRecord(const mwmp::ScriptRecord& record); void overrideRecord(const mwmp::SpellRecord& record); void overrideRecord(const mwmp::StaticRecord& record); void overrideRecord(const mwmp::WeaponRecord& record); diff --git a/apps/openmw/mwmp/Worldstate.cpp b/apps/openmw/mwmp/Worldstate.cpp index 23e4dcd12..8e0d413cb 100644 --- a/apps/openmw/mwmp/Worldstate.cpp +++ b/apps/openmw/mwmp/Worldstate.cpp @@ -292,6 +292,18 @@ void Worldstate::addRecords() RecordHelper::overrideRecord(record); } } + else if (recordsType == mwmp::RECORD_TYPE::SCRIPT) + { + for (auto &&record : scriptRecords) + { + bool hasBaseId = !record.baseId.empty(); + + LOG_APPEND(TimedLog::LOG_INFO, "- script 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 fa6842c81..f0af1a0db 100644 --- a/components/openmw-mp/Base/BaseWorldstate.hpp +++ b/components/openmw-mp/Base/BaseWorldstate.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +53,8 @@ namespace mwmp PROBE, REPAIR, LIGHT, - CELL + CELL, + SCRIPT }; // When using an existing record as a base, this struct tracks which changes @@ -125,6 +127,8 @@ namespace mwmp bool hasSound = false; bool hasOpenSound = false; bool hasCloseSound = false; + + bool hasScriptText = false; }; struct ActivatorRecord @@ -258,6 +262,13 @@ namespace mwmp BaseOverrides baseOverrides; }; + struct ScriptRecord + { + ESM::Script data; + std::string baseId; + BaseOverrides baseOverrides; + }; + struct SpellRecord { ESM::Spell data; @@ -360,6 +371,7 @@ namespace mwmp std::vector potionRecords; std::vector probeRecords; std::vector repairRecords; + std::vector scriptRecords; 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 c2f6a69c8..ebd80802d 100644 --- a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp +++ b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp @@ -62,6 +62,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) worldstate->recordsCount = Utils::getVectorSize(worldstate->lightRecords); else if (worldstate->recordsType == mwmp::RECORD_TYPE::CELL) worldstate->recordsCount = Utils::getVectorSize(worldstate->cellRecords); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::SCRIPT) + worldstate->recordsCount = Utils::getVectorSize(worldstate->scriptRecords); else { LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Processed invalid ID_RECORD_DYNAMIC packet about unimplemented recordsType %i", @@ -124,6 +126,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) Utils::resetVector(worldstate->lightRecords, worldstate->recordsCount); else if (worldstate->recordsType == mwmp::RECORD_TYPE::CELL) Utils::resetVector(worldstate->cellRecords, worldstate->recordsCount); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::SCRIPT) + Utils::resetVector(worldstate->scriptRecords, worldstate->recordsCount); } if (worldstate->recordsType == mwmp::RECORD_TYPE::SPELL) @@ -784,7 +788,24 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) auto &recordData = record.data; RW(record.baseId, send, true); - RW(record.data.mName, send, true); + RW(recordData.mName, send, true); + } + } + else if (worldstate->recordsType == mwmp::RECORD_TYPE::SCRIPT) + { + for (auto &&record : worldstate->scriptRecords) + { + auto &recordData = record.data; + + RW(record.baseId, send, true); + RW(recordData.mId, send, true); + RW(recordData.mScriptText, send, true); + + if (!record.baseId.empty()) + { + auto &&overrides = record.baseOverrides; + RW(overrides.hasScriptText, send); + } } } }