Skip to content

Commit

Permalink
Merge and adapt recent changes from SubnauticaNitrox#2087 and Subnaut…
Browse files Browse the repository at this point in the history
  • Loading branch information
tornac1234 committed Dec 18, 2023
2 parents 61f2a7c + 4606d19 commit e872a26
Show file tree
Hide file tree
Showing 150 changed files with 2,531 additions and 1,191 deletions.
117 changes: 117 additions & 0 deletions Nitrox.Test/Model/DataStructures/CircularBufferTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace NitroxModel.DataStructures;

[TestClass]
public class CircularBufferTest
{
[TestMethod]
public void ShouldLimitSizeToMaxSize()
{
CircularBuffer<string> buffer = new(1);
buffer.Count.Should().Be(0);
buffer.Add("1");
buffer.Count.Should().Be(1);
buffer.Add("2");
buffer.Count.Should().Be(1);

buffer = new CircularBuffer<string>(5);
buffer.Count.Should().Be(0);
buffer.Add("1");
buffer.Count.Should().Be(1);
buffer.Add("2");
buffer.Count.Should().Be(2);
buffer.Add("3");
buffer.Count.Should().Be(3);
buffer.Add("4");
buffer.Count.Should().Be(4);
buffer.Add("5");
buffer.Count.Should().Be(5);
buffer.Add("6");
buffer.Count.Should().Be(5);
}

[TestMethod]
public void ShouldOverwriteOldestItemInBufferWhenCapped()
{
CircularBuffer<string> buffer = new(3);
buffer.Add("1");
buffer[0].Should().Be("1");
buffer.Add("2");
buffer[1].Should().Be("2");
buffer.Add("3");
buffer[2].Should().Be("3");
buffer.Add("4");
buffer[0].Should().Be("4");
buffer.Add("5");
buffer[1].Should().Be("5");
buffer[2].Should().Be("3");
buffer.Add("6");
buffer[2].Should().Be("6");
buffer.Add("7");
buffer.Should().ContainInOrder("7", "5", "6");
}

[TestMethod]
public void ShouldDiscardAddIfCapacityReached()
{
CircularBuffer<string> buffer = new(0);
buffer.Count.Should().Be(0);
buffer.Add("1");
buffer.Count.Should().Be(0);
}

[TestMethod]
public void ShouldBeEmptyWhenCleared()
{
CircularBuffer<string> buffer = new(10);
buffer.Count.Should().Be(0);
buffer.Add("1");
buffer.Add("1");
buffer.Add("1");
buffer.Count.Should().Be(3);
buffer.Clear();
buffer.Count.Should().Be(0);
}

[TestMethod]
public void ShouldGiveLastChanged()
{
CircularBuffer<int> buffer = new(3);
buffer.LastChangedIndex.Should().Be(-1);
buffer.Add(1);
buffer.LastChangedIndex.Should().Be(0);
buffer.Add(2);
buffer.LastChangedIndex.Should().Be(1);
buffer.Add(3);
buffer.LastChangedIndex.Should().Be(2);
buffer.Add(4);
buffer.LastChangedIndex.Should().Be(0);
buffer.Add(5);
buffer.LastChangedIndex.Should().Be(1);
buffer.Add(6);
buffer.LastChangedIndex.Should().Be(2);
buffer.Add(7);
buffer.LastChangedIndex.Should().Be(0);
buffer.Add(8);
buffer.LastChangedIndex.Should().Be(1);
buffer.Clear();
buffer.LastChangedIndex.Should().Be(-1);
}

[TestMethod]
public void ShouldReverseOrderWithNegativeIndex()
{
CircularBuffer<int> buffer = new(6);
buffer.AddRange(1, 2, 3, 4, 5, 6);
buffer[-1].Should().Be(6);
buffer[-2].Should().Be(5);
buffer[-3].Should().Be(4);
buffer[-4].Should().Be(3);
buffer[-5].Should().Be(2);
buffer[-6].Should().Be(1);
buffer[-7].Should().Be(6);
buffer[-8].Should().Be(5);
}
}
20 changes: 20 additions & 0 deletions Nitrox.Test/Patcher/Patches/Dynamic/Flare_Update_PatchTest.cs
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 Flare_Update_PatchTest
{
[TestMethod]
public void Sanity()
{
IEnumerable<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(Flare_Update_Patch.TARGET_METHOD);
IEnumerable<CodeInstruction> transformedIl = Flare_Update_Patch.Transpiler(originalIl);
transformedIl.Count().Should().Be(originalIl.Count());
}
}
22 changes: 22 additions & 0 deletions Nitrox.Test/Server/Serialization/WorldPersistenceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,13 @@ private static void EntityTest(Entity entity, Entity entityAfter)
case SeamothMetadata metadata when entityAfter.Metadata is SeamothMetadata metadataAfter:
Assert.AreEqual(metadata.LightsOn, metadataAfter.LightsOn);
Assert.AreEqual(metadata.Health, metadataAfter.Health);
Assert.AreEqual(metadata.Name, metadataAfter.Name);
Assert.IsTrue(metadata.Colors.SequenceEqual(metadataAfter.Colors));
break;
case ExosuitMetadata metadata when entityAfter.Metadata is ExosuitMetadata metadataAfter:
Assert.AreEqual(metadata.Health, metadataAfter.Health);
Assert.AreEqual(metadata.Name, metadataAfter.Name);
Assert.IsTrue(metadata.Colors.SequenceEqual(metadataAfter.Colors));
break;
case SubNameInputMetadata metadata when entityAfter.Metadata is SubNameInputMetadata metadataAfter:
Assert.AreEqual(metadata.Name, metadataAfter.Name);
Expand Down Expand Up @@ -305,6 +312,14 @@ private static void EntityTest(Entity entity, Entity entityAfter)
Assert.AreEqual(metadata.TimeNextBreed, metadataAfter.TimeNextBreed);
Assert.AreEqual(metadata.BornInside, metadataAfter.BornInside);
break;
case FlareMetadata metadata when entityAfter.Metadata is FlareMetadata metadataAfter:
Assert.AreEqual(metadata.EnergyLeft, metadataAfter.EnergyLeft);
Assert.AreEqual(metadata.HasBeenThrown, metadataAfter.HasBeenThrown);
Assert.AreEqual(metadata.FlareActivateTime, metadataAfter.FlareActivateTime);
break;
case BeaconMetadata metadata when entityAfter.Metadata is BeaconMetadata metadataAfter:
Assert.AreEqual(metadata.Label, metadataAfter.Label);
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 Expand Up @@ -333,6 +348,13 @@ private static void EntityTest(Entity entity, Entity entityAfter)
break;
case CellRootEntity _ when worldEntityAfter is CellRootEntity _:
break;
case PlacedWorldEntity _ when worldEntityAfter is PlacedWorldEntity _:
break;
case OxygenPipeEntity oxygenPipeEntity when worldEntityAfter is OxygenPipeEntity oxygenPipeEntityAfter:
Assert.AreEqual(oxygenPipeEntity.ParentPipeId, oxygenPipeEntityAfter.ParentPipeId);
Assert.AreEqual(oxygenPipeEntity.RootPipeId, oxygenPipeEntityAfter.RootPipeId);
Assert.AreEqual(oxygenPipeEntity.ParentPosition, oxygenPipeEntityAfter.ParentPosition);
break;
case GlobalRootEntity globalRootEntity when worldEntityAfter is GlobalRootEntity globalRootEntityAfter:
if (globalRootEntity.GetType() != typeof(GlobalRootEntity))
{
Expand Down
33 changes: 19 additions & 14 deletions NitroxClient/ClientAutoFacRegistrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
using NitroxClient.GameLogic.PlayerLogic.PlayerPreferences;
using NitroxClient.GameLogic.Settings;
using NitroxClient.GameLogic.Spawning.Metadata;
using NitroxClient.GameLogic.Spawning.Metadata.Extractor;
using NitroxClient.GameLogic.Spawning.Metadata.Extractor.Abstract;
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
using NitroxClient.Map;
using NitroxModel.Core;
using NitroxModel.Helper;
Expand All @@ -48,12 +49,13 @@ public void RegisterDependencies(ContainerBuilder containerBuilder)
}

RegisterCoreDependencies(containerBuilder);
RegisterMetadataDependencies(containerBuilder);
RegisterPacketProcessors(containerBuilder);
RegisterColorSwapManagers(containerBuilder);
RegisterInitialSyncProcessors(containerBuilder);
}

private static void RegisterCoreDependencies(ContainerBuilder containerBuilder)
private void RegisterCoreDependencies(ContainerBuilder containerBuilder)
{
#if DEBUG
containerBuilder.RegisterAssemblyTypes(currentAssembly)
Expand Down Expand Up @@ -99,18 +101,6 @@ private static void RegisterCoreDependencies(ContainerBuilder containerBuilder)
.As<IMap>()
.InstancePerLifetimeScope();

containerBuilder.RegisterAssemblyTypes(currentAssembly)
.AssignableTo<EntityMetadataExtractor>()
.As<EntityMetadataExtractor>()
.AsSelf()
.SingleInstance();

containerBuilder.RegisterAssemblyTypes(currentAssembly)
.AssignableTo<EntityMetadataProcessor>()
.As<EntityMetadataProcessor>()
.AsSelf()
.SingleInstance();

containerBuilder.RegisterType<PlayerManager>().InstancePerLifetimeScope();
containerBuilder.RegisterType<PlayerModelManager>().InstancePerLifetimeScope();
containerBuilder.RegisterType<PlayerVitalsManager>().InstancePerLifetimeScope();
Expand Down Expand Up @@ -144,6 +134,21 @@ private static void RegisterCoreDependencies(ContainerBuilder containerBuilder)
containerBuilder.RegisterType<TimeManager>().InstancePerLifetimeScope();
}

private void RegisterMetadataDependencies(ContainerBuilder containerBuilder)
{
containerBuilder.RegisterAssemblyTypes(currentAssembly)
.AssignableTo<IEntityMetadataExtractor>()
.As<IEntityMetadataExtractor>()
.AsSelf()
.SingleInstance();
containerBuilder.RegisterAssemblyTypes(currentAssembly)
.AssignableTo<IEntityMetadataProcessor>()
.As<IEntityMetadataProcessor>()
.AsSelf()
.SingleInstance();
containerBuilder.RegisterType<EntityMetadataManager>().InstancePerLifetimeScope();
}

private void RegisterPacketProcessors(ContainerBuilder containerBuilder)
{
containerBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using NitroxClient.GameLogic;
using NitroxClient.GameLogic.Bases;
using NitroxClient.GameLogic.Spawning.Bases;
using NitroxClient.GameLogic.Spawning.Metadata;
using NitroxClient.MonoBehaviours;
using NitroxClient.Unity.Helper;
using NitroxModel.DataStructures;
Expand All @@ -22,10 +23,12 @@ namespace NitroxClient.Communication.Packets.Processors;
public class BuildingResyncProcessor : ClientPacketProcessor<BuildingResync>
{
private readonly Entities entities;
private readonly EntityMetadataManager entityMetadataManager;

public BuildingResyncProcessor(Entities entities)
public BuildingResyncProcessor(Entities entities, EntityMetadataManager entityMetadataManager)
{
this.entities = entities;
this.entityMetadataManager = entityMetadataManager;
}

public override void Process(BuildingResync packet)
Expand Down Expand Up @@ -132,6 +135,7 @@ public IEnumerator OverwriteModule(Constructable constructable, ModuleEntity mod
{
Log.Info($"[Module RESYNC] Overwriting module with id {moduleEntity.Id}");
ModuleEntitySpawner.ApplyModuleData(moduleEntity, constructable.gameObject);
entityMetadataManager.ApplyMetadata(constructable.gameObject, moduleEntity.Metadata);
yield break;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
using NitroxClient.Communication.Packets.Processors.Abstract;
using NitroxClient.Communication.Packets.Processors.Abstract;
using NitroxClient.GameLogic.Spawning.Metadata;
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxModel.DataStructures.Util;
using NitroxModel.Helper;
using NitroxModel.Packets;
using UnityEngine;

namespace NitroxClient.Communication.Packets.Processors
namespace NitroxClient.Communication.Packets.Processors;

public class EntityMetadataUpdateProcessor : ClientPacketProcessor<EntityMetadataUpdate>
{
public class EntityMetadataUpdateProcessor : ClientPacketProcessor<EntityMetadataUpdate>
private readonly EntityMetadataManager entityMetadataManager;

public EntityMetadataUpdateProcessor(EntityMetadataManager entityMetadataManager)
{
this.entityMetadataManager = entityMetadataManager;
}

public override void Process(EntityMetadataUpdate update)
{
public override void Process(EntityMetadataUpdate update)
{
GameObject gameObject = NitroxEntity.RequireObjectFrom(update.Id);
GameObject gameObject = NitroxEntity.RequireObjectFrom(update.Id);

Optional<EntityMetadataProcessor> metadataProcessor = EntityMetadataProcessor.FromMetaData(update.NewValue);
Validate.IsTrue(metadataProcessor.HasValue, $"No processor found for EntityMetadata of type {update.NewValue.GetType()}");
Optional<IEntityMetadataProcessor> metadataProcessor = entityMetadataManager.FromMetaData(update.NewValue);
Validate.IsTrue(metadataProcessor.HasValue, $"No processor found for EntityMetadata of type {update.NewValue.GetType()}");

metadataProcessor.Value.ProcessMetadata(gameObject, update.NewValue);
}
metadataProcessor.Value.ProcessMetadata(gameObject, update.NewValue);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using NitroxClient.Communication.Abstract;
Expand Down Expand Up @@ -38,21 +38,17 @@ public override void Process(InitialPlayerSync packet)

private IEnumerator ProcessInitialSyncPacket(object sender, EventArgs eventArgs)
{
// Some packets should not fire during game session join but only afterwards so that initialized/spawned game objects don't trigger packet sending again.
using (PacketSuppressor<PingRenamed>.Suppress())
bool moreProcessorsToRun;
do
{
bool moreProcessorsToRun;
do
yield return Multiplayer.Main.StartCoroutine(RunPendingProcessors());

moreProcessorsToRun = alreadyRan.Count < processors.Count;
if (moreProcessorsToRun && processorsRanLastCycle == 0)
{
yield return Multiplayer.Main.StartCoroutine(RunPendingProcessors());

moreProcessorsToRun = alreadyRan.Count < processors.Count;
if (moreProcessorsToRun && processorsRanLastCycle == 0)
{
throw new Exception($"Detected circular dependencies in initial packet sync between: {GetRemainingProcessorsText()}");
}
} while (moreProcessorsToRun);
}
throw new Exception($"Detected circular dependencies in initial packet sync between: {GetRemainingProcessorsText()}");
}
} while (moreProcessorsToRun);

WaitScreen.Remove(loadingMultiplayerWaitItem);
Multiplayer.Main.InitialSyncCompleted = true;
Expand Down
Loading

0 comments on commit e872a26

Please sign in to comment.