From c56cd7c2218aa71c4e03ce45f7462963fcef6d79 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 10 Jul 2020 02:09:11 +0200 Subject: [PATCH] [General] Implement PlayerSpellsActive packet, part 1 Additions and removals of the local player's active spells can now be saved to and loaded from the server. --- apps/openmw-mp/CMakeLists.txt | 3 +- apps/openmw-mp/Script/Functions/Spells.cpp | 166 ++++++++++++++++ apps/openmw-mp/Script/Functions/Spells.hpp | 184 +++++++++++++++++- apps/openmw-mp/Script/ScriptFunctions.hpp | 1 + .../processors/ProcessorInitializer.cpp | 2 + .../player/ProcessorPlayerSpellsActive.hpp | 26 +++ apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/activespells.cpp | 42 ++++ apps/openmw/mwmp/LocalPlayer.cpp | 95 +++++++++ apps/openmw/mwmp/LocalPlayer.hpp | 6 + .../mwmp/processors/ProcessorInitializer.cpp | 2 + .../player/ProcessorPlayerSpellsActive.hpp | 42 ++++ components/openmw-mp/Base/BasePlayer.hpp | 20 +- .../Player/PacketPlayerSpellsActive.cpp | 70 ++++--- .../Player/PacketPlayerSpellsActive.hpp | 3 + 15 files changed, 620 insertions(+), 44 deletions(-) create mode 100644 apps/openmw-mp/processors/player/ProcessorPlayerSpellsActive.hpp create mode 100644 apps/openmw/mwmp/processors/player/ProcessorPlayerSpellsActive.hpp diff --git a/apps/openmw-mp/CMakeLists.txt b/apps/openmw-mp/CMakeLists.txt index c7cec52c1..e644744ec 100644 --- a/apps/openmw-mp/CMakeLists.txt +++ b/apps/openmw-mp/CMakeLists.txt @@ -107,7 +107,8 @@ set(PROCESSORS_PLAYER processors/player/ProcessorPlayerRest.hpp processors/player/ProcessorPlayerResurrect.hpp processors/player/ProcessorPlayerShapeshift.hpp processors/player/ProcessorPlayerSkill.hpp processors/player/ProcessorPlayerSpeech.hpp processors/player/ProcessorPlayerSpellbook.hpp - processors/player/ProcessorPlayerStatsDynamic.hpp processors/player/ProcessorPlayerTopic.hpp + processors/player/ProcessorPlayerSpellsActive.hpp processors/player/ProcessorPlayerStatsDynamic.hpp + processors/player/ProcessorPlayerTopic.hpp ) source_group(tes3mp-server\\processors\\player FILES ${PROCESSORS_PLAYER}) diff --git a/apps/openmw-mp/Script/Functions/Spells.cpp b/apps/openmw-mp/Script/Functions/Spells.cpp index 78f0e33c1..2535d4ab2 100644 --- a/apps/openmw-mp/Script/Functions/Spells.cpp +++ b/apps/openmw-mp/Script/Functions/Spells.cpp @@ -8,6 +8,8 @@ using namespace mwmp; +std::vector storedActiveEffects; + void SpellFunctions::ClearSpellbookChanges(unsigned short pid) noexcept { Player *player; @@ -16,6 +18,14 @@ void SpellFunctions::ClearSpellbookChanges(unsigned short pid) noexcept player->spellbookChanges.spells.clear(); } +void SpellFunctions::ClearSpellsActiveChanges(unsigned short pid) noexcept +{ + Player* player; + GET_PLAYER(pid, player, ); + + player->spellsActiveChanges.activeSpells.clear(); +} + unsigned int SpellFunctions::GetSpellbookChangesSize(unsigned short pid) noexcept { Player *player; @@ -32,6 +42,22 @@ unsigned int SpellFunctions::GetSpellbookChangesAction(unsigned short pid) noexc return player->spellbookChanges.action; } +unsigned int SpellFunctions::GetSpellsActiveChangesSize(unsigned short pid) noexcept +{ + Player* player; + GET_PLAYER(pid, player, 0); + + return player->spellsActiveChanges.activeSpells.size(); +} + +unsigned int SpellFunctions::GetSpellsActiveChangesAction(unsigned short pid) noexcept +{ + Player* player; + GET_PLAYER(pid, player, 0); + + return player->spellsActiveChanges.action; +} + void SpellFunctions::SetSpellbookChangesAction(unsigned short pid, unsigned char action) noexcept { Player *player; @@ -40,6 +66,14 @@ void SpellFunctions::SetSpellbookChangesAction(unsigned short pid, unsigned char player->spellbookChanges.action = action; } +void SpellFunctions::SetSpellsActiveChangesAction(unsigned short pid, unsigned char action) noexcept +{ + Player* player; + GET_PLAYER(pid, player, ); + + player->spellsActiveChanges.action = action; +} + void SpellFunctions::AddSpell(unsigned short pid, const char* spellId) noexcept { Player *player; @@ -51,6 +85,36 @@ void SpellFunctions::AddSpell(unsigned short pid, const char* spellId) noexcept player->spellbookChanges.spells.push_back(spell); } +void SpellFunctions::AddSpellActive(unsigned short pid, const char* spellId, const char* displayName) noexcept +{ + Player* player; + GET_PLAYER(pid, player, ); + + mwmp::ActiveSpell spell; + spell.id = spellId; + spell.params.mDisplayName = displayName; + spell.params.mEffects = storedActiveEffects; + + player->spellsActiveChanges.activeSpells.push_back(spell); + + storedActiveEffects.clear(); +} + +void SpellFunctions::AddSpellActiveEffect(unsigned short pid, int effectId, int arg, double magnitude, double duration, double timeLeft) noexcept +{ + Player* player; + GET_PLAYER(pid, player, ); + + ESM::ActiveEffect effect; + effect.mEffectId = effectId; + effect.mArg = arg; + effect.mMagnitude = magnitude; + effect.mDuration = duration; + effect.mTimeLeft = timeLeft; + + storedActiveEffects.push_back(effect); +} + const char *SpellFunctions::GetSpellId(unsigned short pid, unsigned int index) noexcept { Player *player; @@ -62,6 +126,94 @@ const char *SpellFunctions::GetSpellId(unsigned short pid, unsigned int index) n return player->spellbookChanges.spells.at(index).mId.c_str(); } +const char* SpellFunctions::GetSpellsActiveId(unsigned short pid, unsigned int index) noexcept +{ + Player* player; + GET_PLAYER(pid, player, ""); + + if (index >= player->spellsActiveChanges.activeSpells.size()) + return "invalid"; + + return player->spellsActiveChanges.activeSpells.at(index).id.c_str(); +} + +const char* SpellFunctions::GetSpellsActiveDisplayName(unsigned short pid, unsigned int index) noexcept +{ + Player* player; + GET_PLAYER(pid, player, ""); + + if (index >= player->spellsActiveChanges.activeSpells.size()) + return "invalid"; + + return player->spellsActiveChanges.activeSpells.at(index).params.mDisplayName.c_str(); +} + +unsigned int SpellFunctions::GetSpellsActiveEffectCount(unsigned short pid, unsigned int index) noexcept +{ + Player* player; + GET_PLAYER(pid, player, 0); + + if (index >= player->spellsActiveChanges.activeSpells.size()) + return 0; + + return player->spellsActiveChanges.activeSpells.at(index).params.mEffects.size(); +} + +unsigned int SpellFunctions::GetSpellsActiveEffectId(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept +{ + Player* player; + GET_PLAYER(pid, player, 0); + + if (spellIndex >= player->spellsActiveChanges.activeSpells.size()) + return 0; + + return player->spellsActiveChanges.activeSpells.at(spellIndex).params.mEffects.at(effectIndex).mEffectId; +} + +unsigned int SpellFunctions::GetSpellsActiveEffectArg(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept +{ + Player* player; + GET_PLAYER(pid, player, 0); + + if (spellIndex >= player->spellsActiveChanges.activeSpells.size()) + return 0; + + return player->spellsActiveChanges.activeSpells.at(spellIndex).params.mEffects.at(effectIndex).mArg; +} + +double SpellFunctions::GetSpellsActiveEffectMagnitude(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept +{ + Player* player; + GET_PLAYER(pid, player, 0); + + if (spellIndex >= player->spellsActiveChanges.activeSpells.size()) + return 0; + + return player->spellsActiveChanges.activeSpells.at(spellIndex).params.mEffects.at(effectIndex).mMagnitude; +} + +double SpellFunctions::GetSpellsActiveEffectDuration(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept +{ + Player* player; + GET_PLAYER(pid, player, 0); + + if (spellIndex >= player->spellsActiveChanges.activeSpells.size()) + return 0; + + return player->spellsActiveChanges.activeSpells.at(spellIndex).params.mEffects.at(effectIndex).mDuration; +} + +double SpellFunctions::GetSpellsActiveEffectTimeLeft(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept +{ + Player* player; + GET_PLAYER(pid, player, 0); + + if (spellIndex >= player->spellsActiveChanges.activeSpells.size()) + return 0; + + return player->spellsActiveChanges.activeSpells.at(spellIndex).params.mEffects.at(effectIndex).mTimeLeft; +} + void SpellFunctions::SendSpellbookChanges(unsigned short pid, bool sendToOtherPlayers, bool skipAttachedPlayer) noexcept { Player *player; @@ -76,6 +228,20 @@ void SpellFunctions::SendSpellbookChanges(unsigned short pid, bool sendToOtherPl packet->Send(true); } +void SpellFunctions::SendSpellsActiveChanges(unsigned short pid, bool sendToOtherPlayers, bool skipAttachedPlayer) noexcept +{ + Player* player; + GET_PLAYER(pid, player, ); + + mwmp::PlayerPacket* packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SPELLS_ACTIVE); + packet->setPlayer(player); + + if (!skipAttachedPlayer) + packet->Send(false); + if (sendToOtherPlayers) + packet->Send(true); +} + // All methods below are deprecated versions of methods from above void SpellFunctions::InitializeSpellbookChanges(unsigned short pid) noexcept diff --git a/apps/openmw-mp/Script/Functions/Spells.hpp b/apps/openmw-mp/Script/Functions/Spells.hpp index d760dbdd0..e0068c9ef 100644 --- a/apps/openmw-mp/Script/Functions/Spells.hpp +++ b/apps/openmw-mp/Script/Functions/Spells.hpp @@ -2,19 +2,35 @@ #define OPENMW_SPELLAPI_HPP #define SPELLAPI \ - {"ClearSpellbookChanges", SpellFunctions::ClearSpellbookChanges},\ + {"ClearSpellbookChanges", SpellFunctions::ClearSpellbookChanges},\ + {"ClearSpellsActiveChanges", SpellFunctions::ClearSpellsActiveChanges},\ \ - {"GetSpellbookChangesSize", SpellFunctions::GetSpellbookChangesSize},\ - {"GetSpellbookChangesAction", SpellFunctions::GetSpellbookChangesAction},\ + {"GetSpellbookChangesSize", SpellFunctions::GetSpellbookChangesSize},\ + {"GetSpellbookChangesAction", SpellFunctions::GetSpellbookChangesAction},\ + {"GetSpellsActiveChangesSize", SpellFunctions::GetSpellsActiveChangesSize},\ + {"GetSpellsActiveChangesAction", SpellFunctions::GetSpellsActiveChangesAction},\ \ - {"SetSpellbookChangesAction", SpellFunctions::SetSpellbookChangesAction},\ - {"AddSpell", SpellFunctions::AddSpell},\ + {"SetSpellbookChangesAction", SpellFunctions::SetSpellbookChangesAction},\ + {"SetSpellsActiveChangesAction", SpellFunctions::SetSpellsActiveChangesAction},\ \ - {"GetSpellId", SpellFunctions::GetSpellId},\ + {"AddSpell", SpellFunctions::AddSpell},\ + {"AddSpellActive", SpellFunctions::AddSpellActive},\ + {"AddSpellActiveEffect", SpellFunctions::AddSpellActiveEffect},\ \ - {"SendSpellbookChanges", SpellFunctions::SendSpellbookChanges},\ + {"GetSpellId", SpellFunctions::GetSpellId},\ + {"GetSpellsActiveId", SpellFunctions::GetSpellsActiveId},\ + {"GetSpellsActiveDisplayName", SpellFunctions::GetSpellsActiveDisplayName},\ + {"GetSpellsActiveEffectCount", SpellFunctions::GetSpellsActiveEffectCount},\ + {"GetSpellsActiveEffectId", SpellFunctions::GetSpellsActiveEffectId},\ + {"GetSpellsActiveEffectArg", SpellFunctions::GetSpellsActiveEffectArg},\ + {"GetSpellsActiveEffectMagnitude", SpellFunctions::GetSpellsActiveEffectMagnitude},\ + {"GetSpellsActiveEffectDuration", SpellFunctions::GetSpellsActiveEffectDuration},\ + {"GetSpellsActiveEffectTimeLeft", SpellFunctions::GetSpellsActiveEffectTimeLeft},\ \ - {"InitializeSpellbookChanges", SpellFunctions::InitializeSpellbookChanges} + {"SendSpellbookChanges", SpellFunctions::SendSpellbookChanges},\ + {"SendSpellsActiveChanges", SpellFunctions::SendSpellsActiveChanges},\ + \ + {"InitializeSpellbookChanges", SpellFunctions::InitializeSpellbookChanges} class SpellFunctions { @@ -30,6 +46,16 @@ public: */ static void ClearSpellbookChanges(unsigned short pid) noexcept; + /** + * \brief Clear the last recorded spells active changes for a player. + * + * This is used to initialize the sending of new PlayerSpellsActive packets. + * + * \param pid The player ID whose spells active changes should be used. + * \return void + */ + static void ClearSpellsActiveChanges(unsigned short pid) noexcept; + /** * \brief Get the number of indexes in a player's latest spellbook changes. * @@ -46,6 +72,22 @@ public: */ static unsigned int GetSpellbookChangesAction(unsigned short pid) noexcept; + /** + * \brief Get the action type used in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \return The action type (0 for SET, 1 for ADD, 2 for REMOVE). + */ + static unsigned int GetSpellsActiveChangesAction(unsigned short pid) noexcept; + + /** + * \brief Get the number of indexes in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \return The number of indexes. + */ + static unsigned int GetSpellsActiveChangesSize(unsigned short pid) noexcept; + /** * \brief Set the action type in a player's spellbook changes. * @@ -55,6 +97,15 @@ public: */ static void SetSpellbookChangesAction(unsigned short pid, unsigned char action) noexcept; + /** + * \brief Set the action type in a player's spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param action The action (0 for SET, 1 for ADD, 2 for REMOVE). + * \return void + */ + static void SetSpellsActiveChangesAction(unsigned short pid, unsigned char action) noexcept; + /** * \brief Add a new spell to the spellbook changes for a player. * @@ -65,14 +116,115 @@ public: static void AddSpell(unsigned short pid, const char* spellId) noexcept; /** - * \brief Get the spellId at a certain index in a player's latest spellbook changes. + * \brief Add a new active spell to the spells active changes for a player, + * using the temporary effect times stored so far. + * + * \param pid The player ID whose spells active changes should be used. + * \param spellId The spellId of the spell. + * \param displayName The displayName of the spell. + * \return void + */ + static void AddSpellActive(unsigned short pid, const char* spellId, const char* displayName) noexcept; + + /** + * \brief Add a new effect to the next active spell that will be added to a player. + * + * \param pid The player ID whose spells active changes should be used. + * \param effectId The id of the effect. + * \param arg The arg of the effect. + * \param magnitude The magnitude of the effect. + * \param duration The duration of the effect. + * \param timeLeft The timeLeft for the effect. + * \return void + */ + static void AddSpellActiveEffect(unsigned short pid, int effectId, int arg, double magnitude, double duration, double timeLeft) noexcept; + + /** + * \brief Get the spell id at a certain index in a player's latest spellbook changes. * * \param pid The player ID whose spellbook changes should be used. * \param index The index of the spell. - * \return The spellId. + * \return The spell id. */ static const char *GetSpellId(unsigned short pid, unsigned int index) noexcept; + /** + * \brief Get the spell id at a certain index in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param index The index of the spell. + * \return The spell id. + */ + static const char* GetSpellsActiveId(unsigned short pid, unsigned int index) noexcept; + + /** + * \brief Get the spell display name at a certain index in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param index The index of the spell. + * \return The spell display name. + */ + static const char* GetSpellsActiveDisplayName(unsigned short pid, unsigned int index) noexcept; + + /** + * \brief Get the number of effects at an index in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param index The index of the spell. + * \return The number of effects. + */ + static unsigned int GetSpellsActiveEffectCount(unsigned short pid, unsigned int index) noexcept; + + /** + * \brief Get the id for an effect index at a spell index in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param spellIndex The index of the spell. + * \param effectIndex The index of the effect. + * \return The id of the effect. + */ + static unsigned int GetSpellsActiveEffectId(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept; + + /** + * \brief Get the arg for an effect index at a spell index in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param spellIndex The index of the spell. + * \param effectIndex The index of the effect. + * \return The arg of the effect. + */ + static unsigned int GetSpellsActiveEffectArg(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept; + + /** + * \brief Get the magnitude for an effect index at a spell index in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param spellIndex The index of the spell. + * \param effectIndex The index of the effect. + * \return The magnitude of the effect. + */ + static double GetSpellsActiveEffectMagnitude(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept; + + /** + * \brief Get the duration for an effect index at a spell index in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param spellIndex The index of the spell. + * \param effectIndex The index of the effect. + * \return The duration of the effect. + */ + static double GetSpellsActiveEffectDuration(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept; + + /** + * \brief Get the time left for an effect index at a spell index in a player's latest spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param spellIndex The index of the spell. + * \param effectIndex The index of the effect. + * \return The time left for the effect. + */ + static double GetSpellsActiveEffectTimeLeft(unsigned short pid, unsigned int spellIndex, unsigned int effectIndex) noexcept; + /** * \brief Send a PlayerSpellbook packet with a player's recorded spellbook changes. * @@ -85,6 +237,18 @@ public: */ static void SendSpellbookChanges(unsigned short pid, bool sendToOtherPlayers, bool skipAttachedPlayer) noexcept; + /** + * \brief Send a PlayerSpellsActive packet with a player's recorded spells active changes. + * + * \param pid The player ID whose spells active changes should be used. + * \param sendToOtherPlayers Whether this packet should be sent to players other than the + * player attached to the packet (false by default). + * \param skipAttachedPlayer Whether the packet should skip being sent to the player attached + * to the packet (false by default). + * \return void + */ + static void SendSpellsActiveChanges(unsigned short pid, bool sendToOtherPlayers, bool skipAttachedPlayer) noexcept; + // All methods below are deprecated versions of methods from above static void InitializeSpellbookChanges(unsigned short pid) noexcept; diff --git a/apps/openmw-mp/Script/ScriptFunctions.hpp b/apps/openmw-mp/Script/ScriptFunctions.hpp index 50de39ebc..73900785b 100644 --- a/apps/openmw-mp/Script/ScriptFunctions.hpp +++ b/apps/openmw-mp/Script/ScriptFunctions.hpp @@ -173,6 +173,7 @@ public: {"OnPlayerFaction", Callback()}, {"OnPlayerShapeshift", Callback()}, {"OnPlayerSpellbook", Callback()}, + {"OnPlayerSpellsActive", Callback()}, {"OnPlayerQuickKeys", Callback()}, {"OnPlayerTopic", Callback()}, {"OnPlayerDisposition", Callback()}, diff --git a/apps/openmw-mp/processors/ProcessorInitializer.cpp b/apps/openmw-mp/processors/ProcessorInitializer.cpp index 6a25150c4..a307d0903 100644 --- a/apps/openmw-mp/processors/ProcessorInitializer.cpp +++ b/apps/openmw-mp/processors/ProcessorInitializer.cpp @@ -37,6 +37,7 @@ #include "player/ProcessorPlayerSkill.hpp" #include "player/ProcessorPlayerSpeech.hpp" #include "player/ProcessorPlayerSpellbook.hpp" +#include "player/ProcessorPlayerSpellsActive.hpp" #include "player/ProcessorPlayerStatsDynamic.hpp" #include "player/ProcessorPlayerTopic.hpp" #include "ActorProcessor.hpp" @@ -120,6 +121,7 @@ void ProcessorInitializer() PlayerProcessor::AddProcessor(new ProcessorPlayerSkill()); PlayerProcessor::AddProcessor(new ProcessorPlayerSpeech()); PlayerProcessor::AddProcessor(new ProcessorPlayerSpellbook()); + PlayerProcessor::AddProcessor(new ProcessorPlayerSpellsActive()); PlayerProcessor::AddProcessor(new ProcessorPlayerStatsDynamic()); PlayerProcessor::AddProcessor(new ProcessorPlayerTopic()); diff --git a/apps/openmw-mp/processors/player/ProcessorPlayerSpellsActive.hpp b/apps/openmw-mp/processors/player/ProcessorPlayerSpellsActive.hpp new file mode 100644 index 000000000..8ef7025b6 --- /dev/null +++ b/apps/openmw-mp/processors/player/ProcessorPlayerSpellsActive.hpp @@ -0,0 +1,26 @@ +#ifndef OPENMW_PROCESSORPLAYERSPELLSACTIVE_HPP +#define OPENMW_PROCESSORPLAYERSPELLSACTIVE_HPP + +#include "../PlayerProcessor.hpp" + +namespace mwmp +{ + class ProcessorPlayerSpellsActive : public PlayerProcessor + { + public: + ProcessorPlayerSpellsActive() + { + BPP_INIT(ID_PLAYER_SPELLS_ACTIVE) + } + + void Do(PlayerPacket &packet, Player &player) override + { + DEBUG_PRINTF(strPacketID.c_str()); + + Script::Call(player.getId()); + } + }; +} + + +#endif //OPENMW_PROCESSORPLAYERSPELLSACTIVE_HPP diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 611993c0d..5aaa9763c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -126,7 +126,7 @@ add_openmw_dir (mwmp/processors/player ProcessorChatMessage ProcessorGUIMessageB ProcessorPlayerInput ProcessorPlayerInventory ProcessorPlayerItemUse ProcessorPlayerJail ProcessorPlayerJournal ProcessorPlayerLevel ProcessorPlayerMiscellaneous ProcessorPlayerMomentum ProcessorPlayerPosition ProcessorPlayerQuickKeys ProcessorPlayerReputation ProcessorPlayerResurrect ProcessorPlayerShapeshift ProcessorPlayerSkill ProcessorPlayerSpeech - ProcessorPlayerSpellbook ProcessorPlayerStatsDynamic ProcessorPlayerTopic + ProcessorPlayerSpellbook ProcessorPlayerSpellsActive ProcessorPlayerStatsDynamic ProcessorPlayerTopic ) add_openmw_dir (mwmp/processors/object BaseObjectProcessor diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index bb38ab6b1..dbdfee991 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -5,6 +5,20 @@ #include +/* + Start of tes3mp addition + + Include additional headers for multiplayer purposes +*/ +#include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/creaturestats.hpp" +#include "../mwworld/class.hpp" +#include "../mwmp/Main.hpp" +#include "../mwmp/LocalPlayer.hpp" +/* + End of tes3mp addition +*/ + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -24,6 +38,16 @@ namespace MWMechanics { if (!timeToExpire (iter)) { + /* + Start of tes3mp addition + + Whenever a player loses an active spell, send an ID_PLAYER_SPELLS_ACTIVE packet to the server with it + */ + mwmp::Main::get().getLocalPlayer()->sendSpellsActiveRemoval(iter->first); + /* + End of tes3mp addition + */ + mSpells.erase (iter++); rebuild = true; } @@ -164,6 +188,24 @@ namespace MWMechanics it->second = params; } + /* + Start of tes3mp addition + + Whenever a player gains an active spell, send an ID_PLAYER_SPELLS_ACTIVE packet to the server with it + */ + ESM::ActiveSpells::ActiveSpellParams esmParams; + esmParams.mEffects = effects; + esmParams.mDisplayName = displayName; + esmParams.mCasterActorId = casterActorId; + + if (this == &MWMechanics::getPlayer().getClass().getCreatureStats(MWMechanics::getPlayer()).getActiveSpells()) + { + mwmp::Main::get().getLocalPlayer()->sendSpellsActiveAddition(id, esmParams); + } + /* + End of tes3mp addition + */ + mSpellsChanged = true; } diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 7410230ea..4f42a404c 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -712,6 +712,23 @@ void LocalPlayer::addSpells() LOG_APPEND(TimedLog::LOG_INFO, "- Ignored addition of invalid spell %s", spell.mId.c_str()); } +void LocalPlayer::addSpellsActive() +{ + MWWorld::Ptr ptrPlayer = getPlayerPtr(); + MWMechanics::ActiveSpells& activeSpells = ptrPlayer.getClass().getCreatureStats(ptrPlayer).getActiveSpells(); + + for (const auto& activeSpell : spellsActiveChanges.activeSpells) + { + // Only add spells that are ensured to exist + if (MWBase::Environment::get().getWorld()->getStore().get().search(activeSpell.id)) + { + activeSpells.addSpell(activeSpell.id, false, activeSpell.params.mEffects, activeSpell.params.mDisplayName, 1); + } + else + LOG_APPEND(TimedLog::LOG_INFO, "- Ignored addition of invalid spell %s", activeSpell.id.c_str()); + } +} + void LocalPlayer::addJournalItems() { for (const auto &journalItem : journalChanges) @@ -803,6 +820,17 @@ void LocalPlayer::removeSpells() } } +void LocalPlayer::removeSpellsActive() +{ + MWWorld::Ptr ptrPlayer = getPlayerPtr(); + MWMechanics::ActiveSpells& activeSpells = ptrPlayer.getClass().getCreatureStats(ptrPlayer).getActiveSpells(); + + for (const auto& activeSpell : spellsActiveChanges.activeSpells) + { + activeSpells.removeEffects(activeSpell.id); + } +} + void LocalPlayer::resurrect() { creatureStats.mDead = false; @@ -1210,6 +1238,16 @@ void LocalPlayer::setSpellbook() addSpells(); } +void LocalPlayer::setSpellsActive() +{ + MWWorld::Ptr ptrPlayer = getPlayerPtr(); + MWMechanics::ActiveSpells& activeSpells = ptrPlayer.getClass().getCreatureStats(ptrPlayer).getActiveSpells(); + activeSpells.clear(); + + // Proceed by adding spells active + addSpellsActive(); +} + void LocalPlayer::setQuickKeys() { MWWorld::Ptr ptrPlayer = getPlayerPtr(); @@ -1522,6 +1560,63 @@ void LocalPlayer::sendSpellChange(std::string id, unsigned int action) getNetworking()->getPlayerPacket(ID_PLAYER_SPELLBOOK)->Send(); } +void LocalPlayer::sendSpellsActive() +{ + MWWorld::Ptr ptrPlayer = getPlayerPtr(); + MWMechanics::ActiveSpells& activeSpells = ptrPlayer.getClass().getCreatureStats(ptrPlayer).getActiveSpells(); + + spellsActiveChanges.activeSpells.clear(); + + // Send spells in spellbook, while ignoring abilities, powers, etc. + for (const auto& ptrSpell : activeSpells) + { + mwmp::ActiveSpell packetSpell; + packetSpell.id = ptrSpell.first; + packetSpell.params.mDisplayName = ptrSpell.second.mDisplayName; + packetSpell.params.mEffects = ptrSpell.second.mEffects; + spellsActiveChanges.activeSpells.push_back(packetSpell); + } + + spellsActiveChanges.action = mwmp::SpellsActiveChanges::SET; + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLS_ACTIVE)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLS_ACTIVE)->Send(); +} + +void LocalPlayer::sendSpellsActiveAddition(const std::string id, ESM::ActiveSpells::ActiveSpellParams params) +{ + // Skip any bugged spells that somehow have clientside-only dynamic IDs + if (id.find("$dynamic") != string::npos) + return; + + spellsActiveChanges.activeSpells.clear(); + + mwmp::ActiveSpell spell; + spell.id = id; + spell.params = params; + spellsActiveChanges.activeSpells.push_back(spell); + + spellsActiveChanges.action = mwmp::SpellsActiveChanges::ADD; + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLS_ACTIVE)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLS_ACTIVE)->Send(); +} + +void LocalPlayer::sendSpellsActiveRemoval(const std::string id) +{ + // Skip any bugged spells that somehow have clientside-only dynamic IDs + if (id.find("$dynamic") != string::npos) + return; + + spellsActiveChanges.activeSpells.clear(); + + mwmp::ActiveSpell spell; + spell.id = id; + spellsActiveChanges.activeSpells.push_back(spell); + + spellsActiveChanges.action = mwmp::SpellsActiveChanges::REMOVE; + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLS_ACTIVE)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_SPELLS_ACTIVE)->Send(); +} + void LocalPlayer::sendQuickKey(unsigned short slot, int type, const std::string& itemId) { quickKeyChanges.clear(); diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 5fe5097c1..8f81fe88a 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -45,11 +45,13 @@ namespace mwmp void addItems(); void addSpells(); + void addSpellsActive(); void addJournalItems(); void addTopics(); void removeItems(); void removeSpells(); + void removeSpellsActive(); void resurrect(); @@ -70,6 +72,7 @@ namespace mwmp void setEquipment(); void setInventory(); void setSpellbook(); + void setSpellsActive(); void setQuickKeys(); void setFactions(); void setBooks(); @@ -86,6 +89,9 @@ namespace mwmp void sendStoredItemRemovals(); void sendSpellbook(); void sendSpellChange(std::string id, unsigned int action); + void sendSpellsActive(); + void sendSpellsActiveAddition(const std::string id, ESM::ActiveSpells::ActiveSpellParams params); + void sendSpellsActiveRemoval(const std::string id); void sendQuickKey(unsigned short slot, int type, const std::string& itemId = ""); void sendJournalEntry(const std::string& quest, int index, const MWWorld::Ptr& actor); void sendJournalIndex(const std::string& quest, int index); diff --git a/apps/openmw/mwmp/processors/ProcessorInitializer.cpp b/apps/openmw/mwmp/processors/ProcessorInitializer.cpp index ec47e5068..0f7f8a76e 100644 --- a/apps/openmw/mwmp/processors/ProcessorInitializer.cpp +++ b/apps/openmw/mwmp/processors/ProcessorInitializer.cpp @@ -43,6 +43,7 @@ #include "player/ProcessorPlayerSkill.hpp" #include "player/ProcessorPlayerSpeech.hpp" #include "player/ProcessorPlayerSpellbook.hpp" +#include "player/ProcessorPlayerSpellsActive.hpp" #include "player/ProcessorPlayerStatsDynamic.hpp" #include "player/ProcessorPlayerTopic.hpp" @@ -146,6 +147,7 @@ void ProcessorInitializer() PlayerProcessor::AddProcessor(new ProcessorPlayerSkill()); PlayerProcessor::AddProcessor(new ProcessorPlayerSpeech()); PlayerProcessor::AddProcessor(new ProcessorPlayerSpellbook()); + PlayerProcessor::AddProcessor(new ProcessorPlayerSpellsActive()); PlayerProcessor::AddProcessor(new ProcessorPlayerStatsDynamic()); PlayerProcessor::AddProcessor(new ProcessorPlayerTopic()); diff --git a/apps/openmw/mwmp/processors/player/ProcessorPlayerSpellsActive.hpp b/apps/openmw/mwmp/processors/player/ProcessorPlayerSpellsActive.hpp new file mode 100644 index 000000000..95752831b --- /dev/null +++ b/apps/openmw/mwmp/processors/player/ProcessorPlayerSpellsActive.hpp @@ -0,0 +1,42 @@ +#ifndef OPENMW_PROCESSORPLAYERSPELLSACTIVE_HPP +#define OPENMW_PROCESSORPLAYERSPELLSACTIVE_HPP + + +#include "../PlayerProcessor.hpp" + +namespace mwmp +{ + class ProcessorPlayerSpellsActive final: public PlayerProcessor + { + public: + ProcessorPlayerSpellsActive() + { + BPP_INIT(ID_PLAYER_SPELLS_ACTIVE) + } + + virtual void Do(PlayerPacket &packet, BasePlayer *player) + { + if (!isLocal()) return; + + LOG_MESSAGE_SIMPLE(TimedLog::LOG_INFO, "Received ID_PLAYER_SPELLS_ACTIVE about LocalPlayer from server"); + + if (isRequest()) + static_cast(player)->sendSpellsActive(); + else + { + LocalPlayer &localPlayer = static_cast(*player); + + int spellsActiveAction = localPlayer.spellsActiveChanges.action; + + if (spellsActiveAction == SpellsActiveChanges::ADD) + localPlayer.addSpellsActive(); + else if (spellsActiveAction == SpellsActiveChanges::REMOVE) + localPlayer.removeSpellsActive(); + else // SpellsActiveChanges::SET + localPlayer.setSpellsActive(); + } + } + }; +} + +#endif //OPENMW_PROCESSORPLAYERSPELLSACTIVE_HPP diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index ae71a66ab..ff9dc0e2a 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -75,6 +75,12 @@ namespace mwmp int type; }; + struct ActiveSpell + { + std::string id; + ESM::ActiveSpells::ActiveSpellParams params; + }; + struct CellState { ESM::Cell cell; @@ -126,6 +132,18 @@ namespace mwmp int action; // 0 - Clear and set in entirety, 1 - Add spell, 2 - Remove spell }; + struct SpellsActiveChanges + { + std::vector activeSpells; + enum ACTION_TYPE + { + SET = 0, + ADD, + REMOVE + }; + int action; // 0 - Clear and set in entirety, 1 - Add spell, 2 - Remove spell + }; + enum RESURRECT_TYPE { REGULAR = 0, @@ -208,6 +226,7 @@ namespace mwmp InventoryChanges inventoryChanges; SpellbookChanges spellbookChanges; + SpellsActiveChanges spellsActiveChanges; std::vector quickKeyChanges; std::vector journalChanges; FactionChanges factionChanges; @@ -215,7 +234,6 @@ namespace mwmp std::vector bookChanges; std::vector cellStateChanges; - ESM::ActiveSpells activeSpells; std::vector alliedPlayers; CurrentContainer currentContainer; diff --git a/components/openmw-mp/Packets/Player/PacketPlayerSpellsActive.cpp b/components/openmw-mp/Packets/Player/PacketPlayerSpellsActive.cpp index 6ebec15d6..585a190b1 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerSpellsActive.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerSpellsActive.cpp @@ -12,43 +12,51 @@ void PacketPlayerSpellsActive::Packet(RakNet::BitStream *newBitstream, bool send { PlayerPacket::Packet(newBitstream, send); - uint32_t spells = 0; + RW(player->spellsActiveChanges.action, send); + + uint32_t count; if (send) - spells = player->activeSpells.mSpells.size(); + count = static_cast(player->spellsActiveChanges.activeSpells.size()); - RW(spells, send); + RW(count, send); - if (send) - for (ESM::ActiveSpells::TContainer::const_iterator spell = player->activeSpells.mSpells.begin(); - spell != player->activeSpells.mSpells.end(); ++spell) + if (!send) + { + player->spellsActiveChanges.activeSpells.clear(); + player->spellsActiveChanges.activeSpells.resize(count); + } + + for (auto&& activeSpell : player->spellsActiveChanges.activeSpells) + { + RW(activeSpell.id, send, true); + RW(activeSpell.params.mDisplayName, send, true); + + uint32_t effectCount; + + if (send) + effectCount = static_cast(activeSpell.params.mEffects.size()); + + RW(effectCount, send); + + if (effectCount > maxEffects) { - RW(spell->first, true); - //RW(spell->second.mTimeStamp, true); - uint32_t effects = spell->second.mEffects.size(); - RW(effects, true); - - for (std::vector::const_iterator effect = spell->second.mEffects.begin(); - effect != spell->second.mEffects.end(); ++effect) - RW(effect, true); - + return; } - else - for (uint32_t i = 0; i < spells; i++) + + if (!send) { - ESM::ActiveSpells::TContainer::value_type spell; - - RW(spell.first, false); - //RW(spell.second.mTimeStamp, false); - uint32_t effects; - RW(effects, false); - - ESM::ActiveEffect effect; - for (uint32_t j = 0; j < effects; j++) - { - RW(effect, false); - spell.second.mEffects.push_back(effect); - } - player->activeSpells.mSpells.insert(spell); + activeSpell.params.mEffects.clear(); + activeSpell.params.mEffects.resize(effectCount); } + + for (auto&& effect : activeSpell.params.mEffects) + { + RW(effect.mEffectId, send); + RW(effect.mArg, send); + RW(effect.mMagnitude, send); + RW(effect.mDuration, send); + RW(effect.mTimeLeft, send); + } + } } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerSpellsActive.hpp b/components/openmw-mp/Packets/Player/PacketPlayerSpellsActive.hpp index 437658f8b..60ee276b5 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerSpellsActive.hpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerSpellsActive.hpp @@ -11,6 +11,9 @@ namespace mwmp PacketPlayerSpellsActive(RakNet::RakPeerInterface *peer); virtual void Packet(RakNet::BitStream *newBitstream, bool send); + + protected: + static const int maxEffects = 20; }; }