From e9336e53fce592ae07b96b208c94b92f9b341636 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 27 Jul 2019 03:45:50 +0300 Subject: [PATCH] [General] Implement container and door records for RecordDynamic packets --- .../Script/Functions/RecordsDynamic.cpp | 69 ++++++++- .../Script/Functions/RecordsDynamic.hpp | 21 +++ apps/openmw/mwmp/RecordHelper.cpp | 131 ++++++++++++++++++ apps/openmw/mwmp/RecordHelper.hpp | 9 ++ apps/openmw/mwmp/Worldstate.cpp | 24 ++++ components/openmw-mp/Base/BaseWorldstate.hpp | 26 +++- .../Worldstate/PacketRecordDynamic.cpp | 60 ++++++++ 7 files changed, 338 insertions(+), 2 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp index 8da37aa24..b7842da5a 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp @@ -22,6 +22,8 @@ BookRecord tempBook; ClothingRecord tempClothing; MiscellaneousRecord tempMiscellaneous; WeaponRecord tempWeapon; +ContainerRecord tempContainer; +DoorRecord tempDoor; BaseOverrides tempOverrides; @@ -337,7 +339,10 @@ void RecordsDynamicFunctions::SetRecordId(const char* id) noexcept tempMiscellaneous.data.mId = id; else if (writeRecordsType == mwmp::RECORD_TYPE::WEAPON) tempWeapon.data.mId = id; - + else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) + tempContainer.data.mId = id; + else if (writeRecordsType == mwmp::RECORD_TYPE::DOOR) + tempDoor.data.mId = id; else LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set id for record type %i which lacks that property", writeRecordsType); } @@ -366,6 +371,10 @@ void RecordsDynamicFunctions::SetRecordBaseId(const char* baseId) noexcept tempMiscellaneous.baseId = baseId; else if (writeRecordsType == mwmp::RECORD_TYPE::WEAPON) tempWeapon.baseId = baseId; + else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) + tempContainer.baseId = baseId; + else if (writeRecordsType == mwmp::RECORD_TYPE::DOOR) + tempDoor.baseId = baseId; else LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set baseId for record type %i which lacks that property", writeRecordsType); } @@ -429,6 +438,10 @@ void RecordsDynamicFunctions::SetRecordName(const char* name) noexcept tempMiscellaneous.data.mName = name; else if (writeRecordsType == mwmp::RECORD_TYPE::WEAPON) tempWeapon.data.mName = name; + else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) + tempContainer.data.mName = name; + else if (writeRecordsType == mwmp::RECORD_TYPE::DOOR) + tempDoor.data.mName = name; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set name for record type %i which lacks that property", writeRecordsType); @@ -458,6 +471,10 @@ void RecordsDynamicFunctions::SetRecordModel(const char* model) noexcept tempMiscellaneous.data.mModel = model; else if (writeRecordsType == mwmp::RECORD_TYPE::WEAPON) tempWeapon.data.mModel = model; + else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) + tempContainer.data.mModel = model; + else if (writeRecordsType == mwmp::RECORD_TYPE::DOOR) + tempDoor.data.mModel = model; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set model for record type %i which lacks that property", writeRecordsType); @@ -512,6 +529,10 @@ void RecordsDynamicFunctions::SetRecordScript(const char* script) noexcept tempMiscellaneous.data.mScript = script; else if (writeRecordsType == mwmp::RECORD_TYPE::WEAPON) tempWeapon.data.mScript = script; + else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) + tempContainer.data.mScript = script; + else if (writeRecordsType == mwmp::RECORD_TYPE::DOOR) + tempDoor.data.mScript = script; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set script for record type %i which lacks that property", writeRecordsType); @@ -687,6 +708,8 @@ void RecordsDynamicFunctions::SetRecordWeight(double weight) noexcept tempMiscellaneous.data.mData.mWeight = weight; else if (writeRecordsType == mwmp::RECORD_TYPE::WEAPON) tempWeapon.data.mData.mWeight = weight; + else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) + tempContainer.data.mWeight = weight; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set weight for record type %i which lacks that property", writeRecordsType); @@ -1026,6 +1049,36 @@ void RecordsDynamicFunctions::SetRecordAIFight(int aiFight) noexcept tempOverrides.hasAiFight = true; } +void RecordsDynamicFunctions::SetRecordOpenSound(const char* sound) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::DOOR) + tempDoor.data.mOpenSound = sound; + else + { + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set open sound for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasOpenSound = true; +} + +void RecordsDynamicFunctions::SetRecordCloseSound(const char* sound) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::DOOR) + tempDoor.data.mCloseSound = sound; + else + { + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set close sound for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasCloseSound = true; +} + void RecordsDynamicFunctions::SetRecordIdByIndex(unsigned int index, const char* id) noexcept { unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; @@ -1193,6 +1246,18 @@ void RecordsDynamicFunctions::AddRecord() noexcept WorldstateFunctions::writeWorldstate.weaponRecords.push_back(tempWeapon); tempWeapon = {}; } + else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) + { + tempContainer.baseOverrides = tempOverrides; + WorldstateFunctions::writeWorldstate.containerRecords.push_back(tempContainer); + tempContainer = {}; + } + else if (writeRecordsType == mwmp::RECORD_TYPE::DOOR) + { + tempDoor.baseOverrides = tempOverrides; + WorldstateFunctions::writeWorldstate.doorRecords.push_back(tempDoor); + tempDoor = {}; + } tempOverrides = {}; } @@ -1233,6 +1298,8 @@ void RecordsDynamicFunctions::AddRecordInventoryItem() noexcept tempCreature.inventory.push_back(tempInventoryItem); else if (writeRecordsType == mwmp::RECORD_TYPE::NPC) tempNpc.inventory.push_back(tempInventoryItem); + else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) + tempContainer.inventory.push_back(tempInventoryItem); tempOverrides.hasInventory = true; tempInventoryItem = {}; diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp index 4e858f1b1..0fc633549 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp @@ -84,6 +84,9 @@ {"SetRecordFatigue", RecordsDynamicFunctions::SetRecordFatigue},\ {"SetRecordAIFight", RecordsDynamicFunctions::SetRecordAIFight},\ \ + {"SetRecordOpenSound", RecordsDynamicFunctions::SetRecordOpenSound},\ + {"SetRecordCloseSound", RecordsDynamicFunctions::SetRecordCloseSound},\ + \ {"SetRecordIdByIndex", RecordsDynamicFunctions::SetRecordIdByIndex},\ {"SetRecordEnchantmentIdByIndex", RecordsDynamicFunctions::SetRecordEnchantmentIdByIndex},\ \ @@ -712,6 +715,24 @@ public: */ static void SetRecordAIFight(int aiFight) noexcept; + /** + * \brief Set the opening sound of the temporary record stored on the server for the + * currently specified record type. + * + * \param sound The opening sound of the record. + * \return void + */ + static void SetRecordOpenSound(const char* sound) noexcept; + + /** + * \brief Set the closing sound of the temporary record stored on the server for the + * currently specified record type. + * + * \param sound The closing sound of the record. + * \return void + */ + static void SetRecordCloseSound(const char* sound) 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 5bbbccb51..c99c40ddb 100644 --- a/apps/openmw/mwmp/RecordHelper.cpp +++ b/apps/openmw/mwmp/RecordHelper.cpp @@ -90,6 +90,20 @@ bool RecordHelper::doesWeaponRecordExist(const std::string& id) return world->getStore().get().search(id); } +bool RecordHelper::doesContainerRecordExist(const std::string& id) +{ + MWBase::World *world = MWBase::Environment::get().getWorld(); + + return world->getStore().get().search(id); +} + +bool RecordHelper::doesDoorRecordExist(const std::string& id) +{ + MWBase::World *world = MWBase::Environment::get().getWorld(); + + return world->getStore().get().search(id); +} + std::string RecordHelper::createCreatureRecord(const ESM::Creature& record) { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -843,6 +857,109 @@ void RecordHelper::overrideWeaponRecord(const mwmp::WeaponRecord& record) world->updatePtrsWithRefId(recordData.mId); } +void RecordHelper::overrideContainerRecord(const mwmp::ContainerRecord& record) +{ + const ESM::Container &recordData = record.data; + + if (recordData.mId.empty()) + { + LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided"); + return; + } + + bool isExistingId = doesContainerRecordExist(recordData.mId); + MWBase::World *world = MWBase::Environment::get().getWorld(); + + if (record.baseId.empty()) + { + world->getModifiableStore().overrideRecord(recordData); + } + else if (doesContainerRecordExist(record.baseId)) + { + const ESM::Container *baseData = world->getStore().get().search(record.baseId); + ESM::Container finalData = *baseData; + finalData.mId = recordData.mId; + + if (record.baseOverrides.hasName) + finalData.mName = recordData.mName; + + if (record.baseOverrides.hasModel) + finalData.mModel = recordData.mModel; + + if (record.baseOverrides.hasWeight) + finalData.mWeight = recordData.mWeight; + + if (record.baseOverrides.hasFlags) + finalData.mFlags = recordData.mFlags; + + if (record.baseOverrides.hasScript) + finalData.mScript = recordData.mScript; + + if (record.baseOverrides.hasInventory) + finalData.mInventory.mList = recordData.mInventory.mList; + + world->getModifiableStore().overrideRecord(finalData); + } + else + { + LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str()); + return; + } + + if (isExistingId) + world->updatePtrsWithRefId(recordData.mId); +} + +void RecordHelper::overrideDoorRecord(const mwmp::DoorRecord& record) +{ + const ESM::Door &recordData = record.data; + + if (recordData.mId.empty()) + { + LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided"); + return; + } + + bool isExistingId = doesDoorRecordExist(recordData.mId); + MWBase::World *world = MWBase::Environment::get().getWorld(); + + if (record.baseId.empty()) + { + world->getModifiableStore().overrideRecord(recordData); + } + else if (doesDoorRecordExist(record.baseId)) + { + const ESM::Door *baseData = world->getStore().get().search(record.baseId); + ESM::Door finalData = *baseData; + finalData.mId = recordData.mId; + + if (record.baseOverrides.hasName) + finalData.mName = recordData.mName; + + if (record.baseOverrides.hasModel) + finalData.mModel = recordData.mModel; + + if (record.baseOverrides.hasOpenSound) + finalData.mOpenSound = recordData.mOpenSound; + + if (record.baseOverrides.hasCloseSound) + finalData.mCloseSound = recordData.mCloseSound; + + if (record.baseOverrides.hasScript) + finalData.mScript = recordData.mScript; + + world->getModifiableStore().overrideRecord(finalData); + } + else + { + LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with invalid baseId %s", record.baseId.c_str()); + return; + } + + if (isExistingId) + world->updatePtrsWithRefId(recordData.mId); +} + void RecordHelper::overrideCreatureRecord(const ESM::Creature& record) { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -912,3 +1029,17 @@ void RecordHelper::overrideWeaponRecord(const ESM::Weapon& record) world->getModifiableStore().overrideRecord(record); } + +void RecordHelper::overrideContainerRecord(const ESM::Container& record) +{ + MWBase::World *world = MWBase::Environment::get().getWorld(); + + world->getModifiableStore().overrideRecord(record); +} + +void RecordHelper::overrideDoorRecord(const ESM::Door& record) +{ + MWBase::World *world = MWBase::Environment::get().getWorld(); + + world->getModifiableStore().overrideRecord(record); +} diff --git a/apps/openmw/mwmp/RecordHelper.hpp b/apps/openmw/mwmp/RecordHelper.hpp index 222f3f47b..9f4e1ffd7 100644 --- a/apps/openmw/mwmp/RecordHelper.hpp +++ b/apps/openmw/mwmp/RecordHelper.hpp @@ -24,6 +24,9 @@ namespace RecordHelper bool doesMiscellaneousRecordExist(const std::string& id); bool doesWeaponRecordExist(const std::string& id); + bool doesContainerRecordExist(const std::string& id); + bool doesDoorRecordExist(const std::string& id); + std::string createCreatureRecord(const ESM::Creature& record); std::string createNpcRecord(const ESM::NPC& record); @@ -40,6 +43,9 @@ namespace RecordHelper void overrideMiscellaneousRecord(const mwmp::MiscellaneousRecord& record); void overrideWeaponRecord(const mwmp::WeaponRecord& record); + void overrideContainerRecord(const mwmp::ContainerRecord& record); + void overrideDoorRecord(const mwmp::DoorRecord& record); + void overrideCreatureRecord(const ESM::Creature& record); void overrideNpcRecord(const ESM::NPC& record); @@ -52,6 +58,9 @@ namespace RecordHelper void overrideClothingRecord(const ESM::Clothing& record); void overrideMiscellaneousRecord(const ESM::Miscellaneous& record); void overrideWeaponRecord(const ESM::Weapon& record); + + void overrideContainerRecord(const ESM::Container& record); + void overrideDoorRecord(const ESM::Door& record); } diff --git a/apps/openmw/mwmp/Worldstate.cpp b/apps/openmw/mwmp/Worldstate.cpp index cf2bda79f..5e47892b5 100644 --- a/apps/openmw/mwmp/Worldstate.cpp +++ b/apps/openmw/mwmp/Worldstate.cpp @@ -158,6 +158,30 @@ void Worldstate::addRecords() RecordHelper::overrideWeaponRecord(record); } } + else if (recordsType == mwmp::RECORD_TYPE::CONTAINER) + { + for (auto &&record : containerRecords) + { + bool hasBaseId = !record.baseId.empty(); + + LOG_APPEND(Log::LOG_INFO, "- container record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(), + hasBaseId ? record.baseId.c_str() : "empty"); + + RecordHelper::overrideContainerRecord(record); + } + } + else if (recordsType == mwmp::RECORD_TYPE::DOOR) + { + for (auto &&record : doorRecords) + { + bool hasBaseId = !record.baseId.empty(); + + LOG_APPEND(Log::LOG_INFO, "- door record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(), + hasBaseId ? record.baseId.c_str() : "empty"); + + RecordHelper::overrideDoorRecord(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 8860a0ec8..fc07ef964 100644 --- a/components/openmw-mp/Base/BaseWorldstate.hpp +++ b/components/openmw-mp/Base/BaseWorldstate.hpp @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -31,7 +33,9 @@ namespace mwmp NPC, POTION, SPELL, - WEAPON + WEAPON, + CONTAINER, + DOOR }; // When using an existing record as a base, this struct tracks which changes @@ -91,6 +95,9 @@ namespace mwmp bool hasMagicka = false; bool hasFatigue = false; bool hasAiFight = false; + + bool hasOpenSound = false; + bool hasCloseSound = false; }; struct ArmorRecord @@ -114,6 +121,14 @@ namespace mwmp BaseOverrides baseOverrides; }; + struct ContainerRecord + { + ESM::Container data; + std::string baseId; + std::vector inventory; + BaseOverrides baseOverrides; + }; + struct CreatureRecord { ESM::Creature data; @@ -123,6 +138,13 @@ namespace mwmp BaseOverrides baseOverrides; }; + struct DoorRecord + { + ESM::Door data; + std::string baseId; + BaseOverrides baseOverrides; + }; + struct EnchantmentRecord { ESM::Enchantment data; @@ -224,7 +246,9 @@ namespace mwmp std::vector armorRecords; std::vector bookRecords; std::vector clothingRecords; + std::vector containerRecords; std::vector creatureRecords; + std::vector doorRecords; std::vector enchantmentRecords; std::vector miscellaneousRecords; std::vector npcRecords; diff --git a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp index f3d6600c6..0d548f648 100644 --- a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp +++ b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp @@ -40,6 +40,10 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) worldstate->recordsCount = Utils::getVectorSize(worldstate->miscellaneousRecords); else if (worldstate->recordsType == mwmp::RECORD_TYPE::WEAPON) worldstate->recordsCount = Utils::getVectorSize(worldstate->weaponRecords); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::CONTAINER) + worldstate->recordsCount = Utils::getVectorSize(worldstate->containerRecords); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::DOOR) + worldstate->recordsCount = Utils::getVectorSize(worldstate->doorRecords); else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Processed invalid ID_RECORD_DYNAMIC packet about unimplemented recordsType %i", @@ -80,6 +84,10 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) Utils::resetVector(worldstate->miscellaneousRecords, worldstate->recordsCount); else if (worldstate->recordsType == mwmp::RECORD_TYPE::WEAPON) Utils::resetVector(worldstate->weaponRecords, worldstate->recordsCount); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::CONTAINER) + Utils::resetVector(worldstate->containerRecords, worldstate->recordsCount); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::DOOR) + Utils::resetVector(worldstate->doorRecords, worldstate->recordsCount); } if (worldstate->recordsType == mwmp::RECORD_TYPE::SPELL) @@ -438,6 +446,58 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) } } } + else if (worldstate->recordsType == mwmp::RECORD_TYPE::CONTAINER) + { + for (auto &&record : worldstate->containerRecords) + { + auto &recordData = record.data; + + RW(record.baseId, send, true); + RW(recordData.mId, send, true); + RW(recordData.mName, send, true); + RW(recordData.mModel, send, true); + RW(recordData.mWeight, send); + RW(recordData.mFlags, send); + RW(recordData.mScript, send, true); + ProcessInventoryList(record.inventory, recordData.mInventory, send); + + if (!record.baseId.empty()) + { + auto &&overrides = record.baseOverrides; + RW(overrides.hasName, send); + RW(overrides.hasModel, send); + RW(overrides.hasWeight, send); + RW(overrides.hasFlags, send); + RW(overrides.hasScript, send); + RW(overrides.hasInventory, send); + } + } + } + else if (worldstate->recordsType == mwmp::RECORD_TYPE::DOOR) + { + for (auto &&record : worldstate->doorRecords) + { + auto &recordData = record.data; + + RW(record.baseId, send, true); + RW(recordData.mId, send, true); + RW(recordData.mName, send, true); + RW(recordData.mModel, send, true); + RW(recordData.mOpenSound, send, true); + RW(recordData.mCloseSound, send, true); + RW(recordData.mScript, send, true); + + if (!record.baseId.empty()) + { + auto &&overrides = record.baseOverrides; + RW(overrides.hasName, send); + RW(overrides.hasModel, send); + RW(overrides.hasOpenSound, send); + RW(overrides.hasCloseSound, send); + RW(overrides.hasScript, send); + } + } + } } void PacketRecordDynamic::ProcessEffects(ESM::EffectList &effectList, bool send)