mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-03 07:19:41 +00:00
[Client] Correctly implement movement animation sync for NPCs
This commit is contained in:
parent
5b43e62c50
commit
d3f3fb5d05
10 changed files with 226 additions and 72 deletions
|
@ -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
|
||||
|
|
30
components/openmw-mp/Base/BaseStructs.hpp
Normal file
30
components/openmw-mp/Base/BaseStructs.hpp
Normal file
|
@ -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…
Reference in a new issue