1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-03-30 10:36:42 +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/ProcessorPlayerRest.hpp processors/player/ProcessorPlayerResurrect.hpp
processors/player/ProcessorPlayerShapeshift.hpp processors/player/ProcessorPlayerSkill.hpp processors/player/ProcessorPlayerShapeshift.hpp processors/player/ProcessorPlayerSkill.hpp
processors/player/ProcessorPlayerSpeech.hpp processors/player/ProcessorPlayerSpellbook.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}) source_group(tes3mp-server\\processors\\player FILES ${PROCESSORS_PLAYER})

View file

@ -8,6 +8,8 @@
using namespace mwmp; using namespace mwmp;
std::vector<ESM::ActiveEffect> storedActiveEffects;
void SpellFunctions::ClearSpellbookChanges(unsigned short pid) noexcept void SpellFunctions::ClearSpellbookChanges(unsigned short pid) noexcept
{ {
Player *player; Player *player;
@ -16,6 +18,14 @@ void SpellFunctions::ClearSpellbookChanges(unsigned short pid) noexcept
player->spellbookChanges.spells.clear(); 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 unsigned int SpellFunctions::GetSpellbookChangesSize(unsigned short pid) noexcept
{ {
Player *player; Player *player;
@ -32,6 +42,22 @@ unsigned int SpellFunctions::GetSpellbookChangesAction(unsigned short pid) noexc
return player->spellbookChanges.action; 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 void SpellFunctions::SetSpellbookChangesAction(unsigned short pid, unsigned char action) noexcept
{ {
Player *player; Player *player;
@ -40,6 +66,14 @@ void SpellFunctions::SetSpellbookChangesAction(unsigned short pid, unsigned char
player->spellbookChanges.action = action; 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 void SpellFunctions::AddSpell(unsigned short pid, const char* spellId) noexcept
{ {
Player *player; Player *player;
@ -51,6 +85,36 @@ void SpellFunctions::AddSpell(unsigned short pid, const char* spellId) noexcept
player->spellbookChanges.spells.push_back(spell); 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 const char *SpellFunctions::GetSpellId(unsigned short pid, unsigned int index) noexcept
{ {
Player *player; 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(); 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 void SpellFunctions::SendSpellbookChanges(unsigned short pid, bool sendToOtherPlayers, bool skipAttachedPlayer) noexcept
{ {
Player *player; Player *player;
@ -76,6 +228,20 @@ void SpellFunctions::SendSpellbookChanges(unsigned short pid, bool sendToOtherPl
packet->Send(true); 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 // All methods below are deprecated versions of methods from above
void SpellFunctions::InitializeSpellbookChanges(unsigned short pid) noexcept void SpellFunctions::InitializeSpellbookChanges(unsigned short pid) noexcept

View file

@ -3,16 +3,32 @@
#define SPELLAPI \ #define SPELLAPI \
{"ClearSpellbookChanges", SpellFunctions::ClearSpellbookChanges},\ {"ClearSpellbookChanges", SpellFunctions::ClearSpellbookChanges},\
{"ClearSpellsActiveChanges", SpellFunctions::ClearSpellsActiveChanges},\
\ \
{"GetSpellbookChangesSize", SpellFunctions::GetSpellbookChangesSize},\ {"GetSpellbookChangesSize", SpellFunctions::GetSpellbookChangesSize},\
{"GetSpellbookChangesAction", SpellFunctions::GetSpellbookChangesAction},\ {"GetSpellbookChangesAction", SpellFunctions::GetSpellbookChangesAction},\
{"GetSpellsActiveChangesSize", SpellFunctions::GetSpellsActiveChangesSize},\
{"GetSpellsActiveChangesAction", SpellFunctions::GetSpellsActiveChangesAction},\
\ \
{"SetSpellbookChangesAction", SpellFunctions::SetSpellbookChangesAction},\ {"SetSpellbookChangesAction", SpellFunctions::SetSpellbookChangesAction},\
{"SetSpellsActiveChangesAction", SpellFunctions::SetSpellsActiveChangesAction},\
\
{"AddSpell", SpellFunctions::AddSpell},\ {"AddSpell", SpellFunctions::AddSpell},\
{"AddSpellActive", SpellFunctions::AddSpellActive},\
{"AddSpellActiveEffect", SpellFunctions::AddSpellActiveEffect},\
\ \
{"GetSpellId", SpellFunctions::GetSpellId},\ {"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},\
\ \
{"SendSpellbookChanges", SpellFunctions::SendSpellbookChanges},\ {"SendSpellbookChanges", SpellFunctions::SendSpellbookChanges},\
{"SendSpellsActiveChanges", SpellFunctions::SendSpellsActiveChanges},\
\ \
{"InitializeSpellbookChanges", SpellFunctions::InitializeSpellbookChanges} {"InitializeSpellbookChanges", SpellFunctions::InitializeSpellbookChanges}
@ -30,6 +46,16 @@ public:
*/ */
static void ClearSpellbookChanges(unsigned short pid) noexcept; 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. * \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; 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. * \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; 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. * \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; 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 pid The player ID whose spellbook changes should be used.
* \param index The index of the spell. * \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; 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. * \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; 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 // All methods below are deprecated versions of methods from above
static void InitializeSpellbookChanges(unsigned short pid) noexcept; static void InitializeSpellbookChanges(unsigned short pid) noexcept;

View file

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

View file

@ -37,6 +37,7 @@
#include "player/ProcessorPlayerSkill.hpp" #include "player/ProcessorPlayerSkill.hpp"
#include "player/ProcessorPlayerSpeech.hpp" #include "player/ProcessorPlayerSpeech.hpp"
#include "player/ProcessorPlayerSpellbook.hpp" #include "player/ProcessorPlayerSpellbook.hpp"
#include "player/ProcessorPlayerSpellsActive.hpp"
#include "player/ProcessorPlayerStatsDynamic.hpp" #include "player/ProcessorPlayerStatsDynamic.hpp"
#include "player/ProcessorPlayerTopic.hpp" #include "player/ProcessorPlayerTopic.hpp"
#include "ActorProcessor.hpp" #include "ActorProcessor.hpp"
@ -120,6 +121,7 @@ void ProcessorInitializer()
PlayerProcessor::AddProcessor(new ProcessorPlayerSkill()); PlayerProcessor::AddProcessor(new ProcessorPlayerSkill());
PlayerProcessor::AddProcessor(new ProcessorPlayerSpeech()); PlayerProcessor::AddProcessor(new ProcessorPlayerSpeech());
PlayerProcessor::AddProcessor(new ProcessorPlayerSpellbook()); PlayerProcessor::AddProcessor(new ProcessorPlayerSpellbook());
PlayerProcessor::AddProcessor(new ProcessorPlayerSpellsActive());
PlayerProcessor::AddProcessor(new ProcessorPlayerStatsDynamic()); PlayerProcessor::AddProcessor(new ProcessorPlayerStatsDynamic());
PlayerProcessor::AddProcessor(new ProcessorPlayerTopic()); 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 ProcessorPlayerInput ProcessorPlayerInventory ProcessorPlayerItemUse ProcessorPlayerJail ProcessorPlayerJournal
ProcessorPlayerLevel ProcessorPlayerMiscellaneous ProcessorPlayerMomentum ProcessorPlayerPosition ProcessorPlayerQuickKeys ProcessorPlayerLevel ProcessorPlayerMiscellaneous ProcessorPlayerMomentum ProcessorPlayerPosition ProcessorPlayerQuickKeys
ProcessorPlayerReputation ProcessorPlayerResurrect ProcessorPlayerShapeshift ProcessorPlayerSkill ProcessorPlayerSpeech ProcessorPlayerReputation ProcessorPlayerResurrect ProcessorPlayerShapeshift ProcessorPlayerSkill ProcessorPlayerSpeech
ProcessorPlayerSpellbook ProcessorPlayerStatsDynamic ProcessorPlayerTopic ProcessorPlayerSpellbook ProcessorPlayerSpellsActive ProcessorPlayerStatsDynamic ProcessorPlayerTopic
) )
add_openmw_dir (mwmp/processors/object BaseObjectProcessor add_openmw_dir (mwmp/processors/object BaseObjectProcessor

View file

@ -5,6 +5,20 @@
#include <components/esm/loadmgef.hpp> #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/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -24,6 +38,16 @@ namespace MWMechanics
{ {
if (!timeToExpire (iter)) 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++); mSpells.erase (iter++);
rebuild = true; rebuild = true;
} }
@ -164,6 +188,24 @@ namespace MWMechanics
it->second = params; 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; 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()); 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() void LocalPlayer::addJournalItems()
{ {
for (const auto &journalItem : journalChanges) 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() void LocalPlayer::resurrect()
{ {
creatureStats.mDead = false; creatureStats.mDead = false;
@ -1210,6 +1238,16 @@ void LocalPlayer::setSpellbook()
addSpells(); 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() void LocalPlayer::setQuickKeys()
{ {
MWWorld::Ptr ptrPlayer = getPlayerPtr(); MWWorld::Ptr ptrPlayer = getPlayerPtr();
@ -1522,6 +1560,63 @@ void LocalPlayer::sendSpellChange(std::string id, unsigned int action)
getNetworking()->getPlayerPacket(ID_PLAYER_SPELLBOOK)->Send(); 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) void LocalPlayer::sendQuickKey(unsigned short slot, int type, const std::string& itemId)
{ {
quickKeyChanges.clear(); quickKeyChanges.clear();

View file

@ -45,11 +45,13 @@ namespace mwmp
void addItems(); void addItems();
void addSpells(); void addSpells();
void addSpellsActive();
void addJournalItems(); void addJournalItems();
void addTopics(); void addTopics();
void removeItems(); void removeItems();
void removeSpells(); void removeSpells();
void removeSpellsActive();
void resurrect(); void resurrect();
@ -70,6 +72,7 @@ namespace mwmp
void setEquipment(); void setEquipment();
void setInventory(); void setInventory();
void setSpellbook(); void setSpellbook();
void setSpellsActive();
void setQuickKeys(); void setQuickKeys();
void setFactions(); void setFactions();
void setBooks(); void setBooks();
@ -86,6 +89,9 @@ namespace mwmp
void sendStoredItemRemovals(); void sendStoredItemRemovals();
void sendSpellbook(); void sendSpellbook();
void sendSpellChange(std::string id, unsigned int action); 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 sendQuickKey(unsigned short slot, int type, const std::string& itemId = "");
void sendJournalEntry(const std::string& quest, int index, const MWWorld::Ptr& actor); void sendJournalEntry(const std::string& quest, int index, const MWWorld::Ptr& actor);
void sendJournalIndex(const std::string& quest, int index); void sendJournalIndex(const std::string& quest, int index);

View file

@ -43,6 +43,7 @@
#include "player/ProcessorPlayerSkill.hpp" #include "player/ProcessorPlayerSkill.hpp"
#include "player/ProcessorPlayerSpeech.hpp" #include "player/ProcessorPlayerSpeech.hpp"
#include "player/ProcessorPlayerSpellbook.hpp" #include "player/ProcessorPlayerSpellbook.hpp"
#include "player/ProcessorPlayerSpellsActive.hpp"
#include "player/ProcessorPlayerStatsDynamic.hpp" #include "player/ProcessorPlayerStatsDynamic.hpp"
#include "player/ProcessorPlayerTopic.hpp" #include "player/ProcessorPlayerTopic.hpp"
@ -146,6 +147,7 @@ void ProcessorInitializer()
PlayerProcessor::AddProcessor(new ProcessorPlayerSkill()); PlayerProcessor::AddProcessor(new ProcessorPlayerSkill());
PlayerProcessor::AddProcessor(new ProcessorPlayerSpeech()); PlayerProcessor::AddProcessor(new ProcessorPlayerSpeech());
PlayerProcessor::AddProcessor(new ProcessorPlayerSpellbook()); PlayerProcessor::AddProcessor(new ProcessorPlayerSpellbook());
PlayerProcessor::AddProcessor(new ProcessorPlayerSpellsActive());
PlayerProcessor::AddProcessor(new ProcessorPlayerStatsDynamic()); PlayerProcessor::AddProcessor(new ProcessorPlayerStatsDynamic());
PlayerProcessor::AddProcessor(new ProcessorPlayerTopic()); 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; int type;
}; };
struct ActiveSpell
{
std::string id;
ESM::ActiveSpells::ActiveSpellParams params;
};
struct CellState struct CellState
{ {
ESM::Cell cell; ESM::Cell cell;
@ -126,6 +132,18 @@ namespace mwmp
int action; // 0 - Clear and set in entirety, 1 - Add spell, 2 - Remove spell 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 enum RESURRECT_TYPE
{ {
REGULAR = 0, REGULAR = 0,
@ -208,6 +226,7 @@ namespace mwmp
InventoryChanges inventoryChanges; InventoryChanges inventoryChanges;
SpellbookChanges spellbookChanges; SpellbookChanges spellbookChanges;
SpellsActiveChanges spellsActiveChanges;
std::vector<QuickKey> quickKeyChanges; std::vector<QuickKey> quickKeyChanges;
std::vector<JournalItem> journalChanges; std::vector<JournalItem> journalChanges;
FactionChanges factionChanges; FactionChanges factionChanges;
@ -215,7 +234,6 @@ namespace mwmp
std::vector<Book> bookChanges; std::vector<Book> bookChanges;
std::vector<CellState> cellStateChanges; std::vector<CellState> cellStateChanges;
ESM::ActiveSpells activeSpells;
std::vector<RakNet::RakNetGUID> alliedPlayers; std::vector<RakNet::RakNetGUID> alliedPlayers;
CurrentContainer currentContainer; CurrentContainer currentContainer;

View file

@ -12,43 +12,51 @@ void PacketPlayerSpellsActive::Packet(RakNet::BitStream *newBitstream, bool send
{ {
PlayerPacket::Packet(newBitstream, send); PlayerPacket::Packet(newBitstream, send);
uint32_t spells = 0; RW(player->spellsActiveChanges.action, send);
uint32_t count;
if (send) if (send)
spells = player->activeSpells.mSpells.size(); count = static_cast<uint32_t>(player->spellsActiveChanges.activeSpells.size());
RW(spells, send); RW(count, send);
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) if (send)
for (ESM::ActiveSpells::TContainer::const_iterator spell = player->activeSpells.mSpells.begin(); effectCount = static_cast<uint32_t>(activeSpell.params.mEffects.size());
spell != player->activeSpells.mSpells.end(); ++spell)
RW(effectCount, send);
if (effectCount > maxEffects)
{ {
RW(spell->first, true); return;
//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);
} }
else
for (uint32_t i = 0; i < spells; i++)
{
ESM::ActiveSpells::TContainer::value_type spell;
RW(spell.first, false); if (!send)
//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); activeSpell.params.mEffects.clear();
spell.second.mEffects.push_back(effect); 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);
} }
player->activeSpells.mSpells.insert(spell);
} }
} }

View file

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