[Client] Correctly implement movement animation sync for NPCs

0.6.1
David Cernat 8 years ago
parent 5b43e62c50
commit d3f3fb5d05

@ -27,8 +27,19 @@
#include <components/sceneutil/positionattitudetransform.hpp>
/*
Start of tes3mp addition
Include additional headers for multiplayer purposes
*/
#include <components/openmw-mp/Log.hpp>
#include "../mwmp/Main.hpp"
#include "../mwmp/CellController.hpp"
#include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/LocalActor.hpp"
/*
End of tes3mp addition
*/
#include "../mwrender/animation.hpp"
@ -1577,6 +1588,25 @@ void CharacterController::updateAnimQueue()
void CharacterController::update(float duration)
{
/*
Start of tes3mp addition
Keep track of LocalActor and DedicatedActor objects so as to reuse them
*/
bool hasLocalActorRecord = mwmp::Main::get().getCellController()->hasLocalActorRecord(mPtr);
bool hasDedicatedActorRecord = mwmp::Main::get().getCellController()->hasDedicatedActorRecord(mPtr);
mwmp::LocalActor *localActor;
mwmp::DedicatedActor *dedicatedActor;
if (hasLocalActorRecord)
localActor = mwmp::Main::get().getCellController()->getLocalActor(mPtr);
if (hasDedicatedActorRecord)
dedicatedActor = mwmp::Main::get().getCellController()->getDedicatedActor(mPtr);
/*
End of tes3mp addition
*/
MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Class &cls = mPtr.getClass();
osg::Vec3f movement(0.f, 0.f, 0.f);
@ -1862,7 +1892,36 @@ void CharacterController::update(float duration)
else
forcestateupdate = updateCreatureState() || forcestateupdate;
/*
Start of tes3mp addition
Save or load animation states for this actor, depending on whether it's a local
or dedicated one
*/
if (hasLocalActorRecord)
{
localActor->hasAnimStates = true;
localActor->animStates.idlestate = idlestate;
localActor->animStates.movestate = movestate;
localActor->animStates.jumpstate = jumpstate;
localActor->animStates.forcestateupdate = forcestateupdate;
}
else if (hasDedicatedActorRecord)
{
if (dedicatedActor->hasAnimStates)
{
idlestate = CharacterState(dedicatedActor->animStates.idlestate);
movestate = CharacterState(dedicatedActor->animStates.movestate);
jumpstate = JumpingState(dedicatedActor->animStates.jumpstate);
forcestateupdate = dedicatedActor->animStates.forcestateupdate;
}
}
/*
End of tes3mp addition
*/
refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate);
updateIdleStormState(inwater);
}
@ -1952,6 +2011,27 @@ void CharacterController::update(float duration)
if (mFloatToSurface && cls.isActor() && cls.getCreatureStats(mPtr).isDead() && cls.canSwim(mPtr))
moved.z() = 1.0;
/*
Start of tes3mp addition
Save or load movement velocity based on whether this is a local or dedicated actor
*/
if (hasLocalActorRecord)
{
localActor->hasMovement = true;
localActor->movement.x = moved.x();
localActor->movement.y = moved.y();
localActor->movement.z = moved.z();
}
else if (hasDedicatedActorRecord)
{
if (dedicatedActor->hasMovement)
moved = osg::Vec3f(dedicatedActor->movement.x, dedicatedActor->movement.y, dedicatedActor->movement.z);
}
/*
End of tes3mp addition
*/
// Update movement
if(mMovementAnimationControlled && mPtr.getClass().isActor())
world->queueMovement(mPtr, moved);
@ -2079,6 +2159,25 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
mAnimation->play(groupname, Priority_Default,
MWRender::Animation::BlendMask_All, false, 1.0f,
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback);
/*
Start of tes3mp addition
If we are the cell authority over this actor, we need to record this new
animation for it
*/
if (mwmp::Main::get().getCellController()->hasLocalActorRecord(mPtr))
{
mwmp::LocalActor *actor = mwmp::Main::get().getCellController()->getLocalActor(mPtr);
actor->hasAnimation = true;
actor->animation.groupname = groupname;
actor->animation.mode = mode;
actor->animation.count = count;
actor->animation.persist = persist;
}
/*
End of tes3mp addition
*/
}
else if(mode == 0)
{

@ -57,7 +57,28 @@ void Cell::updateLocal()
worldObject.movementFlags = actor->movementFlags;
worldObject.headPitch = actor->headPitch;
worldObject.headYaw = actor->headYaw;
worldObject.hasAnimation = actor->hasAnimation;
worldObject.hasAnimStates = actor->hasAnimStates;
worldObject.hasMovement = actor->hasMovement;
if (actor->hasAnimation)
{
worldObject.animation = actor->animation;
}
if (actor->hasAnimStates)
{
worldObject.animStates = actor->animStates;
}
if (actor->hasMovement)
{
worldObject.movement = actor->movement;
}
actor->hasAnimation = false;
actor->hasAnimStates = false;
actor->hasMovement = false;
worldEvent->addObject(worldObject);
++it;
@ -161,6 +182,24 @@ void Cell::readCellFrame(WorldEvent& worldEvent)
actor->direction = worldObject.direction;
actor->drawState = worldObject.drawState;
actor->movementFlags = worldObject.movementFlags;
actor->hasAnimation = worldObject.hasAnimation;
actor->hasAnimStates = worldObject.hasAnimStates;
actor->hasMovement = worldObject.hasMovement;
if (actor->hasAnimation)
{
actor->animation = worldObject.animation;
}
if (actor->hasAnimStates)
{
actor->animStates = worldObject.animStates;
}
if (actor->hasMovement)
{
actor->movement = worldObject.movement;
}
}
}
}

@ -1,3 +1,5 @@
#include <components/openmw-mp/Log.hpp>
#include "../mwbase/environment.hpp"
#include "../mwmechanics/mechanicsmanagerimp.hpp"
#include "../mwmechanics/movement.hpp"
@ -25,7 +27,6 @@ void DedicatedActor::update(float dt)
{
move(dt);
setDrawState();
setMovementFlags();
setAnimation();
}
@ -35,11 +36,6 @@ void DedicatedActor::move(float dt)
world->moveObject(ptr, position.pos[0], position.pos[1], position.pos[2]);
MWMechanics::Movement& move = ptr.getClass().getMovementSettings(ptr);
move.mPosition[0] = direction.pos[0];
move.mPosition[1] = direction.pos[1];
move.mPosition[2] = direction.pos[2];
world->rotateObject(ptr, position.rot[0], position.rot[1], position.rot[2]);
}
@ -55,30 +51,12 @@ void DedicatedActor::setDrawState()
ptr.getClass().getNpcStats(ptr).setDrawState(DrawState_Spell);
}
void DedicatedActor::setMovementFlags()
{
using namespace MWMechanics;
MWMechanics::NpcStats *ptrNpcStats = &ptr.getClass().getNpcStats(ptr);
ptrNpcStats->setMovementFlag(CreatureStats::Flag_Run, (movementFlags & CreatureStats::Flag_Run) != 0);
ptrNpcStats->setMovementFlag(CreatureStats::Flag_Sneak, (movementFlags & CreatureStats::Flag_Sneak) != 0);
ptrNpcStats->setMovementFlag(CreatureStats::Flag_ForceJump, (movementFlags & CreatureStats::Flag_ForceJump) != 0);
ptrNpcStats->setMovementFlag(CreatureStats::Flag_ForceMoveJump, (movementFlags & CreatureStats::Flag_ForceMoveJump) != 0);
}
void DedicatedActor::setAnimation()
{
MWBase::World *world = MWBase::Environment::get().getWorld();
if (headPitch != -1 && headYaw != -1)
if (hasAnimation)
{
MWRender::Animation *animation = world->getAnimation(ptr);
if (animation)
{
animation->setHeadPitch(headPitch);
animation->setHeadYaw(headYaw);
}
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(ptr,
animation.groupname, animation.mode, animation.count, animation.persist);
}
}

@ -17,7 +17,6 @@ namespace mwmp
void update(float dt);
void move(float dt);
void setDrawState();
void setMovementFlags();
void setAnimation();
MWWorld::Ptr getPtr();

@ -1,3 +1,5 @@
#include <components/openmw-mp/Log.hpp>
#include "../mwbase/environment.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/npcstats.hpp"
@ -14,6 +16,9 @@ LocalActor::LocalActor()
{
headPitch = -1;
headYaw = -1;
hasAnimation = false;
hasAnimStates = false;
hasMovement = false;
}
LocalActor::~LocalActor()
@ -25,18 +30,11 @@ void LocalActor::update()
{
updatePosition();
updateDrawState();
updateMovementFlags();
updateAnimation();
}
void LocalActor::updatePosition()
{
position = ptr.getRefData().getPosition();
MWMechanics::Movement &move = ptr.getClass().getMovementSettings(ptr);
direction.pos[0] = move.mPosition[0];
direction.pos[1] = move.mPosition[1];
direction.pos[2] = move.mPosition[2];
}
void LocalActor::updateDrawState()
@ -44,41 +42,6 @@ void LocalActor::updateDrawState()
drawState = ptr.getClass().getNpcStats(ptr).getDrawState();
}
void LocalActor::updateMovementFlags()
{
using namespace MWMechanics;
MWBase::World *world = MWBase::Environment::get().getWorld();
MWMechanics::NpcStats ptrNpcStats = ptr.getClass().getNpcStats(ptr);
bool run = ptrNpcStats.getMovementFlag(CreatureStats::Flag_Run);
bool sneak = ptrNpcStats.getMovementFlag(CreatureStats::Flag_Sneak);
bool forceJump = ptrNpcStats.getMovementFlag(CreatureStats::Flag_ForceJump);
bool forceMoveJump = ptrNpcStats.getMovementFlag(CreatureStats::Flag_ForceMoveJump);
#define __SETFLAG(flag, value) (value) ? (movementFlags | flag) : (movementFlags & ~flag)
movementFlags = __SETFLAG(CreatureStats::Flag_Sneak, sneak);
movementFlags = __SETFLAG(CreatureStats::Flag_Run, run);
movementFlags = __SETFLAG(CreatureStats::Flag_ForceJump, forceJump);
movementFlags = __SETFLAG(CreatureStats::Flag_ForceMoveJump, forceMoveJump);
#undef __SETFLAG
}
void LocalActor::updateAnimation()
{
MWBase::World *world = MWBase::Environment::get().getWorld();
MWRender::Animation *animation = world->getAnimation(ptr);
if (animation)
{
headPitch = animation->getHeadPitch();
headYaw = animation->getHeadYaw();
}
}
MWWorld::Ptr LocalActor::getPtr()
{
return ptr;

@ -17,8 +17,6 @@ namespace mwmp
void updatePosition();
void updateDrawState();
void updateMovementFlags();
void updateAnimation();
MWWorld::Ptr getPtr();
void setPtr(const MWWorld::Ptr& newPtr);

@ -2,6 +2,7 @@
#define OPENMW_BASEACTOR_HPP
#include <components/esm/loadcell.hpp>
#include <components/openmw-mp/Base/BaseStructs.hpp>
namespace mwmp
{
@ -25,6 +26,15 @@ namespace mwmp
float headPitch;
float headYaw;
Animation animation;
bool hasAnimation;
AnimStates animStates;
bool hasAnimStates;
Movement movement;
bool hasMovement;
};
}

@ -3,6 +3,7 @@
#include <components/esm/loadcell.hpp>
#include <components/esm/cellref.hpp>
#include <components/openmw-mp/Base/BaseStructs.hpp>
#include <RakNetTypes.h>
namespace mwmp
@ -62,6 +63,15 @@ namespace mwmp
std::string varName;
ContainerChanges containerChanges;
Animation animation;
bool hasAnimation;
AnimStates animStates;
bool hasAnimStates;
Movement movement;
bool hasMovement;
};
struct ObjectChanges

@ -0,0 +1,30 @@
#ifndef OPENMW_BASESTRUCTS_HPP
#define OPENMW_BASESTRUCTS_HPP
namespace mwmp
{
struct Animation
{
std::string groupname;
int mode;
int count;
bool persist;
};
struct AnimStates
{
int idlestate;
int movestate;
int jumpstate;
bool forcestateupdate;
};
struct Movement
{
float x;
float y;
float z;
};
}
#endif //OPENMW_BASESTRUCTS_HPP

@ -1,4 +1,5 @@
#include <components/openmw-mp/NetworkMessages.hpp>
#include <components/openmw-mp/Log.hpp>
#include "PacketActorFrame.hpp"
using namespace mwmp;
@ -44,6 +45,33 @@ void PacketActorFrame::Packet(RakNet::BitStream *bs, bool send)
RW(worldObject.headPitch, send);
RW(worldObject.headYaw, send);
RW(worldObject.hasAnimation, send);
RW(worldObject.hasAnimStates, send);
RW(worldObject.hasMovement, send);
if (worldObject.hasAnimation)
{
RW(worldObject.animation.groupname, send);
RW(worldObject.animation.mode, send);
RW(worldObject.animation.count, send);
RW(worldObject.animation.persist, send);
}
if (worldObject.hasAnimStates)
{
RW(worldObject.animStates.idlestate, send);
RW(worldObject.animStates.movestate, send);
RW(worldObject.animStates.jumpstate, send);
RW(worldObject.animStates.forcestateupdate, send);
}
if (worldObject.hasMovement)
{
RW(worldObject.movement.x, send);
RW(worldObject.movement.y, send);
RW(worldObject.movement.y, send);
}
if (!send)
{
event->objectChanges.objects.push_back(worldObject);

Loading…
Cancel
Save