Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MTTB-409] Fix a Healer ability doesn't work (#893) #893

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Assets/GameData/Action/Mage/MageHeal.asset
Git LFS file not shown
35 changes: 25 additions & 10 deletions Assets/Scripts/Gameplay/Action/ActionUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,35 @@ public static class ActionUtils
const float k_VeryCloseTeleportRange = k_CloseDistanceOffset + 1;

/// <summary>
/// Does a melee foe hit detect.
/// Detects friends and/or foes near us.
/// </summary>
/// <param name="isNPC">true if the attacker is an NPC (and therefore should hit PCs). False for the reverse.</param>
/// <param name="wantPcs">true if we should detect PCs</param>
/// <param name="wantNpcs">true if we should detect NPCs</param>
/// <param name="attacker">The collider of the attacking GameObject.</param>
/// <param name="range">The range in meters to check for foes.</param>
/// <param name="range">The range in meters to check.</param>
/// <param name="radius">The radius in meters to check.</param>
/// <param name="results">Place an uninitialized RayCastHit[] ref in here. It will be set to the results array. </param>
/// <remarks>
/// This method does not alloc. It returns a maximum of 4 results. Consume the results immediately, as the array will be overwritten with
/// the next similar query.
/// </remarks>
/// <returns>Total number of foes encountered. </returns>
public static int DetectMeleeFoe(bool isNPC, Collider attacker, float range, out RaycastHit[] results)
/// <returns></returns>
public static int DetectNearbyEntitiesUseSphere(bool wantPcs, bool wantNpcs, Collider attacker, float range, float radius, out RaycastHit[] results)
{
return DetectNearbyEntities(isNPC, !isNPC, attacker, range, out results);
var myBounds = attacker.bounds;

if (s_PCLayer == -1)
s_PCLayer = LayerMask.NameToLayer("PCs");
if (s_NpcLayer == -1)
s_NpcLayer = LayerMask.NameToLayer("NPCs");

int mask = 0;
if (wantPcs)
mask |= (1 << s_PCLayer);
if (wantNpcs)
mask |= (1 << s_NpcLayer);

int numResults = Physics.SphereCastNonAlloc(attacker.transform.position, radius,
attacker.transform.forward, s_Hits, range, mask);

results = s_Hits;
return numResults;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ private void PerformMeleeAttack(ServerCharacter parent)
// perform a typical melee-hit. But note that we are using the Radius field for range, not the Range field!
IDamageable foe = MeleeAction.GetIdealMeleeFoe(Config.IsFriendly ^ parent.IsNpc,
parent.physicsWrapper.DamageCollider,
Config.Radius,
Config.Radius, 0.0f,
(Data.TargetIds != null && Data.TargetIds.Length > 0 ? Data.TargetIds[0] : 0));

if (foe != null)
Expand Down
33 changes: 28 additions & 5 deletions Assets/Scripts/Gameplay/Action/ConcreteActions/MeleeAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public override bool OnUpdate(ServerCharacter clientCharacter)
/// <returns></returns>
private IDamageable DetectFoe(ServerCharacter parent, ulong foeHint = 0)
{
return GetIdealMeleeFoe(Config.IsFriendly ^ parent.IsNpc, parent.physicsWrapper.DamageCollider, Config.Range, foeHint);
return GetIdealMeleeFoe(Config.IsFriendly ^ parent.IsNpc, parent.physicsWrapper.DamageCollider, Config.Range, Config.Radius, foeHint);
}

/// <summary>
Expand All @@ -96,25 +96,48 @@ private IDamageable DetectFoe(ServerCharacter parent, ulong foeHint = 0)
/// <param name="isNPC">true if the attacker is an NPC (and therefore should hit PCs). False for the reverse.</param>
/// <param name="ourCollider">The collider of the attacking GameObject.</param>
/// <param name="meleeRange">The range in meters to check for foes.</param>
/// <param name="meleeRadius">The radius in meters to check for foes.</param>
/// <param name="preferredTargetNetworkId">The NetworkObjectId of our preferred foe, or 0 if no preference</param>
/// <returns>ideal target's IDamageable, or null if no valid target found</returns>
public static IDamageable GetIdealMeleeFoe(bool isNPC, Collider ourCollider, float meleeRange, ulong preferredTargetNetworkId)
/// <remarks>
/// If a Radius value is set (greater than 0), collision checking will be done with a Sphere the size of the Radius, not the size of the Box.
/// Also, if multiple targets collide as a result, the target with the highest total damage is prioritized.
/// </remarks>
public static IDamageable GetIdealMeleeFoe(bool isNPC, Collider ourCollider, float meleeRange, float meleeRadius, ulong preferredTargetNetworkId)
{
RaycastHit[] results;
int numResults = ActionUtils.DetectMeleeFoe(isNPC, ourCollider, meleeRange, out results);
int numResults = 0.0f < meleeRadius
? ActionUtils.DetectNearbyEntitiesUseSphere(isNPC, !isNPC, ourCollider, meleeRange, meleeRadius, out results)
: ActionUtils.DetectNearbyEntities(isNPC, !isNPC, ourCollider, meleeRange, out results);

IDamageable foundFoe = null;

//everything that got hit by the raycast should have an IDamageable component, so we can retrieve that and see if they're appropriate targets.
//we always prefer the hinted foe. If he's still in range, he should take the damage, because he's who the client visualization
//system will play the hit-react on (in case there's any ambiguity).
//if that is not the case, we prioritize the target with the highest total damage.
int maxDamage = int.MinValue;

for (int i = 0; i < numResults; i++)
{
var damageable = results[i].collider.GetComponent<IDamageable>();
if (damageable != null && damageable.IsDamageable() &&
(damageable.NetworkObjectId == preferredTargetNetworkId || foundFoe == null))
if (damageable == null || !damageable.IsDamageable())
{
continue;
}

if (damageable.NetworkObjectId == preferredTargetNetworkId)
{
foundFoe = damageable;
maxDamage = int.MaxValue;
continue;
}

var totalDamage = damageable.GetTotalDamage();
if (foundFoe == null || maxDamage < totalDamage)
{
foundFoe = damageable;
maxDamage = totalDamage;
}
}

Expand Down
5 changes: 5 additions & 0 deletions Assets/Scripts/Gameplay/GameplayObjects/Breakable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ public void ReceiveHP(ServerCharacter inflicter, int HP)
}
}

public int GetTotalDamage()
{
return Math.Max(0, m_MaxHealth.Value - m_NetworkHealthState.HitPoints.Value);
}

private void Break()
{
IsBroken.Value = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections;
using Unity.BossRoom.ConnectionManagement;
using Unity.BossRoom.Gameplay.Actions;
Expand Down Expand Up @@ -156,6 +157,7 @@ public override void OnNetworkSpawn()
NetLifeState.LifeState.OnValueChanged += OnLifeStateChanged;
m_DamageReceiver.DamageReceived += ReceiveHP;
m_DamageReceiver.CollisionEntered += CollisionEntered;
m_DamageReceiver.GetTotalDamageFunc += GetTotalDamage;

if (IsNpc)
{
Expand All @@ -179,6 +181,7 @@ public override void OnNetworkDespawn()
{
m_DamageReceiver.DamageReceived -= ReceiveHP;
m_DamageReceiver.CollisionEntered -= CollisionEntered;
m_DamageReceiver.GetTotalDamageFunc -= GetTotalDamage;
}
}

Expand Down Expand Up @@ -393,6 +396,11 @@ void CollisionEntered(Collision collision)
}
}

int GetTotalDamage()
{
return Math.Max(0, CharacterClass.BaseHP.Value - HitPoints);
}

/// <summary>
/// This character's AIBrain. Will be null if this is not an NPC.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions Assets/Scripts/Gameplay/GameplayObjects/DamageReceiver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class DamageReceiver : NetworkBehaviour, IDamageable

public event Action<Collision> CollisionEntered;

public event Func<int> GetTotalDamageFunc;

[SerializeField]
NetworkLifeState m_NetworkLifeState;

Expand All @@ -22,6 +24,16 @@ public void ReceiveHP(ServerCharacter inflicter, int HP)
}
}

public int GetTotalDamage()
{
if (!IsDamageable())
{
return 0;
}

return GetTotalDamageFunc?.Invoke() ?? 0;
}

public IDamageable.SpecialDamageFlags GetSpecialDamageFlags()
{
return IDamageable.SpecialDamageFlags.None;
Expand Down
6 changes: 6 additions & 0 deletions Assets/Scripts/Gameplay/GameplayObjects/IDamageable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public interface IDamageable
/// <param name="HP">The damage done. Negative value is damage, positive is healing.</param>
void ReceiveHP(ServerCharacter inflicter, int HP);

/// <summary>
/// Get the total damage value.
/// </summary>
/// <returns>The return value is your total health minus your current health.</returns>
int GetTotalDamage();

/// <summary>
/// The NetworkId of this object.
/// </summary>
Expand Down
6 changes: 5 additions & 1 deletion Assets/Scripts/Gameplay/UserInput/ClientInputSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,11 @@ void PopulateSkillRequest(Vector3 hitPoint, ActionID actionID, ref ActionRequest
// figure out the Direction in case we want to send it
Vector3 offset = hitPoint - m_PhysicsWrapper.Transform.position;
offset.y = 0;
Vector3 direction = offset.normalized;

//there is a bug where the direction is flipped if the hitPos and current position are almost the same,
//so we use the character's direction instead.
float directionLength = offset.magnitude;
Vector3 direction = 1.0f/*epsilon*/ <= directionLength ? (offset / directionLength) : m_PhysicsWrapper.Transform.forward;

switch (actionConfig.Logic)
{
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Cleanup
* Removed ParrelSync from the project

### Fixed
* Fix a Healer ability doesn't work (#893)
* Changed the way characters are oriented when using skills.
* Added the GetTotalDamage API to the IDamagble interface. This number is your maximum health minus your current health.
* Changed the way MeleeAction selects a target when there are multiple targets to collide with. The target with the highest GetTotalDamage value (mentioned above) will be selected.


## [2.5.0] - 2024-04-18

Expand Down
Loading