From 4100d93dea5e79655de572f3d45bcbe063b29820 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 3 Aug 2019 06:19:22 +0300 Subject: [PATCH] [General] Implement ingredient records for RecordDynamic packets --- .../Script/Functions/RecordsDynamic.cpp | 43 ++++++++++ apps/openmw/mwmp/RecordHelper.cpp | 79 +++++++++++++++++++ apps/openmw/mwmp/RecordHelper.hpp | 6 ++ apps/openmw/mwmp/Worldstate.cpp | 12 +++ components/openmw-mp/Base/BaseWorldstate.hpp | 12 ++- .../Worldstate/PacketRecordDynamic.cpp | 35 ++++++++ 6 files changed, 186 insertions(+), 1 deletion(-) diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp index 64b70ac53..bf4e02689 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp @@ -26,9 +26,11 @@ ContainerRecord tempContainer; DoorRecord tempDoor; ActivatorRecord tempActivator; StaticRecord tempStatic; +IngredientRecord tempIngredient; BaseOverrides tempOverrides; +unsigned int effectCount = 0; ESM::ENAMstruct tempEffect; ESM::PartReference tempBodyPart; mwmp::Item tempInventoryItem; @@ -65,6 +67,7 @@ void RecordsDynamicFunctions::ClearRecords() noexcept WorldstateFunctions::writeWorldstate.doorRecords.clear(); WorldstateFunctions::writeWorldstate.activatorRecords.clear(); WorldstateFunctions::writeWorldstate.staticRecords.clear(); + WorldstateFunctions::writeWorldstate.ingredientRecords.clear(); } unsigned short RecordsDynamicFunctions::GetRecordType() noexcept @@ -353,6 +356,8 @@ void RecordsDynamicFunctions::SetRecordId(const char* id) noexcept tempActivator.data.mId = id; else if (writeRecordsType == mwmp::RECORD_TYPE::STATIC) tempStatic.data.mId = id; + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + tempIngredient.data.mId = id; else LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set id for record type %i which lacks that property", writeRecordsType); } @@ -389,6 +394,8 @@ void RecordsDynamicFunctions::SetRecordBaseId(const char* baseId) noexcept tempActivator.baseId = baseId; else if (writeRecordsType == mwmp::RECORD_TYPE::STATIC) tempStatic.baseId = baseId; + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + tempIngredient.baseId = baseId; else LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set baseId for record type %i which lacks that property", writeRecordsType); } @@ -458,6 +465,8 @@ void RecordsDynamicFunctions::SetRecordName(const char* name) noexcept tempDoor.data.mName = name; else if (writeRecordsType == mwmp::RECORD_TYPE::ACTIVATOR) tempActivator.data.mName = name; + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + tempIngredient.data.mName = name; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set name for record type %i which lacks that property", writeRecordsType); @@ -495,6 +504,8 @@ void RecordsDynamicFunctions::SetRecordModel(const char* model) noexcept tempActivator.data.mModel = model; else if (writeRecordsType == mwmp::RECORD_TYPE::STATIC) tempStatic.data.mModel = model; + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + tempIngredient.data.mModel = model; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set model for record type %i which lacks that property", writeRecordsType); @@ -520,6 +531,8 @@ void RecordsDynamicFunctions::SetRecordIcon(const char* icon) noexcept tempMiscellaneous.data.mIcon = icon; else if (writeRecordsType == mwmp::RECORD_TYPE::WEAPON) tempWeapon.data.mIcon = icon; + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + tempIngredient.data.mIcon = icon; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set icon for record type %i which lacks that property", writeRecordsType); @@ -555,6 +568,8 @@ void RecordsDynamicFunctions::SetRecordScript(const char* script) noexcept tempDoor.data.mScript = script; else if (writeRecordsType == mwmp::RECORD_TYPE::ACTIVATOR) tempActivator.data.mScript = script; + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + tempIngredient.data.mScript = script; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set script for record type %i which lacks that property", writeRecordsType); @@ -707,6 +722,8 @@ void RecordsDynamicFunctions::SetRecordValue(int value) noexcept tempMiscellaneous.data.mData.mValue = value; else if (writeRecordsType == mwmp::RECORD_TYPE::WEAPON) tempWeapon.data.mData.mValue = value; + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + tempIngredient.data.mData.mValue = value; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set value for record type %i which lacks that property", writeRecordsType); @@ -734,6 +751,8 @@ void RecordsDynamicFunctions::SetRecordWeight(double weight) noexcept tempWeapon.data.mData.mWeight = weight; else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) tempContainer.data.mWeight = weight; + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + tempIngredient.data.mData.mWeight = weight; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set weight for record type %i which lacks that property", writeRecordsType); @@ -1294,7 +1313,14 @@ void RecordsDynamicFunctions::AddRecord() noexcept WorldstateFunctions::writeWorldstate.staticRecords.push_back(tempStatic); tempStatic = {}; } + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + { + tempIngredient.baseOverrides = tempOverrides; + WorldstateFunctions::writeWorldstate.ingredientRecords.push_back(tempIngredient); + tempIngredient = {}; + } + effectCount = 0; tempOverrides = {}; } @@ -1308,8 +1334,25 @@ void RecordsDynamicFunctions::AddRecordEffect() noexcept tempPotion.data.mEffects.mList.push_back(tempEffect); else if (writeRecordsType == mwmp::RECORD_TYPE::ENCHANTMENT) tempEnchantment.data.mEffects.mList.push_back(tempEffect); + else if (writeRecordsType == mwmp::RECORD_TYPE::INGREDIENT) + { + const static unsigned int effectCap = sizeof(tempIngredient.data.mData.mEffectID) / sizeof(tempIngredient.data.mData.mEffectID[0]); + + if (effectCount < effectCap) + { + tempIngredient.data.mData.mEffectID[effectCount] = tempEffect.mEffectID; + tempIngredient.data.mData.mAttributes[effectCount] = tempEffect.mAttribute; + tempIngredient.data.mData.mSkills[effectCount] = tempEffect.mSkill; + } + else + { + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Could not add record effect to temporary ingredient record because the cap of %i effects has been reached", + effectCap); + } + } tempOverrides.hasEffects = true; + effectCount++; tempEffect = {}; } diff --git a/apps/openmw/mwmp/RecordHelper.cpp b/apps/openmw/mwmp/RecordHelper.cpp index 2839b6632..2c161725b 100644 --- a/apps/openmw/mwmp/RecordHelper.cpp +++ b/apps/openmw/mwmp/RecordHelper.cpp @@ -118,6 +118,13 @@ bool RecordHelper::doesStaticRecordExist(const std::string& id) return world->getStore().get().search(id); } +bool RecordHelper::doesIngredientRecordExist(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(); @@ -1056,6 +1063,71 @@ void RecordHelper::overrideStaticRecord(const mwmp::StaticRecord& record) world->updatePtrsWithRefId(recordData.mId); } +void RecordHelper::overrideIngredientRecord(const mwmp::IngredientRecord& record) +{ + const ESM::Ingredient &recordData = record.data; + + if (recordData.mId.empty()) + { + LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided"); + return; + } + + bool isExistingId = doesIngredientRecordExist(recordData.mId); + MWBase::World *world = MWBase::Environment::get().getWorld(); + + if (record.baseId.empty()) + { + world->getModifiableStore().overrideRecord(recordData); + } + else if (doesIngredientRecordExist(record.baseId)) + { + const ESM::Ingredient *baseData = world->getStore().get().search(record.baseId); + ESM::Ingredient 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.hasIcon) + finalData.mIcon = recordData.mIcon; + + if (record.baseOverrides.hasWeight) + finalData.mData.mWeight = recordData.mData.mWeight; + + if (record.baseOverrides.hasValue) + finalData.mData.mValue = recordData.mData.mValue; + + if (record.baseOverrides.hasScript) + finalData.mScript = recordData.mScript; + + if (record.baseOverrides.hasEffects) + { + const static unsigned int effectCap = sizeof(recordData.mData.mEffectID) / sizeof(recordData.mData.mEffectID[0]); + + for (int effectIndex = 0; effectIndex < effectCap; effectIndex++) + { + finalData.mData.mEffectID[effectIndex] = recordData.mData.mEffectID[effectIndex]; + finalData.mData.mAttributes[effectIndex] = recordData.mData.mAttributes[effectIndex]; + finalData.mData.mSkills[effectIndex] = recordData.mData.mSkills[effectIndex]; + } + } + + 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(); @@ -1153,3 +1225,10 @@ void RecordHelper::overrideStaticRecord(const ESM::Static& record) world->getModifiableStore().overrideRecord(record); } + +void RecordHelper::overrideIngredientRecord(const ESM::Ingredient& 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 2161a8776..b8cd88420 100644 --- a/apps/openmw/mwmp/RecordHelper.hpp +++ b/apps/openmw/mwmp/RecordHelper.hpp @@ -30,6 +30,8 @@ namespace RecordHelper bool doesActivatorRecordExist(const std::string& id); bool doesStaticRecordExist(const std::string& id); + bool doesIngredientRecordExist(const std::string& id); + std::string createCreatureRecord(const ESM::Creature& record); std::string createNpcRecord(const ESM::NPC& record); @@ -52,6 +54,8 @@ namespace RecordHelper void overrideActivatorRecord(const mwmp::ActivatorRecord& record); void overrideStaticRecord(const mwmp::StaticRecord& record); + void overrideIngredientRecord(const mwmp::IngredientRecord& record); + void overrideCreatureRecord(const ESM::Creature& record); void overrideNpcRecord(const ESM::NPC& record); @@ -70,6 +74,8 @@ namespace RecordHelper void overrideActivatorRecord(const ESM::Activator& record); void overrideStaticRecord(const ESM::Static& record); + + void overrideIngredientRecord(const ESM::Ingredient& record); } diff --git a/apps/openmw/mwmp/Worldstate.cpp b/apps/openmw/mwmp/Worldstate.cpp index d8c11120b..f8408146a 100644 --- a/apps/openmw/mwmp/Worldstate.cpp +++ b/apps/openmw/mwmp/Worldstate.cpp @@ -206,6 +206,18 @@ void Worldstate::addRecords() RecordHelper::overrideStaticRecord(record); } } + else if (recordsType == mwmp::RECORD_TYPE::INGREDIENT) + { + for (auto &&record : ingredientRecords) + { + bool hasBaseId = !record.baseId.empty(); + + LOG_APPEND(Log::LOG_INFO, "- ingredient record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(), + hasBaseId ? record.baseId.c_str() : "empty"); + + RecordHelper::overrideIngredientRecord(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 1909d4203..f42dbd785 100644 --- a/components/openmw-mp/Base/BaseWorldstate.hpp +++ b/components/openmw-mp/Base/BaseWorldstate.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,8 @@ namespace mwmp CONTAINER, DOOR, ACTIVATOR, - STATIC + STATIC, + INGREDIENT }; // When using an existing record as a base, this struct tracks which changes @@ -163,6 +165,13 @@ namespace mwmp BaseOverrides baseOverrides; }; + struct IngredientRecord + { + ESM::Ingredient data; + std::string baseId; + BaseOverrides baseOverrides; + }; + struct MiscellaneousRecord { ESM::Miscellaneous data; @@ -269,6 +278,7 @@ namespace mwmp std::vector creatureRecords; std::vector doorRecords; std::vector enchantmentRecords; + std::vector ingredientRecords; std::vector miscellaneousRecords; std::vector npcRecords; std::vector potionRecords; diff --git a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp index 69913a5bf..778011346 100644 --- a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp +++ b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp @@ -48,6 +48,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) worldstate->recordsCount = Utils::getVectorSize(worldstate->activatorRecords); else if (worldstate->recordsType == mwmp::RECORD_TYPE::STATIC) worldstate->recordsCount = Utils::getVectorSize(worldstate->staticRecords); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::INGREDIENT) + worldstate->recordsCount = Utils::getVectorSize(worldstate->ingredientRecords); else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Processed invalid ID_RECORD_DYNAMIC packet about unimplemented recordsType %i", @@ -96,6 +98,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) Utils::resetVector(worldstate->activatorRecords, worldstate->recordsCount); else if (worldstate->recordsType == mwmp::RECORD_TYPE::STATIC) Utils::resetVector(worldstate->staticRecords, worldstate->recordsCount); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::INGREDIENT) + Utils::resetVector(worldstate->ingredientRecords, worldstate->recordsCount); } if (worldstate->recordsType == mwmp::RECORD_TYPE::SPELL) @@ -544,6 +548,37 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) } } } + else if (worldstate->recordsType == mwmp::RECORD_TYPE::INGREDIENT) + { + for (auto &&record : worldstate->ingredientRecords) + { + 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.mIcon, send, true); + RW(recordData.mData.mWeight, send); + RW(recordData.mData.mValue, send); + RW(recordData.mData.mEffectID, send); + RW(recordData.mData.mAttributes, send); + RW(recordData.mData.mSkills, send); + RW(recordData.mScript, send, true); + + if (!record.baseId.empty()) + { + auto &&overrides = record.baseOverrides; + RW(overrides.hasName, send); + RW(overrides.hasModel, send); + RW(overrides.hasIcon, send); + RW(overrides.hasWeight, send); + RW(overrides.hasValue, send); + RW(overrides.hasEffects, send); + RW(overrides.hasScript, send); + } + } + } } void PacketRecordDynamic::ProcessEffects(ESM::EffectList &effectList, bool send)