1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 18:19:55 +00:00

[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.
This commit is contained in:
David Cernat 2020-07-10 02:09:11 +02:00
parent 3a8831dc15
commit c56cd7c221
15 changed files with 620 additions and 44 deletions

View file

@ -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})

View file

@ -8,6 +8,8 @@
using namespace mwmp;
std::vector<ESM::ActiveEffect> 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

View file

@ -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;

View file

@ -173,6 +173,7 @@ public:
{"OnPlayerFaction", Callback<unsigned short>()},
{"OnPlayerShapeshift", Callback<unsigned short>()},
{"OnPlayerSpellbook", Callback<unsigned short>()},
{"OnPlayerSpellsActive", Callback<unsigned short>()},
{"OnPlayerQuickKeys", Callback<unsigned short>()},
{"OnPlayerTopic", Callback<unsigned short>()},
{"OnPlayerDisposition", Callback<unsigned short>()},

View file

@ -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());

View file

@ -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<Script::CallbackIdentity("OnPlayerSpellsActive")>(player.getId());
}
};
}
#endif //OPENMW_PROCESSORPLAYERSPELLSACTIVE_HPP

View file

@ -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

View file

@ -5,6 +5,20 @@
#include <components/esm/loadmgef.hpp>
/*
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;
}

View file

@ -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<ESM::Spell>().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();

View file

@ -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);

View file

@ -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());

View file

@ -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<LocalPlayer*>(player)->sendSpellsActive();
else
{
LocalPlayer &localPlayer = static_cast<LocalPlayer&>(*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

View file

@ -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<ActiveSpell> 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<QuickKey> quickKeyChanges;
std::vector<JournalItem> journalChanges;
FactionChanges factionChanges;
@ -215,7 +234,6 @@ namespace mwmp
std::vector<Book> bookChanges;
std::vector<CellState> cellStateChanges;
ESM::ActiveSpells activeSpells;
std::vector<RakNet::RakNetGUID> alliedPlayers;
CurrentContainer currentContainer;

View file

@ -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<uint32_t>(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<uint32_t>(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<ESM::ActiveEffect>::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);
}
}
}

View file

@ -11,6 +11,9 @@ namespace mwmp
PacketPlayerSpellsActive(RakNet::RakPeerInterface *peer);
virtual void Packet(RakNet::BitStream *newBitstream, bool send);
protected:
static const int maxEffects = 20;
};
}