Skip to content

Commit

Permalink
Character: added state & situation flag system.
Browse files Browse the repository at this point in the history
This obsoletes the separate "upper/lower" body anim system.

* Character.cpp: no longer determines animations, only sets state & situation flags.
* SimBuffers.h, Network.h: now transferring flags instead of anim+time.
* GfxCharacter.cpp: determine animation from flags and other state info.
  • Loading branch information
ohlidalp committed Sep 23, 2022
1 parent e9eaeec commit ec463eb
Show file tree
Hide file tree
Showing 9 changed files with 363 additions and 355 deletions.
2 changes: 0 additions & 2 deletions source/main/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@

#define ROR_ASSERT(_EXPR) assert(_EXPR)

#define CHARACTER_ANIM_NAME_LEN 10 // Restricted for networking

// Legacy macros
#define TOSTRING(x) Ogre::StringConverter::toString(x)
#define PARSEINT(x) Ogre::StringConverter::parseInt(x)
Expand Down
436 changes: 184 additions & 252 deletions source/main/gameplay/Character.cpp

Large diffs are not rendered by default.

61 changes: 35 additions & 26 deletions source/main/gameplay/Character.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,69 +47,78 @@ class Character

public:

// Action flags
static const BitMask_t ACTION_MOVE_FORWARD = BITMASK(1);
static const BitMask_t ACTION_MOVE_BACKWARD = BITMASK(2);
static const BitMask_t ACTION_TURN_RIGHT = BITMASK(3);
static const BitMask_t ACTION_TURN_LEFT = BITMASK(4);
static const BitMask_t ACTION_SIDESTEP_RIGHT = BITMASK(5);
static const BitMask_t ACTION_SIDESTEP_LEFT = BITMASK(6);
static const BitMask_t ACTION_RUN = BITMASK(7);
static const BitMask_t ACTION_JUMP = BITMASK(8);
static const BitMask_t ACTION_WAVE_HAND = BITMASK(9);
static const BitMask_t ACTION_SLOW_TURN = BITMASK(10);

// Situation flags
static const BitMask_t SITUATION_ON_SOLID_GROUND = BITMASK(1);
static const BitMask_t SITUATION_IN_SHALLOW_WATER = BITMASK(2);
static const BitMask_t SITUATION_IN_DEEP_WATER = BITMASK(3);
static const BitMask_t SITUATION_IN_AIR = BITMASK(4);
static const BitMask_t SITUATION_DRIVING = BITMASK(5);

Character(int source = -1, unsigned int streamid = 0, Ogre::UTFString playerName = "", int color_number = 0, bool is_remote = true);
~Character();

Ogre::UTFString const& GetNetUsername() { return m_net_username; }
// get state
Ogre::Vector3 getPosition();
Ogre::Radian getRotation() const { return m_character_rotation; }
Actor* GetActorCoupling() { return m_actor_coupling; }

Ogre::Vector3 getPosition();
void setPosition(Ogre::Vector3 position);
void setRotation(Ogre::Radian rotation);
void move(Ogre::Vector3 offset);
void update(float dt);
void updateLocal(float dt);
void upateRemote(float dt);
void updateCharacterRotation();
void SetActorCoupling(bool enabled, Actor* actor);

// network
void receiveStreamData(unsigned int& type, int& source, unsigned int& streamid, char* buffer);
void SendStreamData();
int getSourceID() const { return m_source_id; }
bool isRemote() const { return m_is_remote; }
int GetColorNum() const { return m_color_number; }
void setColour(int color) { this->m_color_number = color; }

// anims
std::string const & GetUpperAnimName() const { return m_anim_upper_name; }
float GetUpperAnimTime() const { return m_anim_upper_time; }
std::string const & GetLowerAnimName() const { return m_anim_lower_name; }
float GetLowerAnimTime() const { return m_anim_lower_time; }
Ogre::UTFString const& GetNetUsername() { return m_net_username; }

private:

void ReportError(const char* detail);
void SendStreamData();
void SendStreamSetup();
void SetUpperAnimState(std::string mode, float time = 0);
void SetLowerAnimState(std::string mode, float time = 0);

Actor* m_actor_coupling; //!< The vehicle or machine which the character occupies
// attributes
std::string m_instance_name;

// transforms
Ogre::Vector3 m_character_position;
Ogre::Vector3 m_prev_position;
Ogre::Radian m_character_rotation;
float m_character_h_speed;
float m_character_v_speed;
Ogre::Vector3 m_character_position;
Ogre::Vector3 m_prev_position;
bool m_can_jump;
std::string m_instance_name;

// visuals
float m_driving_anim_length;
// state
BitMask_t m_action_flags = 0;
BitMask_t m_situation_flags = 0;
Actor* m_actor_coupling; //!< The vehicle or machine which the character occupies

// network
bool m_is_remote;
float m_net_last_anim_time;
int m_color_number;
Ogre::UTFString m_net_username;
Ogre::Timer m_net_timer;
unsigned long m_net_last_update_time;
int m_stream_id;
int m_source_id;

// anims
std::string m_anim_upper_name;
float m_anim_upper_time;
std::string m_anim_lower_name;
float m_anim_lower_time;
};

/// @} // addtogroup Character
Expand Down
10 changes: 7 additions & 3 deletions source/main/gameplay/CharacterFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,16 @@ void CharacterFactory::removeStreamSource(int sourceid)

void CharacterFactory::Update(float dt)
{
m_local_character->update(dt);
m_local_character->updateLocal(dt);

for (auto& c : m_remote_characters)
#ifdef USE_SOCKETW
if ((App::mp_state->getEnum<MpState>() == MpState::CONNECTED) && !m_local_character->isRemote())
{
c->update(dt);
m_local_character->SendStreamData();
}
#endif // USE_SOCKETW


}

void CharacterFactory::UndoRemoteActorCoupling(Actor* actor)
Expand Down
182 changes: 122 additions & 60 deletions source/main/gfx/GfxCharacter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
This source file is part of Rigs of Rods
Copyright 2005-2012 Pierre-Michel Ricordel
Copyright 2007-2012 Thomas Fischer
Copyright 2017-2018 Petr Ohlidal
Copyright 2017-2022 Petr Ohlidal
For more information, see http://www.rigsofrods.org/
Expand Down Expand Up @@ -45,7 +45,6 @@ GfxCharacter::GfxCharacter(Character* character)
, xc_instance_name(character->m_instance_name)
{
Entity* entity = App::GetGfxScene()->GetSceneManager()->createEntity(xc_instance_name + "_mesh", "character.mesh");
character->m_driving_anim_length = entity->getAnimationState("Driving")->getLength();

// fix disappearing mesh
AxisAlignedBox aabb;
Expand Down Expand Up @@ -83,13 +82,12 @@ void RoR::GfxCharacter::BufferSimulationData()
xc_simbuf.simbuf_net_username = xc_character->GetNetUsername();
xc_simbuf.simbuf_is_remote = xc_character->isRemote();
xc_simbuf.simbuf_actor_coupling = xc_character->GetActorCoupling();
xc_simbuf.simbuf_anim_upper_name = xc_character->GetUpperAnimName();
xc_simbuf.simbuf_anim_upper_time = xc_character->GetUpperAnimTime();
xc_simbuf.simbuf_anim_lower_name = xc_character->GetLowerAnimName();
xc_simbuf.simbuf_anim_lower_time = xc_character->GetLowerAnimTime();
xc_simbuf.simbuf_action_flags = xc_character->m_action_flags;
xc_simbuf.simbuf_situation_flags = xc_character->m_situation_flags;
xc_simbuf.simbuf_character_h_speed = xc_character->m_character_h_speed;
}

void RoR::GfxCharacter::UpdateCharacterInScene()
void RoR::GfxCharacter::UpdateCharacterInScene(float dt)
{
// Actor coupling
if (xc_simbuf.simbuf_actor_coupling != xc_simbuf_prev.simbuf_actor_coupling)
Expand Down Expand Up @@ -149,61 +147,13 @@ void RoR::GfxCharacter::UpdateCharacterInScene()

if (!App::GetGuiManager()->CharacterPoseUtil.IsManualPoseActive())
{
// Reset all anims


LOG(fmt::format("file:{}, line:{}, func:{}, resetting all animations before update", __FILE__, __LINE__, __FUNCTION__));
AnimationStateSet* stateset = entity->getAllAnimationStates();
for (auto& state_pair : stateset->getAnimationStates())
try
{
AnimationState* as = state_pair.second;
as->setEnabled(false);
as->setWeight(0);
LOG(fmt::format("\tanim '{}' was reset", as->getAnimationName()));
this->UpdateAnimations(dt);
}

// upper body anim
if (xc_simbuf.simbuf_anim_upper_name != "")
{
LOG(fmt::format("file:{}, line:{}, func:{}, enabling upper body anim (name '{}', time {})",
__FILE__, __LINE__, __FUNCTION__,
xc_simbuf.simbuf_anim_upper_name, xc_simbuf.simbuf_anim_upper_time));
try
{
this->EnableAnim(entity->getAnimationState(xc_simbuf.simbuf_anim_upper_name), xc_simbuf.simbuf_anim_upper_time);
}
catch (Ogre::Exception& eeh) {
App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR,
fmt::format("error updating upper body anim (name '{}', time {}), message:{}",
xc_simbuf.simbuf_anim_upper_name, xc_simbuf.simbuf_anim_upper_time, eeh.getFullDescription()));
}
}
else
{
LOG(fmt::format("file:{}, line:{}, func:{}, no upper body anim requested",
__FILE__, __LINE__, __FUNCTION__));
}

// lower body anim
if (xc_simbuf.simbuf_anim_lower_name != "")
{
LOG(fmt::format("file:{}, line:{}, func:{}, enabling lower body anim (name '{}', time {})",
__FILE__, __LINE__, __FUNCTION__,
xc_simbuf.simbuf_anim_lower_name, xc_simbuf.simbuf_anim_lower_time));
try
{
this->EnableAnim(entity->getAnimationState(xc_simbuf.simbuf_anim_lower_name), xc_simbuf.simbuf_anim_lower_time);
}
catch (Ogre::Exception& eeh) {
App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR,
fmt::format("error updating lower body anim (name '{}', time {}), message:{}",
xc_simbuf.simbuf_anim_lower_name, xc_simbuf.simbuf_anim_lower_time, eeh.getFullDescription()));
}
}
else
{
LOG(fmt::format("file:{}, line:{}, func:{}, no lower body anim requested",
__FILE__, __LINE__, __FUNCTION__));
catch (Ogre::Exception& eeh) {
App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_ERROR,
fmt::format("error updating animations, message:{}", eeh.getFullDescription()));
}
}

Expand Down Expand Up @@ -236,6 +186,118 @@ void RoR::GfxCharacter::UpdateCharacterInScene()
#endif // USE_SOCKETW
}

void GfxCharacter::UpdateAnimations(float dt)
{
// Reset all anims
Ogre::Entity* entity = static_cast<Ogre::Entity*>(xc_scenenode->getAttachedObject(0));
AnimationStateSet* stateset = entity->getAllAnimationStates();
for (auto& state_pair : stateset->getAnimationStates())
{
AnimationState* as = state_pair.second;
as->setEnabled(false);
as->setWeight(0);
}

if (BITMASK_IS_1(xc_simbuf.simbuf_situation_flags, Character::SITUATION_DRIVING))
{
AnimationState* as = entity->getAnimationState("Driving");
float angle = xc_simbuf.simbuf_actor_coupling->ar_hydro_dir_wheel_display * -1.0f; // not getSteeringAngle(), but this, as its smoothed
float anim_time_pos = ((angle + 1.0f) * 0.5f) * as->getLength();
// prevent animation flickering on the borders:
if (anim_time_pos < 0.01f)
{
anim_time_pos = 0.01f;
}
if (anim_time_pos > as->getLength() - 0.01f)
{
anim_time_pos = as->getLength() - 0.01f;
}

as->setTimePosition(anim_time_pos);
as->setWeight(1.f);
as->setEnabled(true);
}
else if (BITMASK_IS_1(xc_simbuf.simbuf_situation_flags, Character::SITUATION_IN_DEEP_WATER))
{
if (BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_MOVE_FORWARD) ||
BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_MOVE_BACKWARD))
{
AnimationState* as = entity->getAnimationState("Swim_loop");
as->setTimePosition(as->getTimePosition() + (dt * xc_simbuf.simbuf_character_h_speed));
as->setWeight(1.f);
as->setEnabled(true);
}
else
{
AnimationState* as = entity->getAnimationState("Spot_swim");
as->setTimePosition(as->getTimePosition() + dt);
as->setWeight(1.f);
as->setEnabled(true);
}
}
else // solid ground or jumping
{
if (BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_MOVE_FORWARD) ||
BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_MOVE_BACKWARD))
{
AnimationState* as = nullptr;
if (BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_RUN))
as = entity->getAnimationState("Run");
else
as = entity->getAnimationState("Walk");

float time = dt * xc_simbuf.simbuf_character_h_speed;
as->setTimePosition(as->getTimePosition() + time);
as->setWeight(1.f);
as->setEnabled(true);
}
else
{
if (BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_TURN_LEFT))
{
AnimationState* as = entity->getAnimationState("Turn");
float time = dt;
if (BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_SLOW_TURN))
time *= 1.2f;
as->setTimePosition(as->getTimePosition() + time);
as->setWeight(1.f);
as->setEnabled(true);
}
else if (BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_TURN_RIGHT))
{
AnimationState* as = entity->getAnimationState("Turn");
float time = -dt;
if (BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_SLOW_TURN))
time *= 1.2f;
as->setTimePosition(as->getTimePosition() + time);
as->setWeight(1.f);
as->setEnabled(true);
}
else if (BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_SIDESTEP_RIGHT))
{
AnimationState* as = entity->getAnimationState("Side_step");
as->setTimePosition(as->getTimePosition() + dt);
as->setWeight(1.f);
as->setEnabled(true);
}
else if (BITMASK_IS_1(xc_simbuf.simbuf_action_flags, Character::ACTION_SIDESTEP_LEFT))
{
AnimationState* as = entity->getAnimationState("Side_step");
as->setTimePosition(as->getTimePosition() + -dt);
as->setWeight(1.f);
as->setEnabled(true);
}
else
{
AnimationState* as = entity->getAnimationState("Idle_sway");
as->setTimePosition(as->getTimePosition() + dt);
as->setWeight(1.f);
as->setEnabled(true);
}
}
}
}

void GfxCharacter::DisableAnim(Ogre::AnimationState* as)
{
as->setEnabled(false);
Expand Down
5 changes: 3 additions & 2 deletions source/main/gfx/GfxCharacter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
This source file is part of Rigs of Rods
Copyright 2005-2012 Pierre-Michel Ricordel
Copyright 2007-2012 Thomas Fischer
Copyright 2017-2018 Petr Ohlidal
Copyright 2017-2022 Petr Ohlidal
For more information, see http://www.rigsofrods.org/
Expand Down Expand Up @@ -40,9 +40,10 @@ struct GfxCharacter
~GfxCharacter();

void BufferSimulationData();
void UpdateCharacterInScene();
void UpdateCharacterInScene(float dt);
void DisableAnim(Ogre::AnimationState* anim_state);
void EnableAnim(Ogre::AnimationState* anim_state, float time);
void UpdateAnimations(float dt);

Ogre::SceneNode* xc_scenenode;
CharacterSB xc_simbuf;
Expand Down
2 changes: 1 addition & 1 deletion source/main/gfx/GfxScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ void GfxScene::UpdateScene(float dt_sec)
// Player avatars
for (GfxCharacter* a: m_all_gfx_characters)
{
a->UpdateCharacterInScene();
a->UpdateCharacterInScene(dt_sec);
}

// Actors - update misc visuals
Expand Down
Loading

0 comments on commit ec463eb

Please sign in to comment.