Skip to content

Commit 862ae97

Browse files
committed
Sync Sea Dragons
1 parent 1a987e9 commit 862ae97

File tree

36 files changed

+889
-21
lines changed

36 files changed

+889
-21
lines changed

Nitrox.Test/Patcher/Patches/Dynamic/SpawnConsoleCommand_OnConsoleCommand_PatchTest.cs renamed to Nitrox.Test/Patcher/Patches/Dynamic/SeaDragonMeleeAttack_OnTouchFront_PatchTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
namespace NitroxPatcher.Patches.Dynamic;
99

1010
[TestClass]
11-
public class SpawnConsoleCommand_OnConsoleCommand_PatchTest
11+
public class SeaDragonMeleeAttack_OnTouchFront_PatchTest
1212
{
1313
[TestMethod]
1414
public void Sanity()
1515
{
16-
IEnumerable<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(SpawnConsoleCommand_OnConsoleCommand_Patch.TARGET_METHOD);
17-
IEnumerable<CodeInstruction> transformedIl = SpawnConsoleCommand_OnConsoleCommand_Patch.Transpiler(originalIl);
18-
transformedIl.Count().Should().Be(originalIl.Count() + 2);
16+
IEnumerable<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(SeaDragonMeleeAttack_OnTouchFront_Patch.TARGET_METHOD);
17+
IEnumerable<CodeInstruction> transformedIl = SeaDragonMeleeAttack_OnTouchFront_Patch.Transpiler(originalIl);
18+
transformedIl.Count().Should().Be(originalIl.Count() + 9);
1919
}
2020
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using FluentAssertions;
4+
using HarmonyLib;
5+
using Microsoft.VisualStudio.TestTools.UnitTesting;
6+
using NitroxTest.Patcher;
7+
8+
namespace NitroxPatcher.Patches.Dynamic;
9+
10+
[TestClass]
11+
public class SeaDragonMeleeAttack_SwatAttack_PatchTest
12+
{
13+
[TestMethod]
14+
public void Sanity()
15+
{
16+
IEnumerable<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(SeaDragonMeleeAttack_SwatAttack_Patch.TARGET_METHOD);
17+
IEnumerable<CodeInstruction> transformedIl = SeaDragonMeleeAttack_SwatAttack_Patch.Transpiler(originalIl);
18+
transformedIl.Count().Should().Be(originalIl.Count() + 4);
19+
}
20+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using NitroxClient.Communication.Packets.Processors.Abstract;
2+
using NitroxClient.GameLogic;
3+
using NitroxModel.Packets;
4+
5+
namespace NitroxClient.Communication.Packets.Processors;
6+
7+
public class RangedAttackLastTargetUpdateProcessor : ClientPacketProcessor<RangedAttackLastTargetUpdate>
8+
{
9+
public override void Process(RangedAttackLastTargetUpdate packet)
10+
{
11+
AI.RangedAttackLastTargetUpdate(packet.CreatureId, packet.TargetId, packet.AttackTypeIndex, packet.State);
12+
}
13+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using NitroxClient.Communication.Packets.Processors.Abstract;
2+
using NitroxClient.GameLogic.PlayerLogic;
3+
using NitroxClient.MonoBehaviours;
4+
using NitroxModel.Packets;
5+
using UnityEngine;
6+
7+
namespace NitroxClient.Communication.Packets.Processors;
8+
9+
public class SeaDragonAttackTargetProcessor : ClientPacketProcessor<SeaDragonAttackTarget>
10+
{
11+
public override void Process(SeaDragonAttackTarget packet)
12+
{
13+
if (!NitroxEntity.TryGetComponentFrom(packet.SeaDragonId, out SeaDragonMeleeAttack seaDragonMeleeAttack) ||
14+
!NitroxEntity.TryGetObjectFrom(packet.TargetId, out GameObject target))
15+
{
16+
return;
17+
}
18+
19+
seaDragonMeleeAttack.seaDragon.Aggression.Value = packet.Aggression;
20+
if (target.GetComponent<SubControl>())
21+
{
22+
// SeaDragonMeleeAttack.OnTouchFront's useful part about Cyclops attack
23+
seaDragonMeleeAttack.animator.SetTrigger("shove");
24+
seaDragonMeleeAttack.SendMessage("OnMeleeAttack", target, SendMessageOptions.DontRequireReceiver);
25+
seaDragonMeleeAttack.timeLastBite = Time.time;
26+
return;
27+
}
28+
29+
30+
// SeaDragonMeleeAttack.OnTouchFront's useful part about local player attack
31+
Collider collider;
32+
if (target.TryGetComponent(out RemotePlayerIdentifier remotePlayerIdentifier))
33+
{
34+
collider = remotePlayerIdentifier.RemotePlayer.Collider;
35+
}
36+
else if (target.GetComponent<Player>())
37+
{
38+
collider = Player.mainCollider;
39+
}
40+
else
41+
{
42+
return;
43+
}
44+
45+
seaDragonMeleeAttack.timeLastBite = Time.time;
46+
if (seaDragonMeleeAttack.attackSound)
47+
{
48+
// TODO: Adapt this code when #1780 is merged
49+
Utils.PlayEnvSound(seaDragonMeleeAttack.attackSound, collider.transform.position, 20f);
50+
}
51+
seaDragonMeleeAttack.OnTouch(collider);
52+
}
53+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using NitroxClient.Communication.Packets.Processors.Abstract;
2+
using NitroxClient.MonoBehaviours;
3+
using NitroxModel.Packets;
4+
5+
namespace NitroxClient.Communication.Packets.Processors;
6+
7+
public class SeaDragonGrabExosuitProcessor : ClientPacketProcessor<SeaDragonGrabExosuit>
8+
{
9+
public override void Process(SeaDragonGrabExosuit packet)
10+
{
11+
if (!NitroxEntity.TryGetComponentFrom(packet.SeaDragonId, out SeaDragon seaDragon) ||
12+
!NitroxEntity.TryGetComponentFrom(packet.TargetId, out Exosuit exosuit))
13+
{
14+
return;
15+
}
16+
17+
using (PacketSuppressor<SeaDragonGrabExosuit>.Suppress())
18+
{
19+
seaDragon.GrabExosuit(exosuit);
20+
seaDragon.CancelInvoke(nameof(SeaDragon.DamageExosuit));
21+
}
22+
}
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using NitroxClient.Communication.Packets.Processors.Abstract;
2+
using NitroxClient.MonoBehaviours;
3+
using NitroxModel.Packets;
4+
using UnityEngine;
5+
6+
namespace NitroxClient.Communication.Packets.Processors;
7+
8+
public class SeaDragonSwatAttackProcessor : ClientPacketProcessor<SeaDragonSwatAttack>
9+
{
10+
public override void Process(SeaDragonSwatAttack packet)
11+
{
12+
if (!NitroxEntity.TryGetComponentFrom(packet.SeaDragonId, out SeaDragonMeleeAttack seaDragonMeleeAttack) ||
13+
!NitroxEntity.TryGetObjectFrom(packet.TargetId, out GameObject targetObject))
14+
{
15+
return;
16+
}
17+
18+
using (PacketSuppressor<SeaDragonSwatAttack>.Suppress())
19+
{
20+
seaDragonMeleeAttack.seaDragon.Aggression.Value = packet.Aggression;
21+
seaDragonMeleeAttack.SwatAttack(targetObject, packet.IsRightHand);
22+
}
23+
}
24+
}

NitroxClient/GameLogic/AI.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using NitroxModel.DataStructures;
88
using NitroxModel.Packets;
99
using UnityEngine;
10+
using static NitroxModel.Packets.RangedAttackLastTargetUpdate;
1011

1112
namespace NitroxClient.GameLogic;
1213

@@ -22,7 +23,7 @@ public class AI
2223
/// </summary>
2324
private readonly HashSet<Type> creatureActionWhitelist =
2425
[
25-
typeof(AttackLastTarget), typeof(AttackCyclops)
26+
typeof(AttackLastTarget), typeof(RangedAttackLastTarget), typeof(AttackCyclops)
2627
];
2728

2829
/// <summary>
@@ -50,7 +51,7 @@ public void BroadcastNewAction(NitroxId creatureId, Creature creature, CreatureA
5051
return;
5152
}
5253

53-
ErrorMessage.AddMessage($"[SEND] reaper action: {newAction.GetType().FullName}");
54+
ErrorMessage.AddMessage($"[SEND] synced action: {newAction.GetType().FullName}");
5455
packetSender.Send(new CreatureActionChanged(creatureId, newAction.GetType().FullName));
5556
}
5657

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

121+
public static void RangedAttackLastTargetUpdate(NitroxId creatureId, NitroxId targetId, int attackTypeIndex, ActionState state)
122+
{
123+
if (!NitroxEntity.TryGetComponentFrom(creatureId, out RangedAttackLastTarget rangedAttackLastTarget) ||
124+
!NitroxEntity.TryGetObjectFrom(targetId, out GameObject targetObject))
125+
{
126+
return;
127+
}
128+
129+
RangedAttackLastTarget.RangedAttackType attackType = rangedAttackLastTarget.attackTypes[attackTypeIndex];
130+
rangedAttackLastTarget.currentAttack = attackType;
131+
rangedAttackLastTarget.currentTarget = targetObject;
132+
133+
switch (state)
134+
{
135+
case ActionState.CHARGING:
136+
rangedAttackLastTarget.StartCharging(attackType);
137+
ErrorMessage.AddMessage($"[GET] {rangedAttackLastTarget.name} charges against {targetObject.name}");
138+
break;
139+
case ActionState.CASTING:
140+
rangedAttackLastTarget.StartCasting(attackType);
141+
ErrorMessage.AddMessage($"[GET] {rangedAttackLastTarget.name} casts against {targetObject.name}");
142+
break;
143+
}
144+
}
145+
120146
public bool TryGetActionForCreature(Creature creature, out CreatureAction action)
121147
{
122148
// TODO: Fix ondeath cinematic being played for all players when getting bitten by a reaper

NitroxClient/GameLogic/InitialSync/PlayerInitialSyncProcessor.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ private void SetPlayerPermissions(Perms permissions)
4141

4242
private void SetPlayerGameObjectId(NitroxId id)
4343
{
44+
EcoTarget playerEcoTarget = Player.mainObject.AddComponent<EcoTarget>();
45+
playerEcoTarget.SetTargetType(RemotePlayer.PLAYER_ECO_TARGET_TYPE);
46+
4447
NitroxEntity.SetNewId(Player.mainObject, id);
4548
Log.Info($"Received initial sync player GameObject Id: {id}");
4649
}

NitroxClient/GameLogic/RemotePlayer.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ namespace NitroxClient.GameLogic;
1717

1818
public class RemotePlayer : INitroxPlayer
1919
{
20+
/// <summary>
21+
/// Marks <see cref="Player.mainObject"/> and every <see cref="Body"/> so they can be precisely queried (e.g. by sea dragons).
22+
/// The value (5050) is determined arbitrarily and should not be used already.
23+
/// </summary>
24+
public const EcoTargetType PLAYER_ECO_TARGET_TYPE = (EcoTargetType)5050;
25+
2026
private static readonly int animatorPlayerIn = Animator.StringToHash("player_in");
2127

2228
private readonly PlayerModelManager playerModelManager;
@@ -317,8 +323,14 @@ public void UpdateEquipmentVisibility(List<TechType> equippedItems)
317323
private void SetupBody()
318324
{
319325
// set as a target for reapers
320-
EcoTarget ecoTarget = Body.AddComponent<EcoTarget>();
321-
ecoTarget.SetTargetType(EcoTargetType.Shark);
326+
EcoTarget sharkEcoTarget = Body.AddComponent<EcoTarget>();
327+
sharkEcoTarget.SetTargetType(EcoTargetType.Shark);
328+
329+
EcoTarget playerEcoTarget = Body.AddComponent<EcoTarget>();
330+
playerEcoTarget.SetTargetType(PLAYER_ECO_TARGET_TYPE);
331+
332+
TechTag techTag = Body.AddComponent<TechTag>();
333+
techTag.type = TechType.Player;
322334

323335
RemotePlayerIdentifier identifier = Body.AddComponent<RemotePlayerIdentifier>();
324336
identifier.RemotePlayer = this;
@@ -464,4 +476,13 @@ private void RefreshVitalsVisibility()
464476
vitals.SetStatsVisible(visible);
465477
}
466478
}
479+
480+
/// <summary>
481+
/// Adaptation of <see cref="Player.CanBeAttacked"/> for remote players.
482+
/// NB: This doesn't check for other player's use of 'invisible' command
483+
/// </summary>
484+
public bool CanBeAttacked()
485+
{
486+
return !SubRoot && !EscapePod && PlayerContext.GameMode != NitroxGameMode.CREATIVE;
487+
}
467488
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using NitroxModel.DataStructures;
3+
4+
namespace NitroxModel.Packets;
5+
6+
[Serializable]
7+
public class RangedAttackLastTargetUpdate : Packet
8+
{
9+
public NitroxId CreatureId { get; }
10+
public NitroxId TargetId { get; }
11+
public int AttackTypeIndex { get; }
12+
public ActionState State { get; }
13+
14+
public RangedAttackLastTargetUpdate(NitroxId creatureId, NitroxId targetId, int attackTypeIndex, ActionState state)
15+
{
16+
CreatureId = creatureId;
17+
TargetId = targetId;
18+
AttackTypeIndex = attackTypeIndex;
19+
State = state;
20+
}
21+
22+
public enum ActionState
23+
{
24+
CHARGING,
25+
CASTING
26+
}
27+
}

0 commit comments

Comments
 (0)