first commit

This commit is contained in:
2025-07-06 00:23:46 +02:00
commit 38f50c8819
1788 changed files with 112878 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NitroxServer.Helper;
namespace Nitrox.Test.Server.Helper;
[TestClass]
public class XORRandomTest
{
[TestMethod]
public void TestMeanGeneration()
{
// arbitrary values under there but we can't compare the generated values with UnityEngine.Random because it's unaccessible
XORRandom.InitSeed("cheescake".GetHashCode());
float mean = 0;
int count = 1000000;
for (int i = 0; i < count; i++)
{
mean += XORRandom.NextFloat();
}
mean /= count;
Assert.IsTrue(Math.Abs(0.5f - mean) < 0.001f, $"Float number generation isn't uniform enough: {mean}");
}
}

View File

@@ -0,0 +1,508 @@
using Nitrox.Test;
using Nitrox.Test.Helper.Faker;
using NitroxModel.Core;
using NitroxModel.DataStructures.GameLogic;
using NitroxModel.DataStructures.GameLogic.Entities;
using NitroxModel.DataStructures.GameLogic.Entities.Bases;
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
using NitroxModel.DataStructures.GameLogic.Entities.Metadata.Bases;
using NitroxServer.GameLogic;
using NitroxServer.GameLogic.Unlockables;
using NitroxServer.Serialization.World;
using NitroxServer_Subnautica;
namespace NitroxServer.Serialization;
[TestClass]
public class WorldPersistenceTest
{
private static readonly string tempSaveFilePath = Path.Combine(Path.GetTempPath(), "NitroxTestTempDir");
private static PersistedWorldData worldData;
public static PersistedWorldData[] WorldsDataAfter { get; private set; }
public static IServerSerializer[] ServerSerializers { get; private set; }
[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
NitroxServiceLocator.InitializeDependencyContainer(new SubnauticaServerAutoFacRegistrar(), new TestAutoFacRegistrar());
NitroxServiceLocator.BeginNewLifetimeScope();
WorldPersistence worldPersistence = NitroxServiceLocator.LocateService<WorldPersistence>();
ServerSerializers = NitroxServiceLocator.LocateService<IServerSerializer[]>();
WorldsDataAfter = new PersistedWorldData[ServerSerializers.Length];
worldData = new NitroxAutoFaker<PersistedWorldData>().Generate();
for (int index = 0; index < ServerSerializers.Length; index++)
{
//Checking saving
worldPersistence.UpdateSerializer(ServerSerializers[index]);
Assert.IsTrue(worldPersistence.Save(worldData, tempSaveFilePath), $"Saving normal world failed while using {ServerSerializers[index]}.");
//Checking loading
WorldsDataAfter[index] = worldPersistence.LoadDataFromPath(tempSaveFilePath);
Assert.IsNotNull(WorldsDataAfter[index], $"Loading saved world failed while using {ServerSerializers[index]}.");
}
}
[DataTestMethod, DynamicWorldDataAfter]
public void WorldDataTest(PersistedWorldData worldDataAfter, string serializerName)
{
Assert.IsTrue(worldData.WorldData.ParsedBatchCells.SequenceEqual(worldDataAfter.WorldData.ParsedBatchCells));
Assert.AreEqual(worldData.WorldData.Seed, worldDataAfter.WorldData.Seed);
PDAStateTest(worldData.WorldData.GameData.PDAState, worldDataAfter.WorldData.GameData.PDAState);
StoryGoalTest(worldData.WorldData.GameData.StoryGoals, worldDataAfter.WorldData.GameData.StoryGoals);
StoryTimingTest(worldData.WorldData.GameData.StoryTiming, worldDataAfter.WorldData.GameData.StoryTiming);
}
private static void PDAStateTest(PDAStateData pdaState, PDAStateData pdaStateAfter)
{
Assert.IsTrue(pdaState.KnownTechTypes.SequenceEqual(pdaStateAfter.KnownTechTypes));
Assert.IsTrue(pdaState.AnalyzedTechTypes.SequenceEqual(pdaStateAfter.AnalyzedTechTypes));
AssertHelper.IsListEqual(pdaState.PdaLog.OrderBy(x => x.Key), pdaStateAfter.PdaLog.OrderBy(x => x.Key), (entry, entryAfter) =>
{
Assert.AreEqual(entry.Key, entryAfter.Key);
Assert.AreEqual(entry.Timestamp, entryAfter.Timestamp);
});
Assert.IsTrue(pdaState.EncyclopediaEntries.SequenceEqual(pdaStateAfter.EncyclopediaEntries));
Assert.IsTrue(pdaState.ScannerFragments.SequenceEqual(pdaStateAfter.ScannerFragments));
AssertHelper.IsListEqual(pdaState.ScannerPartial.OrderBy(x => x.TechType.Name), pdaStateAfter.ScannerPartial.OrderBy(x => x.TechType.Name), (entry, entryAfter) =>
{
Assert.AreEqual(entry.TechType, entryAfter.TechType);
Assert.AreEqual(entry.Unlocked, entryAfter.Unlocked);
});
Assert.IsTrue(pdaState.ScannerComplete.SequenceEqual(pdaStateAfter.ScannerComplete));
}
private static void StoryGoalTest(StoryGoalData storyGoal, StoryGoalData storyGoalAfter)
{
Assert.IsTrue(storyGoal.CompletedGoals.SequenceEqual(storyGoalAfter.CompletedGoals));
Assert.IsTrue(storyGoal.RadioQueue.SequenceEqual(storyGoalAfter.RadioQueue));
AssertHelper.IsListEqual(storyGoal.ScheduledGoals.OrderBy(x => x.GoalKey), storyGoalAfter.ScheduledGoals.OrderBy(x => x.GoalKey), (scheduledGoal, scheduledGoalAfter) =>
{
Assert.AreEqual(scheduledGoal.TimeExecute, scheduledGoalAfter.TimeExecute);
Assert.AreEqual(scheduledGoal.GoalKey, scheduledGoalAfter.GoalKey);
Assert.AreEqual(scheduledGoal.GoalType, scheduledGoalAfter.GoalType);
});
}
private static void StoryTimingTest(StoryTimingData storyTiming, StoryTimingData storyTimingAfter)
{
Assert.AreEqual(storyTiming.ElapsedSeconds, storyTimingAfter.ElapsedSeconds);
Assert.AreEqual(storyTiming.AuroraCountdownTime, storyTimingAfter.AuroraCountdownTime);
Assert.AreEqual(storyTiming.AuroraWarningTime, storyTimingAfter.AuroraWarningTime);
}
[DataTestMethod, DynamicWorldDataAfter]
public void PlayerDataTest(PersistedWorldData worldDataAfter, string serializerName)
{
AssertHelper.IsListEqual(worldData.PlayerData.Players.OrderBy(x => x.Id), worldDataAfter.PlayerData.Players.OrderBy(x => x.Id), (playerData, playerDataAfter) =>
{
Assert.AreEqual(playerData.Name, playerDataAfter.Name);
Assert.IsTrue(playerData.UsedItems.SequenceEqual(playerDataAfter.UsedItems));
Assert.IsTrue(playerData.QuickSlotsBindingIds.SequenceEqual(playerDataAfter.QuickSlotsBindingIds));
AssertHelper.IsDictionaryEqual(playerData.EquippedItems, playerDataAfter.EquippedItems, (keyValuePair, keyValuePairAfter) =>
{
Assert.AreEqual(keyValuePair.Key, keyValuePairAfter.Key);
Assert.AreEqual(keyValuePair.Value, keyValuePairAfter.Value);
});
Assert.AreEqual(playerData.Id, playerDataAfter.Id);
Assert.AreEqual(playerData.SpawnPosition, playerDataAfter.SpawnPosition);
Assert.AreEqual(playerData.SpawnRotation, playerDataAfter.SpawnRotation);
Assert.AreEqual(playerData.CurrentStats.Oxygen, playerDataAfter.CurrentStats.Oxygen);
Assert.AreEqual(playerData.CurrentStats.MaxOxygen, playerDataAfter.CurrentStats.MaxOxygen);
Assert.AreEqual(playerData.CurrentStats.Health, playerDataAfter.CurrentStats.Health);
Assert.AreEqual(playerData.CurrentStats.Food, playerDataAfter.CurrentStats.Food);
Assert.AreEqual(playerData.CurrentStats.Water, playerDataAfter.CurrentStats.Water);
Assert.AreEqual(playerData.CurrentStats.InfectionAmount, playerDataAfter.CurrentStats.InfectionAmount);
Assert.AreEqual(playerData.SubRootId, playerDataAfter.SubRootId);
Assert.AreEqual(playerData.Permissions, playerDataAfter.Permissions);
Assert.AreEqual(playerData.NitroxId, playerDataAfter.NitroxId);
Assert.AreEqual(playerData.IsPermaDeath, playerDataAfter.IsPermaDeath);
Assert.IsTrue(playerData.PersonalCompletedGoalsWithTimestamp.SequenceEqual(playerDataAfter.PersonalCompletedGoalsWithTimestamp));
AssertHelper.IsDictionaryEqual(playerData.PlayerPreferences.PingPreferences, playerDataAfter.PlayerPreferences.PingPreferences, (keyValuePair, keyValuePairAfter) =>
{
Assert.AreEqual(keyValuePair.Key, keyValuePairAfter.Key);
Assert.AreEqual(keyValuePair.Value.Color, keyValuePairAfter.Value.Color);
Assert.AreEqual(keyValuePair.Value.Visible, keyValuePairAfter.Value.Visible);
});
Assert.IsTrue(playerData.PlayerPreferences.PinnedTechTypes.SequenceEqual(playerDataAfter.PlayerPreferences.PinnedTechTypes));
});
}
[DataTestMethod, DynamicWorldDataAfter]
public void EntityDataTest(PersistedWorldData worldDataAfter, string serializerName)
{
AssertHelper.IsListEqual(worldData.EntityData.Entities.OrderBy(x => x.Id), worldDataAfter.EntityData.Entities.OrderBy(x => x.Id), EntityTest);
}
[DataTestMethod, DynamicWorldDataAfter]
public void GlobalRootDataTest(PersistedWorldData worldDataAfter, string serializerName)
{
AssertHelper.IsListEqual(worldData.GlobalRootData.Entities.OrderBy(x => x.Id), worldDataAfter.GlobalRootData.Entities.OrderBy(x => x.Id), EntityTest);
}
private static void EntityTest(Entity entity, Entity entityAfter)
{
Assert.AreEqual(entity.Id, entityAfter.Id);
Assert.AreEqual(entity.TechType, entityAfter.TechType);
Assert.AreEqual(entity.ParentId, entityAfter.ParentId);
switch (entity.Metadata)
{
case KeypadMetadata metadata when entityAfter.Metadata is KeypadMetadata metadataAfter:
Assert.AreEqual(metadata.Unlocked, metadataAfter.Unlocked);
break;
case SealedDoorMetadata metadata when entityAfter.Metadata is SealedDoorMetadata metadataAfter:
Assert.AreEqual(metadata.Sealed, metadataAfter.Sealed);
Assert.AreEqual(metadata.OpenedAmount, metadataAfter.OpenedAmount);
break;
case PrecursorDoorwayMetadata metadata when entityAfter.Metadata is PrecursorDoorwayMetadata metadataAfter:
Assert.AreEqual(metadata.IsOpen, metadataAfter.IsOpen);
break;
case PrecursorTeleporterMetadata metadata when entityAfter.Metadata is PrecursorTeleporterMetadata metadataAfter:
Assert.AreEqual(metadata.IsOpen, metadataAfter.IsOpen);
break;
case PrecursorKeyTerminalMetadata metadata when entityAfter.Metadata is PrecursorKeyTerminalMetadata metadataAfter:
Assert.AreEqual(metadata.Slotted, metadataAfter.Slotted);
break;
case PrecursorTeleporterActivationTerminalMetadata metadata when entityAfter.Metadata is PrecursorTeleporterActivationTerminalMetadata metadataAfter:
Assert.AreEqual(metadata.Unlocked, metadataAfter.Unlocked);
break;
case StarshipDoorMetadata metadata when entityAfter.Metadata is StarshipDoorMetadata metadataAfter:
Assert.AreEqual(metadata.DoorLocked, metadataAfter.DoorLocked);
Assert.AreEqual(metadata.DoorOpen, metadataAfter.DoorOpen);
break;
case WeldableWallPanelGenericMetadata metadata when entityAfter.Metadata is WeldableWallPanelGenericMetadata metadataAfter:
Assert.AreEqual(metadata.LiveMixInHealth, metadataAfter.LiveMixInHealth);
break;
case IncubatorMetadata metadata when entityAfter.Metadata is IncubatorMetadata metadataAfter:
Assert.AreEqual(metadata.Powered, metadataAfter.Powered);
Assert.AreEqual(metadata.Hatched, metadataAfter.Hatched);
break;
case EntitySignMetadata metadata when entityAfter.Metadata is EntitySignMetadata metadataAfter:
Assert.AreEqual(metadata.Text, metadataAfter.Text);
Assert.AreEqual(metadata.ColorIndex, metadataAfter.ColorIndex);
Assert.AreEqual(metadata.ScaleIndex, metadataAfter.ScaleIndex);
Assert.IsTrue(metadata.Elements.SequenceEqual(metadataAfter.Elements));
Assert.AreEqual(metadata.Background, metadataAfter.Background);
break;
case ConstructorMetadata metadata when entityAfter.Metadata is ConstructorMetadata metadataAfter:
Assert.AreEqual(metadata.Deployed, metadataAfter.Deployed);
break;
case FlashlightMetadata metadata when entityAfter.Metadata is FlashlightMetadata metadataAfter:
Assert.AreEqual(metadata.On, metadataAfter.On);
break;
case BatteryMetadata metadata when entityAfter.Metadata is BatteryMetadata metadataAfter:
Assert.AreEqual(metadata.Charge, metadataAfter.Charge);
break;
case EscapePodMetadata metadata when entityAfter.Metadata is EscapePodMetadata metadataAfter:
Assert.AreEqual(metadata.PodRepaired, metadataAfter.PodRepaired);
Assert.AreEqual(metadata.RadioRepaired, metadataAfter.RadioRepaired);
break;
case CrafterMetadata metadata when entityAfter.Metadata is CrafterMetadata metadataAfter:
Assert.AreEqual(metadata.TechType, metadataAfter.TechType);
Assert.AreEqual(metadata.StartTime, metadataAfter.StartTime);
Assert.AreEqual(metadata.Duration, metadataAfter.Duration);
break;
case PlantableMetadata metadata when entityAfter.Metadata is PlantableMetadata metadataAfter:
Assert.AreEqual(metadata.TimeStartGrowth, metadataAfter.TimeStartGrowth);
Assert.AreEqual(metadata.SlotID, metadataAfter.SlotID);
// FruitPlantMetadata field is not checked before it's only temporary
break;
case FruitPlantMetadata metadata when entityAfter.Metadata is FruitPlantMetadata metadataAfter:
Assert.IsTrue(metadata.PickedStates.SequenceEqual(metadataAfter.PickedStates));
Assert.AreEqual(metadata.TimeNextFruit, metadataAfter.TimeNextFruit);
break;
case CyclopsMetadata metadata when entityAfter.Metadata is CyclopsMetadata metadataAfter:
Assert.AreEqual(metadata.SilentRunningOn, metadataAfter.SilentRunningOn);
Assert.AreEqual(metadata.ShieldOn, metadataAfter.ShieldOn);
Assert.AreEqual(metadata.SonarOn, metadataAfter.SonarOn);
Assert.AreEqual(metadata.EngineOn, metadataAfter.EngineOn);
Assert.AreEqual(metadata.EngineMode, metadataAfter.EngineMode);
Assert.AreEqual(metadata.Health, metadataAfter.Health);
break;
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);
Assert.IsTrue(metadata.Colors.SequenceEqual(metadataAfter.Colors));
break;
case RocketMetadata metadata when entityAfter.Metadata is RocketMetadata metadataAfter:
Assert.AreEqual(metadata.CurrentStage, metadataAfter.CurrentStage);
Assert.AreEqual(metadata.LastStageTransitionTime, metadataAfter.LastStageTransitionTime);
Assert.AreEqual(metadata.ElevatorState, metadataAfter.ElevatorState);
Assert.AreEqual(metadata.ElevatorPosition, metadataAfter.ElevatorPosition);
Assert.IsTrue(metadata.PreflightChecks.SequenceEqual(metadataAfter.PreflightChecks));
break;
case CyclopsLightingMetadata metadata when entityAfter.Metadata is CyclopsLightingMetadata metadataAfter:
Assert.AreEqual(metadata.FloodLightsOn, metadataAfter.FloodLightsOn);
Assert.AreEqual(metadata.InternalLightsOn, metadataAfter.InternalLightsOn);
break;
case FireExtinguisherHolderMetadata metadata when entityAfter.Metadata is FireExtinguisherHolderMetadata metadataAfter:
Assert.AreEqual(metadata.HasExtinguisher, metadataAfter.HasExtinguisher);
Assert.AreEqual(metadata.Fuel, metadataAfter.Fuel);
break;
case PlayerMetadata metadata when entityAfter.Metadata is PlayerMetadata metadataAfter:
AssertHelper.IsListEqual(metadata.EquippedItems.OrderBy(x => x.Id), metadataAfter.EquippedItems.OrderBy(x => x.Id), (equippedItem, equippedItemAfter) =>
{
Assert.AreEqual(equippedItem.Id, equippedItemAfter.Id);
Assert.AreEqual(equippedItem.Slot, equippedItemAfter.Slot);
Assert.AreEqual(equippedItem.TechType, equippedItemAfter.TechType);
});
break;
case GhostMetadata ghostMetadata when entityAfter.Metadata is GhostMetadata ghostMetadataAfter:
Assert.AreEqual(ghostMetadata.TargetOffset, ghostMetadataAfter.TargetOffset);
if (ghostMetadata.GetType() != ghostMetadataAfter.GetType())
{
Assert.Fail($"Runtime type of {nameof(GhostMetadata)} in {nameof(Entity)}.{nameof(Entity.Metadata)} is not equal: {ghostMetadata.GetType().Name} - {ghostMetadataAfter.GetType().Name}");
}
switch (ghostMetadata)
{
case BaseAnchoredCellGhostMetadata metadata when ghostMetadataAfter is BaseAnchoredCellGhostMetadata metadataAfter:
Assert.AreEqual(metadata.AnchoredCell, metadataAfter.AnchoredCell);
break;
case BaseAnchoredFaceGhostMetadata metadata when ghostMetadataAfter is BaseAnchoredFaceGhostMetadata metadataAfter:
Assert.AreEqual(metadata.AnchoredFace, metadataAfter.AnchoredFace);
break;
case BaseDeconstructableGhostMetadata metadata when ghostMetadataAfter is BaseDeconstructableGhostMetadata metadataAfter:
Assert.AreEqual(metadata.ModuleFace, metadataAfter.ModuleFace);
Assert.AreEqual(metadata.ClassId, metadataAfter.ClassId);
break;
}
break;
case WaterParkCreatureMetadata metadata when entityAfter.Metadata is WaterParkCreatureMetadata metadataAfter:
Assert.AreEqual(metadata.Age, metadataAfter.Age);
Assert.AreEqual(metadata.MatureTime, metadataAfter.MatureTime);
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;
case RadiationMetadata metadata when entityAfter.Metadata is RadiationMetadata metadataAfter:
Assert.AreEqual(metadata.Health, metadataAfter.Health);
Assert.AreEqual(metadata.FixRealTime, metadataAfter.FixRealTime);
break;
case CrashHomeMetadata metadata when entityAfter.Metadata is CrashHomeMetadata metadataAfter:
Assert.AreEqual(metadata.SpawnTime, metadataAfter.SpawnTime);
break;
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;
case StayAtLeashPositionMetadata metadata when entityAfter.Metadata is StayAtLeashPositionMetadata metadataAfter:
Assert.AreEqual(metadata.LeashPosition, metadataAfter.LeashPosition);
break;
case EggMetadata metadata when entityAfter.Metadata is EggMetadata metadataAfter:
Assert.AreEqual(metadata.TimeStartHatching, metadataAfter.TimeStartHatching);
Assert.AreEqual(metadata.Progress, metadataAfter.Progress);
break;
default:
Assert.Fail($"Runtime type of {nameof(Entity)}.{nameof(Entity.Metadata)} is not equal: {entity.Metadata?.GetType().Name} - {entityAfter.Metadata?.GetType().Name}");
break;
}
switch (entity)
{
case WorldEntity worldEntity when entityAfter is WorldEntity worldEntityAfter:
Assert.AreEqual(worldEntity.Transform.LocalPosition, worldEntityAfter.Transform.LocalPosition);
Assert.AreEqual(worldEntity.Transform.LocalRotation, worldEntityAfter.Transform.LocalRotation);
Assert.AreEqual(worldEntity.Transform.LocalScale, worldEntityAfter.Transform.LocalScale);
Assert.AreEqual(worldEntity.Level, worldEntityAfter.Level);
Assert.AreEqual(worldEntity.ClassId, worldEntityAfter.ClassId);
Assert.AreEqual(worldEntity.SpawnedByServer, worldEntityAfter.SpawnedByServer);
if (worldEntity.GetType() != worldEntityAfter.GetType())
{
Assert.Fail($"Runtime type of {nameof(WorldEntity)} is not equal: {worldEntity.GetType().Name} - {worldEntityAfter.GetType().Name}");
}
else if (worldEntity.GetType() != typeof(WorldEntity))
{
switch (worldEntity)
{
case PlaceholderGroupWorldEntity placeholderGroupWorldEntity when worldEntityAfter is PlaceholderGroupWorldEntity placeholderGroupWorldEntityAfter:
Assert.AreEqual(placeholderGroupWorldEntity.ComponentIndex, placeholderGroupWorldEntityAfter.ComponentIndex);
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 PrefabPlaceholderEntity prefabPlaceholderEntity when entityAfter is PrefabPlaceholderEntity prefabPlaceholderEntityAfter:
Assert.AreEqual(prefabPlaceholderEntity.ComponentIndex, prefabPlaceholderEntityAfter.ComponentIndex);
break;
case SerializedWorldEntity serializedWorldEntity when entityAfter is SerializedWorldEntity serializedWorldEntityAfter:
Assert.AreEqual(serializedWorldEntity.AbsoluteEntityCell, serializedWorldEntityAfter.AbsoluteEntityCell);
AssertHelper.IsListEqual(serializedWorldEntity.Components.OrderBy(c => c.GetHashCode()), serializedWorldEntityAfter.Components.OrderBy(c => c.GetHashCode()), (c1, c2) => c1.Equals(c2));
Assert.AreEqual(serializedWorldEntity.Layer, serializedWorldEntityAfter.Layer);
Assert.AreEqual(serializedWorldEntity.BatchId, serializedWorldEntityAfter.BatchId);
Assert.AreEqual(serializedWorldEntity.CellId, serializedWorldEntityAfter.CellId);
break;
case GeyserWorldEntity geyserEntity when entityAfter is GeyserWorldEntity geyserEntityAfter:
Assert.AreEqual(geyserEntity.RandomIntervalVarianceMultiplier, geyserEntityAfter.RandomIntervalVarianceMultiplier);
Assert.AreEqual(geyserEntity.StartEruptTime, geyserEntityAfter.StartEruptTime);
break;
case ReefbackEntity reefbackEntity when entityAfter is ReefbackEntity reefbackEntityAfter:
Assert.AreEqual(reefbackEntity.GrassIndex, reefbackEntityAfter.GrassIndex);
Assert.AreEqual(reefbackEntity.OriginalPosition, reefbackEntityAfter.OriginalPosition);
break;
case ReefbackChildEntity reefbackChildEntity when entityAfter is ReefbackChildEntity reefbackChildEntityAfter:
Assert.AreEqual(reefbackChildEntity.Type, reefbackChildEntityAfter.Type);
break;
case CreatureRespawnEntity creatureRespawnEntity when entityAfter is CreatureRespawnEntity creatureRespawnEntityAfter:
Assert.AreEqual(creatureRespawnEntity.SpawnTime, creatureRespawnEntityAfter.SpawnTime);
Assert.AreEqual(creatureRespawnEntity.RespawnTechType, creatureRespawnEntityAfter.RespawnTechType);
Assert.IsTrue(creatureRespawnEntity.AddComponents.SequenceEqual(creatureRespawnEntityAfter.AddComponents));
break;
case GlobalRootEntity globalRootEntity when worldEntityAfter is GlobalRootEntity globalRootEntityAfter:
if (globalRootEntity.GetType() != typeof(GlobalRootEntity))
{
switch (globalRootEntity)
{
case BuildEntity buildEntity when globalRootEntityAfter is BuildEntity buildEntityAfter:
Assert.AreEqual(buildEntity.BaseData, buildEntityAfter.BaseData);
break;
case EscapePodWorldEntity escapePodWorldEntity when globalRootEntityAfter is EscapePodWorldEntity escapePodWorldEntityAfter:
Assert.IsTrue(escapePodWorldEntity.Players.SequenceEqual(escapePodWorldEntityAfter.Players));
break;
case InteriorPieceEntity interiorPieceEntity when globalRootEntityAfter is InteriorPieceEntity interiorPieceEntityAfter:
Assert.AreEqual(interiorPieceEntity.BaseFace, interiorPieceEntityAfter.BaseFace);
break;
case MapRoomEntity mapRoomEntity when globalRootEntityAfter is MapRoomEntity mapRoomEntityAfter:
Assert.AreEqual(mapRoomEntity.Cell, mapRoomEntityAfter.Cell);
break;
case ModuleEntity moduleEntity when globalRootEntityAfter is ModuleEntity moduleEntityAfter:
Assert.AreEqual(moduleEntity.ConstructedAmount, moduleEntityAfter.ConstructedAmount);
Assert.AreEqual(moduleEntity.IsInside, moduleEntityAfter.IsInside);
if (moduleEntity.GetType() != moduleEntityAfter.GetType())
{
Assert.Fail($"Runtime type of {nameof(ModuleEntity)} is not equal: {moduleEntity.GetType().Name} - {moduleEntityAfter.GetType().Name}");
}
switch (moduleEntity)
{
case GhostEntity ghostEntity when moduleEntityAfter is GhostEntity ghostEntityAfter:
Assert.AreEqual(ghostEntity.BaseFace, ghostEntityAfter.BaseFace);
Assert.AreEqual(ghostEntity.BaseData, ghostEntityAfter.BaseData);
break;
}
break;
case MoonpoolEntity moonpoolEntity when globalRootEntityAfter is MoonpoolEntity moonpoolEntityAfter:
Assert.AreEqual(moonpoolEntity.Cell, moonpoolEntityAfter.Cell);
break;
case PlanterEntity when globalRootEntityAfter is PlanterEntity:
break;
case PlayerWorldEntity when globalRootEntityAfter is PlayerWorldEntity:
break;
case VehicleWorldEntity vehicleWorldEntity when globalRootEntityAfter is VehicleWorldEntity vehicleWorldEntityAfter:
Assert.AreEqual(vehicleWorldEntity.SpawnerId, vehicleWorldEntityAfter.SpawnerId);
Assert.AreEqual(vehicleWorldEntity.ConstructionTime, vehicleWorldEntityAfter.ConstructionTime);
break;
case RadiationLeakEntity radiationLeakEntity when globalRootEntityAfter is RadiationLeakEntity radiationLeakEntityAfter:
Assert.AreEqual(radiationLeakEntity.ObjectIndex, radiationLeakEntityAfter.ObjectIndex);
break;
default:
Assert.Fail($"Runtime type of {nameof(GlobalRootEntity)} is not equal even after the check: {worldEntity.GetType().Name} - {globalRootEntityAfter.GetType().Name}");
break;
}
}
break;
default:
Assert.Fail($"Runtime type of {nameof(WorldEntity)} is not equal even after the check: {worldEntity.GetType().Name} - {worldEntityAfter.GetType().Name}");
break;
}
}
break;
case PrefabChildEntity prefabChildEntity when entityAfter is PrefabChildEntity prefabChildEntityAfter:
Assert.AreEqual(prefabChildEntity.ComponentIndex, prefabChildEntityAfter.ComponentIndex);
Assert.AreEqual(prefabChildEntity.ClassId, prefabChildEntityAfter.ClassId);
break;
case InventoryEntity inventoryEntity when entityAfter is InventoryEntity inventoryEntityAfter:
Assert.AreEqual(inventoryEntity.ComponentIndex, inventoryEntityAfter.ComponentIndex);
break;
case InventoryItemEntity inventoryItemEntity when entityAfter is InventoryItemEntity inventoryItemEntityAfter:
Assert.AreEqual(inventoryItemEntity.ClassId, inventoryItemEntityAfter.ClassId);
break;
case PathBasedChildEntity pathBasedChildEntity when entityAfter is PathBasedChildEntity pathBasedChildEntityAfter:
Assert.AreEqual(pathBasedChildEntity.Path, pathBasedChildEntityAfter.Path);
break;
case InstalledBatteryEntity when entityAfter is InstalledBatteryEntity:
break;
case InstalledModuleEntity installedModuleEntity when entityAfter is InstalledModuleEntity installedModuleEntityAfter:
Assert.AreEqual(installedModuleEntity.Slot, installedModuleEntityAfter.Slot);
Assert.AreEqual(installedModuleEntity.ClassId, installedModuleEntityAfter.ClassId);
break;
case BaseLeakEntity baseLeakEntity when entityAfter is BaseLeakEntity baseLeakEntityAfter:
Assert.AreEqual(baseLeakEntity.Health, baseLeakEntityAfter.Health);
Assert.AreEqual(baseLeakEntity.RelativeCell, baseLeakEntityAfter.RelativeCell);
break;
default:
Assert.Fail($"Runtime type of {nameof(Entity)} is not equal: {entity.GetType().Name} - {entityAfter.GetType().Name}");
break;
}
AssertHelper.IsListEqual(entity.ChildEntities.OrderBy(x => x.Id), entityAfter.ChildEntities.OrderBy(x => x.Id), EntityTest);
}
[ClassCleanup]
public static void ClassCleanup()
{
NitroxServiceLocator.EndCurrentLifetimeScope();
if (Directory.Exists(tempSaveFilePath))
{
Directory.Delete(tempSaveFilePath, true);
}
}
}
[AttributeUsage(AttributeTargets.Method)]
public class DynamicWorldDataAfterAttribute : Attribute, ITestDataSource
{
public IEnumerable<object[]> GetData(MethodInfo methodInfo)
{
return WorldPersistenceTest.WorldsDataAfter.Select((t, i) => new object[] { t, WorldPersistenceTest.ServerSerializers[i].GetType().Name });
}
public string GetDisplayName(MethodInfo methodInfo, object[] data)
{
return data != null ? $"{methodInfo.Name} ({data[1]})" : $"{methodInfo.Name} (no-data)";
}
}