Skip to content

Commit

Permalink
Sync Sea Treaders
Browse files Browse the repository at this point in the history
  • Loading branch information
tornac1234 committed Mar 24, 2024
1 parent bad5975 commit c6f169c
Show file tree
Hide file tree
Showing 29 changed files with 493 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using HarmonyLib;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NitroxTest.Patcher;

namespace NitroxPatcher.Patches.Dynamic;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using HarmonyLib;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NitroxTest.Patcher;

namespace NitroxPatcher.Patches.Dynamic;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using HarmonyLib;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NitroxTest.Patcher;

namespace NitroxPatcher.Patches.Dynamic;
Expand Down
16 changes: 16 additions & 0 deletions Nitrox.Test/Patcher/Patches/Dynamic/Poop_Perform_PatchTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using HarmonyLib;
using NitroxTest.Patcher;

namespace NitroxPatcher.Patches.Dynamic;

[TestClass]
public class Poop_Perform_PatchTest
{
[TestMethod]
public void Sanity()
{
IEnumerable<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(Poop_Perform_Patch.TARGET_METHOD);
IEnumerable<CodeInstruction> transformedIl = Poop_Perform_Patch.Transpiler(originalIl);
transformedIl.Count().Should().Be(originalIl.Count() + 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using HarmonyLib;
using NitroxTest.Patcher;

namespace NitroxPatcher.Patches.Dynamic;

[TestClass]
public class SeaTreaderSounds_SpawnChunks_PatchTest
{
[TestMethod]
public void Sanity()
{
IEnumerable<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(SeaTreaderSounds_SpawnChunks_Patch.TARGET_METHOD);
IEnumerable<CodeInstruction> transformedIl = SeaTreaderSounds_SpawnChunks_Patch.Transpiler(originalIl);
transformedIl.Count().Should().Be(originalIl.Count() + 3);
}
}
5 changes: 5 additions & 0 deletions Nitrox.Test/Server/Serialization/WorldPersistenceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,11 @@ private static void EntityTest(Entity entity, Entity entityAfter)
case EatableMetadata metadata when entityAfter.Metadata is EatableMetadata metadataAfter:
Assert.AreEqual(metadata.TimeDecayStart, metadataAfter.TimeDecayStart);
break;
case SeaTreaderMetadata metadata when entityAfter.Metadata is SeaTreaderMetadata metadataAfter:
Assert.AreEqual(metadata.ReverseDirection, metadataAfter.ReverseDirection);
Assert.AreEqual(metadata.GrazingEndTime, metadataAfter.GrazingEndTime);
Assert.AreEqual(metadata.LeashPosition, metadataAfter.LeashPosition);
break;
default:
Assert.Fail($"Runtime type of {nameof(Entity)}.{nameof(Entity.Metadata)} is not equal: {entity.Metadata?.GetType().Name} - {entityAfter.Metadata?.GetType().Name}");
break;
Expand Down
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 CreaturePoopPerformedProcessor : ClientPacketProcessor<CreaturePoopPerformed>
{
public override void Process(CreaturePoopPerformed packet)
{
AI.CreaturePoopPerformed(packet.CreatureId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using NitroxClient.Communication.Packets.Processors.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxModel.Packets;
using UnityEngine;

namespace NitroxClient.Communication.Packets.Processors;

public class SeaTreaderChunkPickedUpProcessor : ClientPacketProcessor<SeaTreaderChunkPickedUp>
{
public override void Process(SeaTreaderChunkPickedUp packet)
{
if (NitroxEntity.TryGetComponentFrom(packet.ChunkId, out SinkingGroundChunk sinkingGroundChunk))
{
GameObject.Destroy(sinkingGroundChunk.gameObject);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using NitroxClient.Communication.Packets.Processors.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxClient.Unity.Helper;
using NitroxModel.Packets;
using NitroxModel_Subnautica.DataStructures;
using UnityEngine;

namespace NitroxClient.Communication.Packets.Processors;

public class SeaTreaderSpawnedChunkProcessor : ClientPacketProcessor<SeaTreaderSpawnedChunk>
{
public override void Process(SeaTreaderSpawnedChunk packet)
{
if (NitroxEntity.TryGetComponentFrom(packet.CreatureId, out SeaTreader seaTreader) &&
seaTreader.TryGetComponentInChildren(out SeaTreaderSounds seaTreaderSounds))
{
GameObject chunkObject = GameObjectHelper.InstantiateWithId(seaTreaderSounds.stepChunkPrefab, packet.ChunkId);
chunkObject.transform.position = packet.Position.ToUnity();
chunkObject.transform.rotation = packet.Rotation.ToUnity();
}
}
}
2 changes: 1 addition & 1 deletion NitroxClient/Debuggers/NetworkDebugger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class NetworkDebugger : BaseDebugger, INetworkDebugger
{
nameof(PlayerMovement), nameof(EntityTransformUpdates), nameof(PlayerStats), nameof(SpawnEntities), nameof(VehicleMovement), nameof(PlayerCinematicControllerCall),
nameof(FMODAssetPacket), nameof(FMODEventInstancePacket), nameof(FMODCustomEmitterPacket), nameof(FMODStudioEmitterPacket), nameof(FMODCustomLoopingEmitterPacket),
nameof(SimulationOwnershipChange), nameof(CellVisibilityChanged)
nameof(SimulationOwnershipChange), nameof(CellVisibilityChanged), nameof(CreatureActionChanged)
};
private readonly List<PacketDebugWrapper> packets = new List<PacketDebugWrapper>(PACKET_STORED_COUNT);

Expand Down
14 changes: 12 additions & 2 deletions NitroxClient/GameLogic/AI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class AI
/// </summary>
private readonly HashSet<Type> creatureActionWhitelist =
[
typeof(AttackLastTarget), typeof(RangedAttackLastTarget), typeof(AttackCyclops)
typeof(AttackLastTarget), typeof(RangedAttackLastTarget), typeof(AttackCyclops), typeof(Poop)
];

/// <summary>
Expand All @@ -32,7 +32,7 @@ public class AI
/// </summary>
private readonly HashSet<Type> syncedCreatureWhitelist =
[
typeof(ReaperLeviathan), typeof(SeaDragon)
typeof(ReaperLeviathan), typeof(SeaDragon), typeof(SeaTreader), typeof(GhostLeviathan)
];

public AI(IPacketSender packetSender)
Expand Down Expand Up @@ -143,6 +143,16 @@ public static void RangedAttackLastTargetUpdate(NitroxId creatureId, NitroxId ta
}
}

public static void CreaturePoopPerformed(NitroxId creatureId)
{
if (NitroxEntity.TryGetComponentFrom(creatureId, out Poop poop))
{
// Code from Poop.Perform
SafeAnimator.SetBool(poop.creature.GetAnimator(), poop.animationParameterName, false);
poop.recourceSpawned = true;
}
}

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
@@ -0,0 +1,18 @@
using NitroxClient.GameLogic.Spawning.Metadata.Extractor.Abstract;
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
using NitroxModel_Subnautica.DataStructures;

namespace NitroxClient.GameLogic.Spawning.Metadata.Extractor;

public class SeaTreaderMetadataExtractor : EntityMetadataExtractor<SeaTreader, SeaTreaderMetadata>
{
public override SeaTreaderMetadata Extract(SeaTreader seaTreader)
{
if (!DayNightCycle.main)
{
return null;
}
float grazingEndTime = DayNightCycle.main.timePassedAsFloat + seaTreader.grazingTimeLeft;
return new(seaTreader.reverseDirection, grazingEndTime, seaTreader.leashPosition.ToDto());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
using NitroxModel_Subnautica.DataStructures;
using UnityEngine;

namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;

public class SeaTreaderMetadataProcessor : EntityMetadataProcessor<SeaTreaderMetadata>
{
public override void ProcessMetadata(GameObject gameObject, SeaTreaderMetadata metadata)
{
if (gameObject.TryGetComponent(out SeaTreader seaTreader))
{
if (!seaTreader.isInitialized)
{
seaTreader.InitializeOnce();
}

seaTreader.reverseDirection = metadata.ReverseDirection;

float grazingTimeLeft = Math.Max(0, metadata.GrazingEndTime - DayNightCycle.main.timePassedAsFloat);

seaTreader.grazing = grazingTimeLeft > 0;
seaTreader.grazingTimeLeft = grazingTimeLeft;

seaTreader.leashPosition = metadata.LeashPosition.ToUnity();
seaTreader.leashPosition.y = gameObject.transform.position.y;
seaTreader.isInitialized = true;
seaTreader.InitializeAgain();
}
else
{
Log.Error($"Could not find {nameof(SeaTreader)} on {gameObject.name}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace NitroxModel.DataStructures.GameLogic.Entities.Metadata
[ProtoInclude(76, typeof(RadiationMetadata))]
[ProtoInclude(77, typeof(CrashHomeMetadata))]
[ProtoInclude(78, typeof(EatableMetadata))]
[ProtoInclude(79, typeof(SeaTreaderMetadata))]
public abstract class EntityMetadata
{
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Runtime.Serialization;
using BinaryPack.Attributes;
using NitroxModel.DataStructures.Unity;

namespace NitroxModel.DataStructures.GameLogic.Entities.Metadata;

[Serializable]
[DataContract]
public class SeaTreaderMetadata : EntityMetadata
{
[DataMember(Order = 1)]
public bool ReverseDirection { get; }

[DataMember(Order = 2)]
public float GrazingEndTime { get; }

[DataMember(Order = 3)]
public NitroxVector3 LeashPosition { get; }

[IgnoreConstructor]
protected SeaTreaderMetadata()
{
// Constructor for serialization. Has to be "protected" for json serialization.
}

public SeaTreaderMetadata(bool reverseDirection, float grazingEndTime, NitroxVector3 leashPosition)
{
ReverseDirection = reverseDirection;
GrazingEndTime = grazingEndTime;
LeashPosition = leashPosition;
}

public override string ToString()
{
return $"[{nameof(SeaTreaderMetadata)} ReverseDirection: {ReverseDirection}, GrazingEndTime: {GrazingEndTime}, LeashPosition: {LeashPosition}]";
}
}
15 changes: 15 additions & 0 deletions NitroxModel/Packets/CreaturePoopPerformed.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using NitroxModel.DataStructures;

namespace NitroxModel.Packets;

[Serializable]
public class CreaturePoopPerformed : Packet
{
public NitroxId CreatureId { get; }

public CreaturePoopPerformed(NitroxId creatureId)
{
CreatureId = creatureId;
}
}
15 changes: 15 additions & 0 deletions NitroxModel/Packets/SeaTreaderChunkPickedUp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using NitroxModel.DataStructures;

namespace NitroxModel.Packets;

[Serializable]
public class SeaTreaderChunkPickedUp : Packet
{
public NitroxId ChunkId { get; }

public SeaTreaderChunkPickedUp(NitroxId chunkId)
{
ChunkId = chunkId;
}
}
22 changes: 22 additions & 0 deletions NitroxModel/Packets/SeaTreaderSpawnedChunk.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using NitroxModel.DataStructures;
using NitroxModel.DataStructures.Unity;

namespace NitroxModel.Packets;

[Serializable]
public class SeaTreaderSpawnedChunk : Packet
{
public NitroxId CreatureId { get; }
public NitroxId ChunkId { get; }
public NitroxVector3 Position { get; }
public NitroxQuaternion Rotation { get; }

public SeaTreaderSpawnedChunk(NitroxId creatureId, NitroxId chunkId, NitroxVector3 position, NitroxQuaternion rotation)
{
CreatureId = creatureId;
ChunkId = chunkId;
Position = position;
Rotation = rotation;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using System.Reflection;
using NitroxClient.Communication.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxModel.DataStructures;
using NitroxModel.Helper;
using NitroxModel.Packets;
using System.Reflection;

namespace NitroxPatcher.Patches.Dynamic;

Expand All @@ -12,12 +13,24 @@ public sealed partial class BreakableResource_BreakIntoResources_Patch : NitroxP

public static void Prefix(BreakableResource __instance)
{
if (!__instance.TryGetNitroxEntity(out NitroxEntity destroyedEntity))
if (!__instance.TryGetNitroxId(out NitroxId destroyedId))
{
Log.Warn($"[{nameof(BreakableResource_BreakIntoResources_Patch)}] Could not find {nameof(NitroxEntity)} for breakable entity {__instance.gameObject.GetFullHierarchyPath()}.");
return;
}
// Send packet to destroy the entity
Resolve<IPacketSender>().Send(new EntityDestroyed(destroyedEntity.Id));

// Case by case handling

// Sea Treaders spawn resource chunks but we don't register them on server-side as they're auto destroyed after 60s
// So we need to broadcast their deletion differently
if (__instance.GetComponent<SinkingGroundChunk>())
{
Resolve<IPacketSender>().Send(new SeaTreaderChunkPickedUp(destroyedId));
}
// Generic case
else
{
Resolve<IPacketSender>().Send(new EntityDestroyed(destroyedId));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static bool Prefix(CreatureAction __instance)
return true;
}

// Perform should never be done on non-executing clients because it usually only calls swim behaviours
// Perform is too specific for each action so it should always be synced case by case (and never run directly on remote players)
return false;
}
}
Loading

0 comments on commit c6f169c

Please sign in to comment.