diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp index 9763209a0..5ef7018fb 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.cpp @@ -31,6 +31,7 @@ ApparatusRecord tempApparatus; LockpickRecord tempLockpick; ProbeRecord tempProbe; RepairRecord tempRepair; +LightRecord tempLight; BaseOverrides tempOverrides; @@ -76,6 +77,7 @@ void RecordsDynamicFunctions::ClearRecords() noexcept WorldstateFunctions::writeWorldstate.lockpickRecords.clear(); WorldstateFunctions::writeWorldstate.probeRecords.clear(); WorldstateFunctions::writeWorldstate.repairRecords.clear(); + WorldstateFunctions::writeWorldstate.lightRecords.clear(); } unsigned short RecordsDynamicFunctions::GetRecordType() noexcept @@ -374,6 +376,8 @@ void RecordsDynamicFunctions::SetRecordId(const char* id) noexcept tempProbe.data.mId = id; else if (writeRecordsType == mwmp::RECORD_TYPE::REPAIR) tempRepair.data.mId = id; + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mId = id; else LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set id for record type %i which lacks that property", writeRecordsType); } @@ -420,6 +424,8 @@ void RecordsDynamicFunctions::SetRecordBaseId(const char* baseId) noexcept tempProbe.baseId = baseId; else if (writeRecordsType == mwmp::RECORD_TYPE::REPAIR) tempRepair.baseId = baseId; + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.baseId = baseId; else LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set baseId for record type %i which lacks that property", writeRecordsType); } @@ -501,6 +507,8 @@ void RecordsDynamicFunctions::SetRecordName(const char* name) noexcept tempProbe.data.mName = name; else if (writeRecordsType == mwmp::RECORD_TYPE::REPAIR) tempRepair.data.mName = name; + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mName = name; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set name for record type %i which lacks that property", writeRecordsType); @@ -548,6 +556,8 @@ void RecordsDynamicFunctions::SetRecordModel(const char* model) noexcept tempProbe.data.mModel = model; else if (writeRecordsType == mwmp::RECORD_TYPE::REPAIR) tempRepair.data.mModel = model; + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mModel = model; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set model for record type %i which lacks that property", writeRecordsType); @@ -583,6 +593,8 @@ void RecordsDynamicFunctions::SetRecordIcon(const char* icon) noexcept tempProbe.data.mIcon = icon; else if (writeRecordsType == mwmp::RECORD_TYPE::REPAIR) tempRepair.data.mIcon = icon; + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mIcon = icon; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set icon for record type %i which lacks that property", writeRecordsType); @@ -628,6 +640,8 @@ void RecordsDynamicFunctions::SetRecordScript(const char* script) noexcept tempProbe.data.mScript = script; else if (writeRecordsType == mwmp::RECORD_TYPE::REPAIR) tempRepair.data.mScript = script; + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mScript = script; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set script for record type %i which lacks that property", writeRecordsType); @@ -755,6 +769,8 @@ void RecordsDynamicFunctions::SetRecordFlags(int flags) noexcept tempWeapon.data.mData.mFlags = flags; else if (writeRecordsType == mwmp::RECORD_TYPE::CONTAINER) tempContainer.data.mFlags = flags; + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mData.mFlags = flags; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set flags for record type %i which lacks that property", writeRecordsType); @@ -790,6 +806,8 @@ void RecordsDynamicFunctions::SetRecordValue(int value) noexcept tempProbe.data.mData.mValue = value; else if (writeRecordsType == mwmp::RECORD_TYPE::REPAIR) tempRepair.data.mData.mValue = value; + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mData.mValue = value; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set value for record type %i which lacks that property", writeRecordsType); @@ -827,6 +845,8 @@ void RecordsDynamicFunctions::SetRecordWeight(double weight) noexcept tempProbe.data.mData.mWeight = weight; else if (writeRecordsType == mwmp::RECORD_TYPE::REPAIR) tempRepair.data.mData.mWeight = weight; + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mData.mWeight = weight; else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set weight for record type %i which lacks that property", writeRecordsType); @@ -869,13 +889,58 @@ void RecordsDynamicFunctions::SetRecordUses(int uses) noexcept tempRepair.data.mData.mUses = uses; else { - LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set value for record type %i which lacks that property", writeRecordsType); + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set number of uses for record type %i which lacks that property", writeRecordsType); return; } tempOverrides.hasUses = true; } +void RecordsDynamicFunctions::SetRecordTime(int time) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mData.mTime = time; + else + { + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set time for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasTime = true; +} + +void RecordsDynamicFunctions::SetRecordRadius(int radius) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mData.mRadius = radius; + else + { + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set radius for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasRadius = true; +} + +void RecordsDynamicFunctions::SetRecordColor(unsigned int red, unsigned int green, unsigned int blue) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mData.mColor = red + (green << 8) + (blue << 16); + else + { + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set color for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasColor = true; +} + void RecordsDynamicFunctions::SetRecordArmorRating(int armorRating) noexcept { unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; @@ -1257,6 +1322,21 @@ void RecordsDynamicFunctions::SetRecordAIServices(int aiServices) noexcept tempOverrides.hasAiServices = true; } +void RecordsDynamicFunctions::SetRecordSound(const char* sound) noexcept +{ + unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; + + if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + tempLight.data.mSound = sound; + else + { + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Tried to set sound for record type %i which lacks that property", writeRecordsType); + return; + } + + tempOverrides.hasSound = true; +} + void RecordsDynamicFunctions::SetRecordOpenSound(const char* sound) noexcept { unsigned short writeRecordsType = WorldstateFunctions::writeWorldstate.recordsType; @@ -1508,6 +1588,12 @@ void RecordsDynamicFunctions::AddRecord() noexcept WorldstateFunctions::writeWorldstate.repairRecords.push_back(tempRepair); tempRepair = {}; } + else if (writeRecordsType == mwmp::RECORD_TYPE::LIGHT) + { + tempLight.baseOverrides = tempOverrides; + WorldstateFunctions::writeWorldstate.lightRecords.push_back(tempLight); + tempLight = {}; + } effectCount = 0; tempOverrides = {}; diff --git a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp index 0a6040b24..8160484b8 100644 --- a/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp +++ b/apps/openmw-mp/Script/Functions/RecordsDynamic.hpp @@ -59,6 +59,9 @@ {"SetRecordWeight", RecordsDynamicFunctions::SetRecordWeight},\ {"SetRecordQuality", RecordsDynamicFunctions::SetRecordQuality},\ {"SetRecordUses", RecordsDynamicFunctions::SetRecordUses},\ + {"SetRecordTime", RecordsDynamicFunctions::SetRecordTime},\ + {"SetRecordRadius", RecordsDynamicFunctions::SetRecordRadius},\ + {"SetRecordColor", RecordsDynamicFunctions::SetRecordColor},\ \ {"SetRecordArmorRating", RecordsDynamicFunctions::SetRecordArmorRating},\ {"SetRecordHealth", RecordsDynamicFunctions::SetRecordHealth},\ @@ -90,6 +93,7 @@ {"SetRecordAIAlarm", RecordsDynamicFunctions::SetRecordAIAlarm},\ {"SetRecordAIServices", RecordsDynamicFunctions::SetRecordAIServices},\ \ + {"SetRecordSound", RecordsDynamicFunctions::SetRecordSound},\ {"SetRecordOpenSound", RecordsDynamicFunctions::SetRecordOpenSound},\ {"SetRecordCloseSound", RecordsDynamicFunctions::SetRecordCloseSound},\ \ @@ -543,6 +547,33 @@ public: */ static void SetRecordUses(int uses) noexcept; + /** + * \brief Set the time of the temporary record stored on the server for the currently + * specified record type. + * + * \param time The time of the record. + * \return void + */ + static void SetRecordTime(int time) noexcept; + + /** + * \brief Set the radius of the temporary record stored on the server for the currently + * specified record type. + * + * \param uses The radius of the record. + * \return void + */ + static void SetRecordRadius(int radius) noexcept; + + /** + * \brief Set the color of the temporary record stored on the server for the currently + * specified record type. + * + * \param color The color of the record. + * \return void + */ + static void SetRecordColor(unsigned int red, unsigned int green, unsigned int blue) noexcept; + /** * \brief Set the armor rating of the temporary record stored on the server * for the currently specified record type. @@ -766,6 +797,15 @@ public: */ static void SetRecordAIServices(int aiServices) noexcept; + /** + * \brief Set the sound of the temporary record stored on the server for the currently + * specified record type. + * + * \param sound The sound of the record. + * \return void + */ + static void SetRecordSound(const char* sound) 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 0a658f2cf..759ef64ff 100644 --- a/apps/openmw/mwmp/RecordHelper.cpp +++ b/apps/openmw/mwmp/RecordHelper.cpp @@ -153,6 +153,13 @@ bool RecordHelper::doesRepairRecordExist(const std::string& id) return world->getStore().get().search(id); } +bool RecordHelper::doesLightRecordExist(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(); @@ -1410,6 +1417,74 @@ void RecordHelper::overrideRepairRecord(const mwmp::RepairRecord& record) world->updatePtrsWithRefId(recordData.mId); } +void RecordHelper::overrideLightRecord(const mwmp::LightRecord& record) +{ + const ESM::Light &recordData = record.data; + + if (recordData.mId.empty()) + { + LOG_APPEND(Log::LOG_INFO, "-- Ignoring record override with no id provided"); + return; + } + + bool isExistingId = doesLightRecordExist(recordData.mId); + MWBase::World *world = MWBase::Environment::get().getWorld(); + + if (record.baseId.empty()) + { + world->getModifiableStore().overrideRecord(recordData); + } + else if (doesLightRecordExist(record.baseId)) + { + const ESM::Light *baseData = world->getStore().get().search(record.baseId); + ESM::Light 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.hasSound) + finalData.mSound = recordData.mSound; + + if (record.baseOverrides.hasWeight) + finalData.mData.mWeight = recordData.mData.mWeight; + + if (record.baseOverrides.hasValue) + finalData.mData.mValue = recordData.mData.mValue; + + if (record.baseOverrides.hasTime) + finalData.mData.mTime = recordData.mData.mTime; + + if (record.baseOverrides.hasRadius) + finalData.mData.mRadius = recordData.mData.mRadius; + + if (record.baseOverrides.hasColor) + finalData.mData.mColor = recordData.mData.mColor; + + if (record.baseOverrides.hasFlags) + finalData.mData.mFlags = recordData.mData.mFlags; + + 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(); @@ -1542,3 +1617,10 @@ void RecordHelper::overrideRepairRecord(const ESM::Repair& record) world->getModifiableStore().overrideRecord(record); } + +void RecordHelper::overrideLightRecord(const ESM::Light& 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 9a7677463..f4db5303f 100644 --- a/apps/openmw/mwmp/RecordHelper.hpp +++ b/apps/openmw/mwmp/RecordHelper.hpp @@ -35,6 +35,7 @@ namespace RecordHelper bool doesLockpickRecordExist(const std::string& id); bool doesProbeRecordExist(const std::string& id); bool doesRepairRecordExist(const std::string& id); + bool doesLightRecordExist(const std::string& id); std::string createCreatureRecord(const ESM::Creature& record); std::string createNpcRecord(const ESM::NPC& record); @@ -63,6 +64,7 @@ namespace RecordHelper void overrideLockpickRecord(const mwmp::LockpickRecord& record); void overrideProbeRecord(const mwmp::ProbeRecord& record); void overrideRepairRecord(const mwmp::RepairRecord& record); + void overrideLightRecord(const mwmp::LightRecord& record); void overrideCreatureRecord(const ESM::Creature& record); void overrideNpcRecord(const ESM::NPC& record); @@ -88,6 +90,7 @@ namespace RecordHelper void overrideLockpickRecord(const ESM::Lockpick& record); void overrideProbeRecord(const ESM::Probe& record); void overrideRepairRecord(const ESM::Repair& record); + void overrideLightRecord(const ESM::Light& record); } diff --git a/apps/openmw/mwmp/Worldstate.cpp b/apps/openmw/mwmp/Worldstate.cpp index 8e837a302..cfb9469b9 100644 --- a/apps/openmw/mwmp/Worldstate.cpp +++ b/apps/openmw/mwmp/Worldstate.cpp @@ -266,6 +266,18 @@ void Worldstate::addRecords() RecordHelper::overrideRepairRecord(record); } } + else if (recordsType == mwmp::RECORD_TYPE::LIGHT) + { + for (auto &&record : lightRecords) + { + bool hasBaseId = !record.baseId.empty(); + + LOG_APPEND(Log::LOG_INFO, "- light record %s, %s\n-- baseId is %s", record.data.mId.c_str(), record.data.mName.c_str(), + hasBaseId ? record.baseId.c_str() : "empty"); + + RecordHelper::overrideLightRecord(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 5b75149f9..90b6dd072 100644 --- a/components/openmw-mp/Base/BaseWorldstate.hpp +++ b/components/openmw-mp/Base/BaseWorldstate.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,8 @@ namespace mwmp APPARATUS, LOCKPICK, PROBE, - REPAIR + REPAIR, + LIGHT }; // When using an existing record as a base, this struct tracks which changes @@ -87,6 +89,9 @@ namespace mwmp bool hasWeight = false; bool hasQuality = false; bool hasUses = false; + bool hasTime = false; + bool hasRadius = false; + bool hasColor = false; bool hasArmorRating = false; bool hasHealth = false; @@ -116,6 +121,7 @@ namespace mwmp bool hasAiAlarm = false; bool hasAiServices = false; + bool hasSound = false; bool hasOpenSound = false; bool hasCloseSound = false; }; @@ -193,6 +199,13 @@ namespace mwmp BaseOverrides baseOverrides; }; + struct LightRecord + { + ESM::Light data; + std::string baseId; + BaseOverrides baseOverrides; + }; + struct LockpickRecord { ESM::Lockpick data; @@ -322,6 +335,7 @@ namespace mwmp std::vector doorRecords; std::vector enchantmentRecords; std::vector ingredientRecords; + std::vector lightRecords; std::vector lockpickRecords; 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 e2caf71e0..6c976fa4c 100644 --- a/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp +++ b/components/openmw-mp/Packets/Worldstate/PacketRecordDynamic.cpp @@ -58,6 +58,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) worldstate->recordsCount = Utils::getVectorSize(worldstate->probeRecords); else if (worldstate->recordsType == mwmp::RECORD_TYPE::REPAIR) worldstate->recordsCount = Utils::getVectorSize(worldstate->repairRecords); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::LIGHT) + worldstate->recordsCount = Utils::getVectorSize(worldstate->lightRecords); else { LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Processed invalid ID_RECORD_DYNAMIC packet about unimplemented recordsType %i", @@ -116,6 +118,8 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) Utils::resetVector(worldstate->probeRecords, worldstate->recordsCount); else if (worldstate->recordsType == mwmp::RECORD_TYPE::REPAIR) Utils::resetVector(worldstate->repairRecords, worldstate->recordsCount); + else if (worldstate->recordsType == mwmp::RECORD_TYPE::LIGHT) + Utils::resetVector(worldstate->lightRecords, worldstate->recordsCount); } if (worldstate->recordsType == mwmp::RECORD_TYPE::SPELL) @@ -732,6 +736,43 @@ void PacketRecordDynamic::Packet(RakNet::BitStream *bs, bool send) } } } + else if (worldstate->recordsType == mwmp::RECORD_TYPE::LIGHT) + { + for (auto &&record : worldstate->lightRecords) + { + 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.mSound, send, true); + RW(recordData.mData.mWeight, send, true); + RW(recordData.mData.mValue, send, true); + RW(recordData.mData.mTime, send, true); + RW(recordData.mData.mRadius, send, true); + RW(recordData.mData.mColor, send, true); + RW(recordData.mData.mFlags, 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.hasIcon, send); + RW(overrides.hasSound, send); + RW(overrides.hasWeight, send); + RW(overrides.hasValue, send); + RW(overrides.hasTime, send); + RW(overrides.hasRadius, send); + RW(overrides.hasColor, send); + RW(overrides.hasFlags, send); + RW(overrides.hasScript, send); + } + } + } } void PacketRecordDynamic::ProcessEffects(ESM::EffectList &effectList, bool send)