From fcd31bf4a636f3bd4eb1179c40a335fb4348171e Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 11 Sep 2018 11:56:45 +0300 Subject: [PATCH] [General] Fix problems with the synchronization of ranged attacks Projectile hits now send Attack packets with RANGED attacks, and their success or failure is now synchronized. Strike enchantments no longer require a valid victim to be synchronized. Additional debug messages have been added for attacks. --- apps/openmw/mwmechanics/combat.cpp | 40 ++++++++--- apps/openmw/mwmp/MechanicsHelper.cpp | 70 +++++++++++-------- components/openmw-mp/Base/BaseStructs.hpp | 1 + .../Packets/Actor/PacketActorAttack.cpp | 28 ++++---- .../Packets/Player/PacketPlayerAttack.cpp | 28 ++++---- 5 files changed, 97 insertions(+), 70 deletions(-) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index d6516dea9..52404d2ff 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -217,10 +217,18 @@ namespace MWMechanics /* Start of tes3mp addition - Ignore projectiles fired by DedicatedPlayers + Ignore projectiles fired by DedicatedPlayers and DedicatedActors + + If fired by LocalPlayers and LocalActors, get the associated LocalAttack and set its type + to RANGED */ - if (mwmp::PlayerList::isDedicatedPlayer(attacker)) + if (mwmp::PlayerList::isDedicatedPlayer(attacker) || mwmp::Main::get().getCellController()->isDedicatedActor(attacker)) return; + + mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker); + + if (localAttack) + localAttack->type = mwmp::Attack::RANGED; /* End of tes3mp addition */ @@ -245,10 +253,10 @@ namespace MWMechanics /* Start of tes3mp addition - Mark this as a successful attack for LocalPlayer unless proven otherwise + Mark this as a successful attack for the associated LocalAttack unless proven otherwise */ - if (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - mwmp::Main::get().getLocalPlayer()->attack.success = true; + if (localAttack) + localAttack->success = true; /* End of tes3mp addition */ @@ -258,11 +266,10 @@ namespace MWMechanics /* Start of tes3mp addition - Mark this as a failed attack for LocalPlayer now that the hit roll - has failed + Mark this as a failed LocalAttack now that the hit roll has failed */ - if (attacker == getPlayer()) - mwmp::Main::get().getLocalPlayer()->attack.success = false; + if (localAttack) + localAttack->success = false; /* End of tes3mp addition */ @@ -312,8 +319,6 @@ namespace MWMechanics Track whether the strike enchantment is successful for attacks by the LocalPlayer or LocalActors for both their weapon and projectile */ - mwmp::Attack *localAttack = MechanicsHelper::getLocalAttack(attacker); - bool appliedEnchantment = applyOnStrikeEnchantment(attacker, victim, weapon, hitPosition, true); if (localAttack) @@ -342,6 +347,19 @@ namespace MWMechanics victim.getClass().onHit(victim, damage, true, projectile, attacker, hitPosition, true); } + /* + Start of tes3mp addition + + If this is a local attack that had no victim, send a packet for it here + */ + else if (localAttack) + { + localAttack->hitPosition = MechanicsHelper::getPositionFromVector(hitPosition); + localAttack->shouldSend = true; + } + /* + End of tes3mp addition + */ } float getHitChance(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, int skillValue) diff --git a/apps/openmw/mwmp/MechanicsHelper.cpp b/apps/openmw/mwmp/MechanicsHelper.cpp index fd2b309f6..501abb0be 100644 --- a/apps/openmw/mwmp/MechanicsHelper.cpp +++ b/apps/openmw/mwmp/MechanicsHelper.cpp @@ -204,14 +204,16 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) { if (!attack.pressed) { - LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Processing attack from %s", - attacker.getCellRef().getRefId().c_str()); + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Processing attack from %s of type %i", + attacker.getCellRef().getRefId().c_str(), attack.type); LOG_APPEND(Log::LOG_VERBOSE, "- success: %s", attack.success ? "true" : "false"); if (attack.success) LOG_APPEND(Log::LOG_VERBOSE, "- damage: %f", attack.damage); } + LOG_APPEND(Log::LOG_VERBOSE, "- pressed: %s", attack.pressed ? "true" : "false"); + MWMechanics::CreatureStats &attackerStats = attacker.getClass().getCreatureStats(attacker); MWWorld::Ptr victim; @@ -231,12 +233,14 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) victim = controller->getDedicatedActor(attack.target.refNum, attack.target.mpNum)->getPtr(); } - // Get the weapon used (if hand-to-hand, weapon = inv.end()) - if (attack.type == attack.MELEE) + if (attack.type == attack.MELEE || attack.type == attack.RANGED) { + bool isRanged = attack.type == attack.RANGED; + MWWorld::Ptr weapon; MWWorld::Ptr projectile; + // Get the weapon used; if using hand-to-hand, the weapon is equal to inv.end() if (attacker.getClass().hasInventoryStore(attacker)) { MWWorld::InventoryStore &inventoryStore = attacker.getClass().getInventoryStore(attacker); @@ -253,40 +257,44 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) weapon = MWWorld::Ptr(); } - if (victim.mRef != nullptr) - { - bool healthdmg = true; + bool isHealthDamage = true; - if (weapon.isEmpty()) + if (weapon.isEmpty()) + { + if (attacker.getClass().isBipedal(attacker)) { - if (attacker.getClass().isBipedal(attacker)) - { - MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim); - healthdmg = otherstats.isParalyzed() || otherstats.getKnockedDown(); - } + MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim); + isHealthDamage = otherstats.isParalyzed() || otherstats.getKnockedDown(); } - else - { - LOG_APPEND(Log::LOG_VERBOSE, "- weapon: %s", weapon.getCellRef().getRefId().c_str()); + } + else + { + LOG_APPEND(Log::LOG_VERBOSE, "- weapon: %s\n- isRanged: %s\n- applyWeaponEnchantment: %s\n- applyProjectileEnchantment: %s", + weapon.getCellRef().getRefId().c_str(), isRanged ? "true" : "false", attack.applyWeaponEnchantment ? "true" : "false", + attack.applyProjectileEnchantment ? "true" : "false"); - MWMechanics::blockMeleeAttack(attacker, victim, weapon, attack.damage, 1); + if (attack.applyWeaponEnchantment) + { + MWMechanics::CastSpell cast(attacker, victim, isRanged); + cast.mHitPosition = attack.hitPosition.asVec3(); - if (attack.applyWeaponEnchantment) - { - MWMechanics::CastSpell cast(attacker, victim, false); - cast.mHitPosition = attack.hitPosition.asVec3(); - cast.cast(weapon, false); - } + cast.cast(weapon, false); + } - if (attack.applyProjectileEnchantment) - { - MWMechanics::CastSpell cast(attacker, victim, false); - cast.mHitPosition = attack.hitPosition.asVec3(); - cast.cast(projectile, false); - } + if (isRanged && !projectile.isEmpty() && attack.applyProjectileEnchantment) + { + MWMechanics::CastSpell cast(attacker, victim, isRanged); + cast.mHitPosition = attack.hitPosition.asVec3(); + cast.cast(projectile, false); } + } + + if (victim.mRef != nullptr) + { + if (!isRanged) + MWMechanics::blockMeleeAttack(attacker, victim, weapon, attack.damage, 1); - victim.getClass().onHit(victim, attack.damage, healthdmg, weapon, attacker, attack.hitPosition.asVec3(), + victim.getClass().onHit(victim, attack.damage, isHealthDamage, weapon, attacker, attack.hitPosition.asVec3(), attack.success); } } @@ -300,7 +308,7 @@ void MechanicsHelper::processAttack(Attack attack, const MWWorld::Ptr& attacker) attack.instant = false; } - LOG_APPEND(Log::LOG_VERBOSE, "- spellId: %s, success: %s", attack.spellId.c_str(), attack.success ? "true" : "false"); + LOG_APPEND(Log::LOG_VERBOSE, "- spellId: %s", attack.spellId.c_str()); } else if (attack.type == attack.ITEM_MAGIC) { diff --git a/components/openmw-mp/Base/BaseStructs.hpp b/components/openmw-mp/Base/BaseStructs.hpp index cf809f4a7..d877d54e5 100644 --- a/components/openmw-mp/Base/BaseStructs.hpp +++ b/components/openmw-mp/Base/BaseStructs.hpp @@ -69,6 +69,7 @@ namespace mwmp enum TYPE { MELEE = 0, + RANGED, MAGIC, ITEM_MAGIC, THROWABLE diff --git a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp index 2e0daa1a6..ffb054cd1 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorAttack.cpp @@ -26,19 +26,19 @@ void PacketActorAttack::Actor(BaseActor &actor, bool send) RW(actor.attack.type, send); - if (actor.attack.type == mwmp::Attack::MELEE || actor.attack.type == mwmp::Attack::MAGIC) + if (actor.attack.type == mwmp::Attack::ITEM_MAGIC) + RW(actor.attack.itemId, send, true); + else { RW(actor.attack.pressed, send); RW(actor.attack.success, send); - if (actor.attack.success) + if (actor.attack.type == mwmp::Attack::MAGIC) { - RW(actor.attack.hitPosition.pos[0], send); - RW(actor.attack.hitPosition.pos[1], send); - RW(actor.attack.hitPosition.pos[2], send); + RW(actor.attack.instant, send); + RW(actor.attack.spellId, send, true); } - - if (actor.attack.type == mwmp::Attack::MELEE) + else { RW(actor.attack.damage, send); RW(actor.attack.block, send); @@ -46,13 +46,13 @@ void PacketActorAttack::Actor(BaseActor &actor, bool send) RW(actor.attack.applyWeaponEnchantment, send); RW(actor.attack.applyProjectileEnchantment, send); - } - else if (actor.attack.type == mwmp::Attack::MAGIC) - { - RW(actor.attack.instant, send); - RW(actor.attack.spellId, send, true); + + if (actor.attack.success || actor.attack.applyWeaponEnchantment || actor.attack.applyProjectileEnchantment) + { + RW(actor.attack.hitPosition.pos[0], send); + RW(actor.attack.hitPosition.pos[1], send); + RW(actor.attack.hitPosition.pos[2], send); + } } } - else if (actor.attack.type == mwmp::Attack::ITEM_MAGIC) - RW(actor.attack.itemId, send, true); } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp index bd7144fe0..b28e5c0ff 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerAttack.cpp @@ -27,19 +27,19 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send) RW(player->attack.type, send); - if (player->attack.type == mwmp::Attack::MELEE || player->attack.type == mwmp::Attack::MAGIC) + if (player->attack.type == mwmp::Attack::ITEM_MAGIC) + RW(player->attack.itemId, send, true); + else { RW(player->attack.pressed, send); RW(player->attack.success, send); - if (player->attack.success) + if (player->attack.type == mwmp::Attack::MAGIC) { - RW(player->attack.hitPosition.pos[0], send); - RW(player->attack.hitPosition.pos[1], send); - RW(player->attack.hitPosition.pos[2], send); + RW(player->attack.instant, send); + RW(player->attack.spellId, send, true); } - - if (player->attack.type == mwmp::Attack::MELEE) + else { RW(player->attack.damage, send); RW(player->attack.block, send); @@ -47,13 +47,13 @@ void PacketPlayerAttack::Packet(RakNet::BitStream *bs, bool send) RW(player->attack.applyWeaponEnchantment, send); RW(player->attack.applyProjectileEnchantment, send); - } - else if (player->attack.type == mwmp::Attack::MAGIC) - { - RW(player->attack.instant, send); - RW(player->attack.spellId, send, true); + + if (player->attack.success || player->attack.applyWeaponEnchantment || player->attack.applyProjectileEnchantment) + { + RW(player->attack.hitPosition.pos[0], send); + RW(player->attack.hitPosition.pos[1], send); + RW(player->attack.hitPosition.pos[2], send); + } } } - else if (player->attack.type == mwmp::Attack::ITEM_MAGIC) - RW(player->attack.itemId, send, true); }