From 23d410f4736dce1af01f6a94bc62b2570b9f91d6 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 29 Nov 2019 14:06:17 +0200 Subject: [PATCH] [General] Implement body part records for RecordDynamic packet --- .../Script/Functions/RecordsDynamic.cpp | 55 +++++++++++++++++-- .../Script/Functions/RecordsDynamic.hpp | 14 ++++- apps/openmw/mwmp/RecordHelper.cpp | 49 +++++++++++++++++ apps/openmw/mwmp/RecordHelper.hpp | 1 + apps/openmw/mwmp/Worldstate.cpp | 12 ++++ components/openmw-mp/Base/BaseWorldstate.hpp | 14 ++++- .../Worldstate/PacketRecordDynamic.cpp | 33 ++++++++++- 7 files changed, 169 insertions(+), 9 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp index d1991abe9..2d1fcf10c 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp @@ -34,12 +34,13 @@ RepairRecord tempRepair; LightRecord tempLight; CellRecord tempCell; ScriptRecord tempScript; +BodyPartRecord tempBodyPart; BaseOverrides tempOverrides; unsigned int effectCount = 0; ESM::ENAMstruct tempEffect; -ESM::PartReference tempBodyPart; +ESM::PartReference tempBodyPartReference; mwmp::Item tempInventoryItem; const ESM::EffectList emptyEffectList = {}; @@ -82,6 +83,7 @@ void RecordsDynamicFunctions::ClearRecords() noexcept WorldstateFunctions::writeWorldstate.lightRecords.clear(); WorldstateFunctions::writeWorldstate.cellRecords.clear(); WorldstateFunctions::writeWorldstate.scriptRecords.clear(); + WorldstateFunctions::writeWorldstate.bodyPartRecords.clear(); } unsigned short RecordsDynamicFunctions::GetRecordType() noexcept @@ -384,6 +386,8 @@ void RecordsDynamicFunctions::SetRecordId(const char* id) noexcept tempLight.data.mId = id; else if (writeRecordsType == mwmp::RECORD_TYPE::SCRIPT) tempScript.data.mId = id; + else if (writeRecordsType == mwmp::RECORD_TYPE::BODYPART) + tempBodyPart.data.mId = id; else LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set id for record type %i which lacks that property", writeRecordsType); } @@ -436,6 +440,8 @@ void RecordsDynamicFunctions::SetRecordBaseId(const char* baseId) noexcept tempCell.baseId = baseId; else if (writeRecordsType == mwmp::RECORD_TYPE::SCRIPT) tempScript.baseId = baseId; + else if (writeRecordsType == mwmp::RECORD_TYPE::BODYPART) + tempBodyPart.baseId = baseId; else LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set baseId for record type %i which lacks that property", writeRecordsType); } @@ -470,6 +476,8 @@ void RecordsDynamicFunctions::SetRecordSubtype(unsigned int subtype) noexcept tempWeapon.data.mData.mType = subtype; else if (writeRecordsType == mwmp::RECORD_TYPE::APPARATUS) tempApparatus.data.mData.mType = subtype; + else if (writeRecordsType == mwmp::RECORD_TYPE::BODYPART) + tempBodyPart.data.mData.mType = subtype; else { LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set subtype for record type %i which lacks that property", writeRecordsType); @@ -570,6 +578,8 @@ void RecordsDynamicFunctions::SetRecordModel(const char* model) noexcept tempRepair.data.mModel = model; else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) tempLight.data.mModel = model; + else if (writeRecordsType == mwmp::RECORD_TYPE::BODYPART) + tempBodyPart.data.mModel = model; else { LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set model for record type %i which lacks that property", writeRecordsType); @@ -783,6 +793,8 @@ void RecordsDynamicFunctions::SetRecordFlags(int flags) noexcept tempContainer.data.mFlags = flags; else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) tempLight.data.mData.mFlags = flags; + else if (writeRecordsType == mwmp::RECORD_TYPE::BODYPART) + tempBodyPart.data.mData.mFlags = flags; else { LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set flags for record type %i which lacks that property", writeRecordsType); @@ -1186,6 +1198,8 @@ void RecordsDynamicFunctions::SetRecordRace(const char* race) noexcept if (writeRecordsType == mwmp::RECORD_TYPE::NPC) tempNpc.data.mRace = race; + else if (writeRecordsType == mwmp::RECORD_TYPE::BODYPART) + tempBodyPart.data.mRace = race; else LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set race for record type %i which lacks that property", writeRecordsType); @@ -1247,6 +1261,21 @@ void RecordsDynamicFunctions::SetRecordBloodType(int bloodType) noexcept tempOverrides.hasBloodType = true; } +void RecordsDynamicFunctions::SetRecordVampireState(bool vampireState) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::BODYPART) + tempBodyPart.data.mData.mVampire = vampireState; + else + { + LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Tried to set vampire state for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasVampireState = true; +} + void RecordsDynamicFunctions::SetRecordLevel(int level) noexcept { unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; @@ -1506,17 +1535,25 @@ void RecordsDynamicFunctions::SetRecordEffectMagnitudeMin(int magnitudeMin) noex void RecordsDynamicFunctions::SetRecordBodyPartType(unsigned int partType) noexcept { - tempBodyPart.mPart = partType; + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::BODYPART) + { + tempBodyPart.data.mData.mPart = partType; + tempOverrides.hasBodyPartType = true; + } + else + tempBodyPartReference.mPart = partType; } void RecordsDynamicFunctions::SetRecordBodyPartIdForMale(const char* partId) noexcept { - tempBodyPart.mMale = partId; + tempBodyPartReference.mMale = partId; } void RecordsDynamicFunctions::SetRecordBodyPartIdForFemale(const char* partId) noexcept { - tempBodyPart.mFemale = partId; + tempBodyPartReference.mFemale = partId; } void RecordsDynamicFunctions::SetRecordInventoryItemId(const char* itemId) noexcept @@ -1665,6 +1702,12 @@ void RecordsDynamicFunctions::AddRecord() noexcept WorldstateFunctions::writeWorldstate.scriptRecords.push_back(tempScript); tempScript = {}; } + else if (writeRecordsType == mwmp::RECORD_TYPE::BODYPART) + { + tempBodyPart.baseOverrides = tempOverrides; + WorldstateFunctions::writeWorldstate.bodyPartRecords.push_back(tempBodyPart); + tempBodyPart = {}; + } effectCount = 0; tempOverrides = {}; @@ -1707,9 +1750,9 @@ void RecordsDynamicFunctions::AddRecordBodyPart() noexcept unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; if (writeRecordsType == mwmp::RECORD_TYPE::ARMOR) - tempArmor.data.mParts.mParts.push_back(tempBodyPart); + tempArmor.data.mParts.mParts.push_back(tempBodyPartReference); else if (writeRecordsType == mwmp::RECORD_TYPE::CLOTHING) - tempClothing.data.mParts.mParts.push_back(tempBodyPart); + tempClothing.data.mParts.mParts.push_back(tempBodyPartReference); tempOverrides.hasBodyParts = true; tempBodyPart = {}; diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp index 592065872..3487452d3 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp @@ -86,6 +86,7 @@ \ {"SetRecordScale", RecordsDynamicFunctions::SetRecordScale},\ {"SetRecordBloodType", RecordsDynamicFunctions::SetRecordBloodType},\ + {"SetRecordVampireState", RecordsDynamicFunctions::SetRecordVampireState},\ \ {"SetRecordLevel", RecordsDynamicFunctions::SetRecordLevel},\ {"SetRecordMagicka", RecordsDynamicFunctions::SetRecordMagicka},\ @@ -757,6 +758,15 @@ public: */ static void SetRecordBloodType(int bloodType) noexcept; + /** + * \brief Set the vampire state of the temporary record stored on the server for the + * currently specified record type. + * + * \param vampireState The vampire state of the record. + * \return void + */ + static void SetRecordVampireState(bool vampireState) noexcept; + /** * \brief Set the level of the temporary record stored on the server for the * currently specified record type. @@ -949,7 +959,9 @@ public: static void SetRecordEffectMagnitudeMin(int magnitudeMin) noexcept; /** - * \brief Set the type of the temporary body part stored on the server. + * \brief Set the body part type of the temporary body part stored on the server + * (which then needs to be added to ARMOR or CLOTHING records) or set the body part + * type of the current record if it's a BODYPART. * * \param partType The type of the body part. * \return void diff --git a/apps/openmw/mwmp/RecordHelper.cpp b/apps/openmw/mwmp/RecordHelper.cpp index 002ad291e..94a17a057 100644 --- a/apps/openmw/mwmp/RecordHelper.cpp +++ b/apps/openmw/mwmp/RecordHelper.cpp @@ -192,6 +192,55 @@ void RecordHelper::overrideRecord(const mwmp::ArmorRecord& record) world->updatePtrsWithRefId(recordData.mId); } +void RecordHelper::overrideRecord(const mwmp::BodyPartRecord& record) +{ + const ESM::BodyPart &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::BodyPart *baseData = world->getStore().get().search(record.baseId); + ESM::BodyPart finalData = *baseData; + finalData.mId = recordData.mId; + + if (record.baseOverrides.hasModel) + finalData.mModel = recordData.mModel; + + if (record.baseOverrides.hasRace) + finalData.mRace = recordData.mRace; + + if (record.baseOverrides.hasSubtype) + finalData.mData.mType = recordData.mData.mType; + + if (record.baseOverrides.hasBodyPartType) + finalData.mData.mPart = recordData.mData.mPart; + + if (record.baseOverrides.hasVampireState) + finalData.mData.mVampire = recordData.mData.mVampire; + + if (record.baseOverrides.hasFlags) + finalData.mData.mFlags = recordData.mData.mFlags; + + 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::BookRecord& record) { const ESM::Book &recordData = record.data; diff --git a/apps/openmw/mwmp/RecordHelper.hpp b/apps/openmw/mwmp/RecordHelper.hpp index fdad79844..6d5c61e33 100644 --- a/apps/openmw/mwmp/RecordHelper.hpp +++ b/apps/openmw/mwmp/RecordHelper.hpp @@ -10,6 +10,7 @@ namespace RecordHelper void overrideRecord(const mwmp::ActivatorRecord& record); void overrideRecord(const mwmp::ApparatusRecord& record); void overrideRecord(const mwmp::ArmorRecord& record); + void overrideRecord(const mwmp::BodyPartRecord& record); void overrideRecord(const mwmp::BookRecord& record); void overrideRecord(const mwmp::CellRecord& record); void overrideRecord(const mwmp::ClothingRecord& record); diff --git a/apps/openmw/mwmp/Worldstate.cpp b/apps/openmw/mwmp/Worldstate.cpp index 2483b1676..d416d2441 100644 --- a/apps/openmw/mwmp/Worldstate.cpp +++ b/apps/openmw/mwmp/Worldstate.cpp @@ -304,6 +304,18 @@ void Worldstate::addRecords() RecordHelper::overrideRecord(record); } } + else if (recordsType == mwmp::RECORD_TYPE::BODYPART) + { + for (auto &&record : bodyPartRecords) + { + bool hasBaseId = !record.baseId.empty(); + + LOG_APPEND(TimedLog::LOG_INFO, "- bodypart 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 0ce455b78..c2ba356b3 100644 --- a/components/openmw-mp/Base/BaseWorldstate.hpp +++ b/components/openmw-mp/Base/BaseWorldstate.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -54,7 +55,8 @@ namespace mwmp REPAIR, LIGHT, CELL, - SCRIPT + SCRIPT, + BODYPART }; // When using an existing record as a base, this struct tracks which changes @@ -118,6 +120,8 @@ namespace mwmp bool hasScale = false; bool hasBloodType = false; + bool hasBodyPartType = false; + bool hasVampireState = false; bool hasLevel = false; bool hasMagicka = false; @@ -156,6 +160,13 @@ namespace mwmp BaseOverrides baseOverrides; }; + struct BodyPartRecord + { + ESM::BodyPart data; + std::string baseId; + BaseOverrides baseOverrides; + }; + struct BookRecord { ESM::Book data; @@ -360,6 +371,7 @@ namespace mwmp std::vector activatorRecords; std::vector apparatusRecords; std::vector armorRecords; + std::vector bodyPartRecords; std::vector bookRecords; std::vector cellRecords; std::vector clothingRecords; diff --git a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp index 734503e7c..8c25d7905 100644 --- a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp +++ b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp @@ -64,6 +64,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) worldstate->recordsCount = Utils::getVectorSize(worldstate->cellRecords); else if (worldstate->recordsType == mwmp::RECORD_TYPE::SCRIPT) worldstate->recordsCount = Utils::getVectorSize(worldstate->scriptRecords); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::BODYPART) + worldstate->recordsCount = Utils::getVectorSize(worldstate->bodyPartRecords); else { LOG_MESSAGE_SIMPLE(TimedLog::LOG_ERROR, "Processed invalid ID_RECORD_DYNAMIC packet about unimplemented recordsType %i", @@ -128,6 +130,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) Utils::resetVector(worldstate->cellRecords, worldstate->recordsCount); else if (worldstate->recordsType == mwmp::RECORD_TYPE::SCRIPT) Utils::resetVector(worldstate->scriptRecords, worldstate->recordsCount); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::BODYPART) + Utils::resetVector(worldstate->bodyPartRecords, worldstate->recordsCount); } if (worldstate->recordsType == mwmp::RECORD_TYPE::SPELL) @@ -295,8 +299,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) RW(overrides.hasName, send); RW(overrides.hasGender, send); RW(overrides.hasFlags, send); - RW(overrides.hasModel, send); RW(overrides.hasRace, send); + RW(overrides.hasModel, send); RW(overrides.hasHair, send); RW(overrides.hasHead, send); RW(overrides.hasFaction, send); @@ -813,6 +817,33 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) } } } + else if (worldstate->recordsType == mwmp::RECORD_TYPE::BODYPART) + { + for (auto &&record : worldstate->bodyPartRecords) + { + auto &recordData = record.data; + + RW(record.baseId, send, true); + RW(recordData.mId, send, true); + RW(recordData.mModel, send, true); + RW(recordData.mRace, send, true); + RW(recordData.mData.mType, send); + RW(recordData.mData.mPart, send); + RW(recordData.mData.mVampire, send); + RW(recordData.mData.mFlags, send); + + if (!record.baseId.empty()) + { + auto &&overrides = record.baseOverrides; + RW(overrides.hasModel, send); + RW(overrides.hasRace, send); + RW(overrides.hasSubtype, send); + RW(overrides.hasBodyPartType, send); + RW(overrides.hasVampireState, send); + RW(overrides.hasFlags, send); + } + } + } } void PacketRecordDynamic::ProcessEffects(ESM::EffectList &effectList, bool send)