[General] Implement ActorDeath packet, part 1

ActorDeath packets are sent for dead actors before their StatsDynamic packets. They contain the actor's deathReason in a manner similar to that of PlayerDeath packets.

A future commit will replace the deathReason with a variable named killer which will be an mwmp::Target.
This commit is contained in:
David Cernat 2018-06-27 21:47:55 +03:00
parent 15bfa30070
commit 7ffdb18bf9
14 changed files with 90 additions and 5 deletions

View file

@ -113,10 +113,10 @@ source_group(tes3mp-server FILES ${SERVER} ${SERVER_HEADER})
set(PROCESSORS_ACTOR set(PROCESSORS_ACTOR
processors/actor/ProcessorActorAnimFlags.hpp processors/actor/ProcessorActorAnimPlay.hpp processors/actor/ProcessorActorAnimFlags.hpp processors/actor/ProcessorActorAnimPlay.hpp
processors/actor/ProcessorActorAttack.hpp processors/actor/ProcessorActorCellChange.hpp processors/actor/ProcessorActorAttack.hpp processors/actor/ProcessorActorCellChange.hpp
processors/actor/ProcessorActorEquipment.hpp processors/actor/ProcessorActorInteraction.hpp processors/actor/ProcessorActorDeath.hpp processors/actor/ProcessorActorEquipment.hpp
processors/actor/ProcessorActorList.hpp processors/actor/ProcessorActorPosition.hpp processors/actor/ProcessorActorInteraction.hpp processors/actor/ProcessorActorList.hpp
processors/actor/ProcessorActorSpeech.hpp processors/actor/ProcessorActorStatsDynamic.hpp processors/actor/ProcessorActorPosition.hpp processors/actor/ProcessorActorSpeech.hpp
processors/actor/ProcessorActorTest.hpp processors/actor/ProcessorActorStatsDynamic.hpp processors/actor/ProcessorActorTest.hpp
) )
source_group(tes3mp-server\\processors\\actor FILES ${PROCESSORS_ACTOR}) source_group(tes3mp-server\\processors\\actor FILES ${PROCESSORS_ACTOR})

View file

@ -168,6 +168,11 @@ double ActorFunctions::GetActorEquipmentItemEnchantmentCharge(unsigned int i, un
return readActorList->baseActors.at(i).equipmentItems[slot].enchantmentCharge; return readActorList->baseActors.at(i).equipmentItems[slot].enchantmentCharge;
} }
const char *ActorFunctions::GetActorDeathReason(unsigned int i) noexcept
{
return readActorList->baseActors.at(i).deathReason.c_str();
}
bool ActorFunctions::DoesActorHavePosition(unsigned int i) noexcept bool ActorFunctions::DoesActorHavePosition(unsigned int i) noexcept
{ {
return readActorList->baseActors.at(i).hasPositionData; return readActorList->baseActors.at(i).hasPositionData;

View file

@ -36,6 +36,8 @@
{"GetActorEquipmentItemCharge", ActorFunctions::GetActorEquipmentItemCharge},\ {"GetActorEquipmentItemCharge", ActorFunctions::GetActorEquipmentItemCharge},\
{"GetActorEquipmentItemEnchantmentCharge", ActorFunctions::GetActorEquipmentItemEnchantmentCharge},\ {"GetActorEquipmentItemEnchantmentCharge", ActorFunctions::GetActorEquipmentItemEnchantmentCharge},\
\ \
{"GetActorDeathReason", ActorFunctions::GetActorDeathReason},\
\
{"DoesActorHavePosition", ActorFunctions::DoesActorHavePosition},\ {"DoesActorHavePosition", ActorFunctions::DoesActorHavePosition},\
{"DoesActorHaveStatsDynamic", ActorFunctions::DoesActorHaveStatsDynamic},\ {"DoesActorHaveStatsDynamic", ActorFunctions::DoesActorHaveStatsDynamic},\
\ \
@ -315,6 +317,14 @@ public:
*/ */
static double GetActorEquipmentItemEnchantmentCharge(unsigned int i, unsigned short slot) noexcept; static double GetActorEquipmentItemEnchantmentCharge(unsigned int i, unsigned short slot) noexcept;
/**
* \brief Get the death reason of the actor at a certain index in the read actor list.
*
* \param i The index of the actor.
* \return The death reason.
*/
static const char *GetActorDeathReason(unsigned int i) noexcept;
/** /**
* \brief Check whether there is any positional data for the actor at a certain index in * \brief Check whether there is any positional data for the actor at a certain index in
* the read actor list. * the read actor list.

View file

@ -340,6 +340,7 @@ public:
{"OnObjectTrap", Function<void, unsigned short, const char*>()}, {"OnObjectTrap", Function<void, unsigned short, const char*>()},
{"OnActorList", Function<void, unsigned short, const char*>()}, {"OnActorList", Function<void, unsigned short, const char*>()},
{"OnActorEquipment", Function<void, unsigned short, const char*>()}, {"OnActorEquipment", Function<void, unsigned short, const char*>()},
{"OnActorDeath", Function<void, unsigned short, const char*>()},
{"OnActorCellChange", Function<void, unsigned short, const char*>()}, {"OnActorCellChange", Function<void, unsigned short, const char*>()},
{"OnActorTest", Function<void, unsigned short, const char*>()}, {"OnActorTest", Function<void, unsigned short, const char*>()},
{"OnPlayerSendMessage", Function<bool, unsigned short, const char*>()}, {"OnPlayerSendMessage", Function<bool, unsigned short, const char*>()},

View file

@ -19,7 +19,11 @@ namespace mwmp
Cell *serverCell = CellController::get()->getCell(&actorList.cell); Cell *serverCell = CellController::get()->getCell(&actorList.cell);
if (serverCell != nullptr && *serverCell->getAuthority() == actorList.guid) if (serverCell != nullptr && *serverCell->getAuthority() == actorList.guid)
{
Script::Call<Script::CallbackIdentity("OnActorDeath")>(player.getId(), actorList.cell.getDescription().c_str());
serverCell->sendToLoaded(&packet, &actorList); serverCell->sendToLoaded(&packet, &actorList);
}
} }
}; };
} }

View file

@ -540,6 +540,8 @@ namespace MWClass
Start of tes3mp addition Start of tes3mp addition
If the attacker was the LocalPlayer or LocalActor, record their target and send a packet with it If the attacker was the LocalPlayer or LocalActor, record their target and send a packet with it
If the victim was a LocalActor who died, record their attacker as the deathReason
*/ */
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker); mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
@ -553,6 +555,14 @@ namespace MWClass
localAttack->shouldSend = true; localAttack->shouldSend = true;
} }
if (mwmp::Main::get().getCellController()->isLocalActor(ptr))
{
if (getCreatureStats(ptr).isDead())
{
mwmp::Main::get().getCellController()->getLocalActor(ptr)->deathReason = attacker.getClass().getName(attacker);
}
}
/* /*
End of tes3mp addition End of tes3mp addition
*/ */

View file

@ -953,6 +953,8 @@ namespace MWClass
If the victim was the LocalPlayer, check whether packets should be sent about If the victim was the LocalPlayer, check whether packets should be sent about
their new dynamic stats and position their new dynamic stats and position
If the victim was a LocalActor who died, record their attacker as the deathReason
*/ */
mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker); mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker);
@ -978,6 +980,13 @@ namespace MWClass
mwmp::Main::get().getLocalPlayer()->deathReason = attacker.getClass().getName(attacker); mwmp::Main::get().getLocalPlayer()->deathReason = attacker.getClass().getName(attacker);
} }
} }
else if (mwmp::Main::get().getCellController()->isLocalActor(ptr))
{
if (getCreatureStats(ptr).isDead())
{
mwmp::Main::get().getCellController()->getLocalActor(ptr)->deathReason = attacker.getClass().getName(attacker);
}
}
/* /*
End of tes3mp addition End of tes3mp addition
*/ */

View file

@ -32,6 +32,7 @@ void ActorList::reset()
animPlayActors.clear(); animPlayActors.clear();
speechActors.clear(); speechActors.clear();
statsDynamicActors.clear(); statsDynamicActors.clear();
deathActors.clear();
equipmentActors.clear(); equipmentActors.clear();
attackActors.clear(); attackActors.clear();
cellChangeActors.clear(); cellChangeActors.clear();
@ -73,6 +74,11 @@ void ActorList::addStatsDynamicActor(LocalActor localActor)
statsDynamicActors.push_back(localActor); statsDynamicActors.push_back(localActor);
} }
void ActorList::addDeathActor(LocalActor localActor)
{
deathActors.push_back(localActor);
}
void ActorList::addEquipmentActor(LocalActor localActor) void ActorList::addEquipmentActor(LocalActor localActor)
{ {
equipmentActors.push_back(localActor); equipmentActors.push_back(localActor);
@ -138,6 +144,16 @@ void ActorList::sendStatsDynamicActors()
} }
} }
void ActorList::sendDeathActors()
{
if (deathActors.size() > 0)
{
baseActors = deathActors;
Main::get().getNetworking()->getActorPacket(ID_ACTOR_DEATH)->setActorList(this);
Main::get().getNetworking()->getActorPacket(ID_ACTOR_DEATH)->Send();
}
}
void ActorList::sendEquipmentActors() void ActorList::sendEquipmentActors()
{ {
if (equipmentActors.size() > 0) if (equipmentActors.size() > 0)

View file

@ -26,6 +26,7 @@ namespace mwmp
void addAnimPlayActor(LocalActor localActor); void addAnimPlayActor(LocalActor localActor);
void addSpeechActor(LocalActor localActor); void addSpeechActor(LocalActor localActor);
void addStatsDynamicActor(LocalActor localActor); void addStatsDynamicActor(LocalActor localActor);
void addDeathActor(LocalActor localActor);
void addEquipmentActor(LocalActor localActor); void addEquipmentActor(LocalActor localActor);
void addAttackActor(LocalActor localActor); void addAttackActor(LocalActor localActor);
void addCellChangeActor(LocalActor localActor); void addCellChangeActor(LocalActor localActor);
@ -35,6 +36,7 @@ namespace mwmp
void sendAnimPlayActors(); void sendAnimPlayActors();
void sendSpeechActors(); void sendSpeechActors();
void sendStatsDynamicActors(); void sendStatsDynamicActors();
void sendDeathActors();
void sendEquipmentActors(); void sendEquipmentActors();
void sendAttackActors(); void sendAttackActors();
void sendCellChangeActors(); void sendCellChangeActors();
@ -49,6 +51,7 @@ namespace mwmp
std::vector<BaseActor> animPlayActors; std::vector<BaseActor> animPlayActors;
std::vector<BaseActor> speechActors; std::vector<BaseActor> speechActors;
std::vector<BaseActor> statsDynamicActors; std::vector<BaseActor> statsDynamicActors;
std::vector<BaseActor> deathActors;
std::vector<BaseActor> equipmentActors; std::vector<BaseActor> equipmentActors;
std::vector<BaseActor> attackActors; std::vector<BaseActor> attackActors;
std::vector<BaseActor> cellChangeActors; std::vector<BaseActor> cellChangeActors;

View file

@ -93,6 +93,7 @@ void Cell::updateLocal(bool forceUpdate)
actorList->sendAnimFlagsActors(); actorList->sendAnimFlagsActors();
actorList->sendAnimPlayActors(); actorList->sendAnimPlayActors();
actorList->sendSpeechActors(); actorList->sendSpeechActors();
actorList->sendDeathActors();
actorList->sendStatsDynamicActors(); actorList->sendStatsDynamicActors();
actorList->sendEquipmentActors(); actorList->sendEquipmentActors();
actorList->sendAttackActors(); actorList->sendAttackActors();
@ -370,6 +371,11 @@ void Cell::initializeLocalActor(const MWWorld::Ptr& ptr)
actor->cell = *store->getCell(); actor->cell = *store->getCell();
actor->setPtr(ptr); actor->setPtr(ptr);
// Note that this actor was already dead when we were given control over it,
// to avoid sending an ActorDeath packet
if (ptr.getClass().getCreatureStats(ptr).isDead())
actor->wasDead = true;
std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr); std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr);
localActors[mapIndex] = actor; localActors[mapIndex] = actor;

View file

@ -30,6 +30,7 @@ LocalActor::LocalActor()
wasForceJumping = false; wasForceJumping = false;
wasForceMoveJumping = false; wasForceMoveJumping = false;
wasFlying = false; wasFlying = false;
wasDead = false;
attack.type = Attack::MELEE; attack.type = Attack::MELEE;
attack.shouldSend = false; attack.shouldSend = false;
@ -179,6 +180,22 @@ void LocalActor::updateStatsDynamic(bool forceUpdate)
creatureStats.mDead = ptrCreatureStats->isDead(); creatureStats.mDead = ptrCreatureStats->isDead();
mwmp::Main::get().getNetworking()->getActorList()->addStatsDynamicActor(*this); mwmp::Main::get().getNetworking()->getActorList()->addStatsDynamicActor(*this);
if (creatureStats.mDead && !wasDead)
{
if (deathReason.empty())
deathReason = "suicide";
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_DEATH about %s-%i-%i to server",
refId.c_str(), refNumIndex, mpNum);
LOG_APPEND(Log::LOG_INFO, "- deathReason was %s", deathReason.c_str());
mwmp::Main::get().getNetworking()->getActorList()->addDeathActor(*this);
deathReason = "";
}
wasDead = creatureStats.mDead;
} }
} }

View file

@ -28,6 +28,8 @@ namespace mwmp
MWWorld::Ptr getPtr(); MWWorld::Ptr getPtr();
void setPtr(const MWWorld::Ptr& newPtr); void setPtr(const MWWorld::Ptr& newPtr);
bool wasDead;
private: private:
MWWorld::Ptr ptr; MWWorld::Ptr ptr;

View file

@ -39,6 +39,8 @@ namespace mwmp
Animation animation; Animation animation;
Attack attack; Attack attack;
std::string deathReason;
bool hasAiTarget; bool hasAiTarget;
Target aiTarget; Target aiTarget;
unsigned int aiAction; unsigned int aiAction;

View file

@ -11,5 +11,5 @@ PacketActorDeath::PacketActorDeath(RakNet::RakPeerInterface *peer) : ActorPacket
void PacketActorDeath::Actor(BaseActor &actor, bool send) void PacketActorDeath::Actor(BaseActor &actor, bool send)
{ {
// Placeholder to be filled in later RW(actor.deathReason, send);
} }