Skip to content

Commit

Permalink
Sync Sea Dragons
Browse files Browse the repository at this point in the history
  • Loading branch information
tornac1234 committed Feb 15, 2024
1 parent 1f7f9ec commit c0598d1
Show file tree
Hide file tree
Showing 36 changed files with 903 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using HarmonyLib;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NitroxTest.Patcher;

namespace NitroxPatcher.Patches.Dynamic;

[TestClass]
public class SeaDragonMeleeAttack_OnTouchFront_PatchTest
{
[TestMethod]
public void Sanity()
{
IEnumerable<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(SeaDragonMeleeAttack_OnTouchFront_Patch.TARGET_METHOD);
IEnumerable<CodeInstruction> transformedIl = SeaDragonMeleeAttack_OnTouchFront_Patch.Transpiler(originalIl);
transformedIl.Count().Should().Be(originalIl.Count() + 9);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using HarmonyLib;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NitroxTest.Patcher;

namespace NitroxPatcher.Patches.Dynamic;

[TestClass]
public class SeaDragonMeleeAttack_SwatAttack_PatchTest
{
[TestMethod]
public void Sanity()
{
IEnumerable<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(SeaDragonMeleeAttack_SwatAttack_Patch.TARGET_METHOD);
IEnumerable<CodeInstruction> transformedIl = SeaDragonMeleeAttack_SwatAttack_Patch.Transpiler(originalIl);
transformedIl.Count().Should().Be(originalIl.Count() + 4);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using NitroxClient.Communication.Packets.Processors.Abstract;
using NitroxClient.GameLogic;
using NitroxModel.Packets;

namespace NitroxClient.Communication.Packets.Processors;

public class RangedAttackLastTargetUpdateProcessor : ClientPacketProcessor<RangedAttackLastTargetUpdate>
{
public override void Process(RangedAttackLastTargetUpdate packet)
{
AI.RangedAttackLastTargetUpdate(packet.CreatureId, packet.TargetId, packet.AttackTypeIndex, packet.State);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using NitroxClient.Communication.Packets.Processors.Abstract;
using NitroxClient.GameLogic.PlayerLogic;
using NitroxClient.MonoBehaviours;
using NitroxModel.Packets;
using UnityEngine;

namespace NitroxClient.Communication.Packets.Processors;

public class SeaDragonAttackTargetProcessor : ClientPacketProcessor<SeaDragonAttackTarget>
{
public override void Process(SeaDragonAttackTarget packet)
{
if (!NitroxEntity.TryGetComponentFrom(packet.SeaDragonId, out SeaDragonMeleeAttack seaDragonMeleeAttack) ||
!NitroxEntity.TryGetObjectFrom(packet.TargetId, out GameObject target))
{
return;
}

seaDragonMeleeAttack.seaDragon.Aggression.Value = packet.Aggression;
if (target.GetComponent<SubControl>())
{
// SeaDragonMeleeAttack.OnTouchFront's useful part about Cyclops attack
seaDragonMeleeAttack.animator.SetTrigger("shove");
seaDragonMeleeAttack.SendMessage("OnMeleeAttack", target, SendMessageOptions.DontRequireReceiver);
seaDragonMeleeAttack.timeLastBite = Time.time;
return;
}


// SeaDragonMeleeAttack.OnTouchFront's useful part about local player attack
Collider collider;
if (target.TryGetComponent(out RemotePlayerIdentifier remotePlayerIdentifier))
{
collider = remotePlayerIdentifier.RemotePlayer.Collider;
}
else if (target.GetComponent<Player>())
{
collider = Player.mainCollider;
}
else
{
return;
}

seaDragonMeleeAttack.timeLastBite = Time.time;
if (seaDragonMeleeAttack.attackSound)
{
// TODO: Adapt this code when #1780 is merged
Utils.PlayEnvSound(seaDragonMeleeAttack.attackSound, collider.transform.position, 20f);
}
seaDragonMeleeAttack.OnTouch(collider);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using NitroxClient.Communication.Packets.Processors.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxModel.Packets;

namespace NitroxClient.Communication.Packets.Processors;

public class SeaDragonGrabExosuitProcessor : ClientPacketProcessor<SeaDragonGrabExosuit>
{
public override void Process(SeaDragonGrabExosuit packet)
{
if (!NitroxEntity.TryGetComponentFrom(packet.SeaDragonId, out SeaDragon seaDragon) ||
!NitroxEntity.TryGetComponentFrom(packet.TargetId, out Exosuit exosuit))
{
return;
}

using (PacketSuppressor<SeaDragonGrabExosuit>.Suppress())
{
seaDragon.GrabExosuit(exosuit);
seaDragon.CancelInvoke(nameof(SeaDragon.DamageExosuit));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using NitroxClient.Communication.Packets.Processors.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxModel.Packets;
using UnityEngine;

namespace NitroxClient.Communication.Packets.Processors;

public class SeaDragonSwatAttackProcessor : ClientPacketProcessor<SeaDragonSwatAttack>
{
public override void Process(SeaDragonSwatAttack packet)
{
if (!NitroxEntity.TryGetComponentFrom(packet.SeaDragonId, out SeaDragonMeleeAttack seaDragonMeleeAttack) ||
!NitroxEntity.TryGetObjectFrom(packet.TargetId, out GameObject targetObject))
{
return;
}

using (PacketSuppressor<SeaDragonSwatAttack>.Suppress())
{
seaDragonMeleeAttack.seaDragon.Aggression.Value = packet.Aggression;
seaDragonMeleeAttack.SwatAttack(targetObject, packet.IsRightHand);
}
}
}
30 changes: 28 additions & 2 deletions NitroxClient/GameLogic/AI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using NitroxModel.DataStructures;
using NitroxModel.Packets;
using UnityEngine;
using static NitroxModel.Packets.RangedAttackLastTargetUpdate;

namespace NitroxClient.GameLogic;

Expand All @@ -22,7 +23,7 @@ public class AI
/// </summary>
private readonly HashSet<Type> creatureActionWhitelist =
[
typeof(AttackLastTarget), typeof(AttackCyclops)
typeof(AttackLastTarget), typeof(RangedAttackLastTarget), typeof(AttackCyclops)
];

/// <summary>
Expand Down Expand Up @@ -50,7 +51,7 @@ public void BroadcastNewAction(NitroxId creatureId, Creature creature, CreatureA
return;
}

ErrorMessage.AddMessage($"[SEND] reaper action: {newAction.GetType().FullName}");
ErrorMessage.AddMessage($"[SEND] synced action: {newAction.GetType().FullName}");
packetSender.Send(new CreatureActionChanged(creatureId, newAction.GetType().FullName));
}

Expand Down Expand Up @@ -117,6 +118,31 @@ public static void AttackCyclopsTargetChanged(NitroxId creatureId, NitroxId targ
attackCyclops.SetCurrentTarget(targetObject, targetObject.GetComponent<CyclopsDecoy>());
}

public static void RangedAttackLastTargetUpdate(NitroxId creatureId, NitroxId targetId, int attackTypeIndex, ActionState state)
{
if (!NitroxEntity.TryGetComponentFrom(creatureId, out RangedAttackLastTarget rangedAttackLastTarget) ||
!NitroxEntity.TryGetObjectFrom(targetId, out GameObject targetObject))
{
return;
}

RangedAttackLastTarget.RangedAttackType attackType = rangedAttackLastTarget.attackTypes[attackTypeIndex];
rangedAttackLastTarget.currentAttack = attackType;
rangedAttackLastTarget.currentTarget = targetObject;

switch (state)
{
case ActionState.CHARGING:
rangedAttackLastTarget.StartCharging(attackType);
ErrorMessage.AddMessage($"[GET] {rangedAttackLastTarget.name} charges against {targetObject.name}");
break;
case ActionState.CASTING:
rangedAttackLastTarget.StartCasting(attackType);
ErrorMessage.AddMessage($"[GET] {rangedAttackLastTarget.name} casts against {targetObject.name}");
break;
}
}

public bool TryGetActionForCreature(Creature creature, out CreatureAction action)
{
// TODO: Fix ondeath cinematic being played for all players when getting bitten by a reaper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ private void SetPlayerPermissions(Perms permissions)

private void SetPlayerGameObjectId(NitroxId id)
{
EcoTarget playerEcoTarget = Player.mainObject.AddComponent<EcoTarget>();
playerEcoTarget.SetTargetType(RemotePlayer.PLAYER_ECO_TARGET_TYPE);

NitroxEntity.SetNewId(Player.mainObject, id);
Log.Info($"Received initial sync player GameObject Id: {id}");
}
Expand Down
23 changes: 21 additions & 2 deletions NitroxClient/GameLogic/RemotePlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ namespace NitroxClient.GameLogic
{
public class RemotePlayer : INitroxPlayer
{
/// <summary>
/// Marks <see cref="Player.mainObject"/> and every <see cref="Body"/> so they can be precisely queried (e.g. by sea dragons).
/// </summary>
public const EcoTargetType PLAYER_ECO_TARGET_TYPE = (EcoTargetType)5050;
private static readonly int animatorPlayerIn = Animator.StringToHash("player_in");

private readonly PlayerModelManager playerModelManager;
Expand Down Expand Up @@ -311,8 +315,14 @@ public void UpdateEquipmentVisibility(List<TechType> equippedItems)
private void SetupBody()
{
// set as a target for reapers
EcoTarget ecoTarget = Body.AddComponent<EcoTarget>();
ecoTarget.SetTargetType(EcoTargetType.Shark);
EcoTarget sharkEcoTarget = Body.AddComponent<EcoTarget>();
sharkEcoTarget.SetTargetType(EcoTargetType.Shark);

EcoTarget playerEcoTarget = Body.AddComponent<EcoTarget>();
playerEcoTarget.SetTargetType(PLAYER_ECO_TARGET_TYPE);

TechTag techTag = Body.AddComponent<TechTag>();
techTag.type = TechType.Player;

RemotePlayerIdentifier identifier = Body.AddComponent<RemotePlayerIdentifier>();
identifier.RemotePlayer = this;
Expand Down Expand Up @@ -397,5 +407,14 @@ private void RefreshVitalsVisibility()
vitals.SetStatsVisible(visible);
}
}

/// <summary>
/// Adaptation of <see cref="Player.CanBeAttacked"/> for remote players.
/// NB: This doesn't check for other player's use of 'invisible' command
/// </summary>
public bool CanBeAttacked()
{
return !SubRoot && !EscapePod && PlayerContext.GameMode != NitroxGameMode.CREATIVE;
}
}
}
27 changes: 27 additions & 0 deletions NitroxModel/Packets/RangedAttackLastTargetUpdate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using NitroxModel.DataStructures;

namespace NitroxModel.Packets;

[Serializable]
public class RangedAttackLastTargetUpdate : Packet
{
public NitroxId CreatureId { get; }
public NitroxId TargetId { get; }
public int AttackTypeIndex { get; }
public ActionState State { get; }

public RangedAttackLastTargetUpdate(NitroxId creatureId, NitroxId targetId, int attackTypeIndex, ActionState state)
{
CreatureId = creatureId;
TargetId = targetId;
AttackTypeIndex = attackTypeIndex;
State = state;
}

public enum ActionState
{
CHARGING,
CASTING
}
}
19 changes: 19 additions & 0 deletions NitroxModel/Packets/SeaDragonAttackTarget.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using NitroxModel.DataStructures;

namespace NitroxModel.Packets;

[Serializable]
public class SeaDragonAttackTarget : Packet
{
public NitroxId SeaDragonId { get; }
public NitroxId TargetId { get; }
public float Aggression { get; }

public SeaDragonAttackTarget(NitroxId seaDragonId, NitroxId targetId, float aggression)
{
SeaDragonId = seaDragonId;
TargetId = targetId;
Aggression = aggression;
}
}
17 changes: 17 additions & 0 deletions NitroxModel/Packets/SeaDragonGrabExosuit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using NitroxModel.DataStructures;

namespace NitroxModel.Packets;

[Serializable]
public class SeaDragonGrabExosuit : Packet
{
public NitroxId SeaDragonId { get; }
public NitroxId TargetId { get; }

public SeaDragonGrabExosuit(NitroxId seaDragonId, NitroxId targetId)
{
SeaDragonId = seaDragonId;
TargetId = targetId;
}
}
21 changes: 21 additions & 0 deletions NitroxModel/Packets/SeaDragonSwatAttack.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using NitroxModel.DataStructures;

namespace NitroxModel.Packets;

[Serializable]
public class SeaDragonSwatAttack : Packet
{
public NitroxId SeaDragonId { get; }
public NitroxId TargetId { get; }
public bool IsRightHand { get; }
public float Aggression { get; }

public SeaDragonSwatAttack(NitroxId seaDragonId, NitroxId targetId, bool isRightHand, float aggression)
{
SeaDragonId = seaDragonId;
TargetId = targetId;
IsRightHand = isRightHand;
Aggression = aggression;
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System.Reflection;
using NitroxClient.GameLogic;
using NitroxClient.GameLogic.PlayerLogic;
using NitroxModel.Helper;
using UnityEngine;

namespace NitroxPatcher.Patches.Dynamic;

/// <summary>
/// Allow creatures to chose remote players as targets only if they're not in creative mode.
/// NB: This doesn't check for other player's use of 'invisible' command
/// Allow creatures to chose remote players as targets only if they can be attacked (<see cref="RemotePlayer.CanBeAttacked"/>)
/// </summary>
public sealed partial class AggressiveWhenSeeTarget_IsTargetValid_Patch : NitroxPatch, IDynamicPatch
{
Expand All @@ -19,9 +19,9 @@ public static bool Prefix(GameObject target, ref bool __result)
{
return false;
}
// We only want to cancel if the remote player is a target but
// We only want to cancel if the target is a remote player which can't attacked
if (target.TryGetComponent(out RemotePlayerIdentifier remotePlayerIdentifier) &&
remotePlayerIdentifier.RemotePlayer.PlayerContext.GameMode == NitroxModel.Server.NitroxGameMode.CREATIVE)
!remotePlayerIdentifier.RemotePlayer.CanBeAttacked())
{
__result = false;
return false;
Expand Down
Loading

0 comments on commit c0598d1

Please sign in to comment.