From 140c1c9c1234e33778efcb21d9410aef974f2b3f Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 29 Nov 2019 10:39:57 +0200 Subject: [PATCH] [General] Use hard synchronization for melee attack animations Previously, each client chose its own attack animations for DedicatedPlayers and DedicatedActors based on the direction they were walking in, which however led to desyncs for players with "Always Use Best Attack" enabled and for creatures which pick their attack animations randomly. --- apps/openmw/mwmechanics/aicombat.cpp | 7 ++- apps/openmw/mwmechanics/character.cpp | 57 +++++++++++++++---- apps/openmw/mwmechanics/character.hpp | 10 ++++ apps/openmw/mwmp/MechanicsHelper.cpp | 5 ++ components/openmw-mp/Base/BaseStructs.hpp | 4 +- .../Packets/Actor/PacketActorAttack.cpp | 6 +- .../Packets/Player/PacketPlayerAttack.cpp | 6 +- 7 files changed, 77 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a7583d294..1d6c3e487 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -609,6 +609,9 @@ namespace MWMechanics mAttack = true; // attack starts just now characterController.setAttackingOrSpell(true); + if (!distantCombat) + characterController.setAIAttackType(chooseBestAttack(weapon)); + /* Start of tes3mp addition @@ -620,6 +623,7 @@ namespace MWMechanics { MechanicsHelper::resetAttack(localAttack); localAttack->type = distantCombat ? mwmp::Attack::RANGED : mwmp::Attack::MELEE; + localAttack->attackAnimation = characterController.getAttackType(); localAttack->pressed = true; localAttack->shouldSend = true; } @@ -627,9 +631,6 @@ namespace MWMechanics End of tes3mp addition */ - if (!distantCombat) - characterController.setAIAttackType(chooseBestAttack(weapon)); - mStrength = Misc::Rng::rollClosedProbability(); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 48e6a3a6c..96f565a58 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1569,7 +1569,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) /* Start of tes3mp addition - If this mPtr belongs to a LocalPlayer or LocalActor, get their Attack and prepare + If this mPtr belongs to a LocalPlayer or LocalActor, get their Cast and prepare it for sending */ mwmp::Cast *localCast = MechanicsHelper::getLocalCast(mPtr); @@ -1694,17 +1694,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) } else { - /* - Start of tes3mp change (major) - - We need DedicatedPlayers and DedicatedActors to not have their attacks - cancelled here, so additional conditions have been added for them - */ - if(mPtr == getPlayer() || mwmp::PlayerList::isDedicatedPlayer(mPtr) || - mwmp::Main::get().getCellController()->isDedicatedActor(mPtr)) - /* - End of tes3mp change (major) - */ + if(mPtr == getPlayer()) { if (Settings::Manager::getBool("best attack", "Game")) { @@ -1723,7 +1713,37 @@ bool CharacterController::updateWeaponState(CharacterState& idle) { setAttackTypeBasedOnMovement(); } + + /* + Start of tes3mp addition + + Record the attack animation chosen so we can send it in the next PlayerAttack packet + */ + mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(mPtr); + + if (localAttack) + localAttack->attackAnimation = mAttackType; + /* + End of tes3mp addition + */ } + /* + Start of tes3mp addition + + If this is a DedicatedPlayer or DedicatedActor, use the attack animation received + in the latest Attack packet about them + */ + else + { + mwmp::Attack *dedicatedAttack = MechanicsHelper::getDedicatedAttack(mPtr); + + if (dedicatedAttack) + mAttackType = dedicatedAttack->attackAnimation; + } + /* + End of tes3mp addition + */ + // else if (mPtr != getPlayer()) use mAttackType set by AiCombat startKey = mAttackType+" start"; stopKey = mAttackType+" min attack"; @@ -2935,6 +2955,19 @@ float CharacterController::getAttackStrength() const return mAttackStrength; } +/* + Start of tes3mp addition + + Make it possible to get the current attack type from elsewhere in the code +*/ +std::string CharacterController::getAttackType() const +{ + return mAttackType; +} +/* + End of tes3mp addition +*/ + void CharacterController::setActive(int active) { mAnimation->setActive(active); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 614beca1c..29d6023d3 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -295,6 +295,16 @@ public: float getAttackStrength() const; + /* + Start of tes3mp addition + + Make it possible to get the current attack type from elsewhere in the code + */ + std::string getAttackType() const; + /* + End of tes3mp addition + */ + /// @see Animation::setActive void setActive(int active); diff --git a/apps/openmw/mwmp/MechanicsHelper.cpp b/apps/openmw/mwmp/MechanicsHelper.cpp index 40ee080e9..c0080938d 100644 --- a/apps/openmw/mwmp/MechanicsHelper.cpp +++ b/apps/openmw/mwmp/MechanicsHelper.cpp @@ -282,6 +282,11 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) if (attack.success) LOG_APPEND(TimedLog::LOG_VERBOSE, "- damage: %f", attack.damage); } + else + { + if (attack.type == attack.MELEE) + LOG_APPEND(TimedLog::LOG_VERBOSE, "- animation: %s", attack.attackAnimation.c_str()); + } MWMechanics::CreatureStats &attackerStats = attacker.getClass().getCreatureStats(attacker); MWWorld::Ptr victim; diff --git a/components/openmw-mp/Base/BaseStructs.hpp b/components/openmw-mp/Base/BaseStructs.hpp index ca14f9054..823d8b212 100644 --- a/components/openmw-mp/Base/BaseStructs.hpp +++ b/components/openmw-mp/Base/BaseStructs.hpp @@ -65,13 +65,15 @@ namespace mwmp Target target; - char type; // 0 - melee, 1 - ranged enum TYPE { MELEE = 0, RANGED }; + char type; + std::string attackAnimation; + std::string rangedWeaponId; std::string rangedAmmoId; diff --git a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp index ba5efb89e..ce318fc77 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp @@ -31,7 +31,11 @@ void PacketActorAttack::Actor(BaseActor &actor, bool send) RW(actor.attack.isHit, send); - if (actor.attack.type == mwmp::Attack::RANGED) + if (actor.attack.type == mwmp::Attack::MELEE) + { + RW(actor.attack.attackAnimation, send); + } + else if (actor.attack.type == mwmp::Attack::RANGED) { RW(actor.attack.attackStrength, send); RW(actor.attack.rangedWeaponId, send); diff --git a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp index 3060e3307..092f10170 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp @@ -32,7 +32,11 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send) RW(player->attack.isHit, send); - if (player->attack.type == mwmp::Attack::RANGED) + if (player->attack.type == mwmp::Attack::MELEE) + { + RW(player->attack.attackAnimation, send); + } + else if (player->attack.type == mwmp::Attack::RANGED) { RW(player->attack.attackStrength, send); RW(player->attack.rangedWeaponId, send);