Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3176c36
Converted SimulationOwnership to file-scoped namespace
tornac1234 Aug 27, 2026
10dc63e
Reworked RemotelyControlled and EntityPositionBroadcaster
tornac1234 Aug 29, 2026
022cc0c
Reworked RemotelyControlled to fix Pipe Surface Floater's movements
tornac1234 Aug 30, 2026
1e81ce5
Set no interpolation on surfaced floater to prevent little vibrations…
tornac1234 Aug 30, 2026
e430eb7
Now check if entity should change position without assuming it on cli…
tornac1234 Sep 2, 2026
dc8a1d7
Properly clean not spawned simulated entities, refactor RemotelyContr…
tornac1234 Sep 7, 2026
e4f66e3
Add a test class for DictionaryExtensions.RemoveWhere, and a comment
tornac1234 Sep 16, 2026
94e6e46
Reworked WorldEntityManager to only serve top entities (unparented), …
tornac1234 Sep 16, 2026
6eea5e9
Reworked and upgraded server-side simulation ownership to be more per…
tornac1234 Sep 16, 2026
9d5ce48
Feat: Preload all prefabs when starting the game
tornac1234 Sep 16, 2026
4f9be12
Fix: crash will now spawn by themselves and their parent home will ha…
tornac1234 Sep 16, 2026
5eaed20
Fix: reefback spawn now profits from prefab preload and handles its c…
tornac1234 Sep 16, 2026
5634192
Fix batch spawn regression and leftover misses
tornac1234 Sep 16, 2026
40a2847
fix: improve placeholder group spawn by using prefab preload
tornac1234 Sep 16, 2026
c0a9ffb
Feat: upgrade Entities.cs to better work with in-spawner children spa…
tornac1234 Sep 16, 2026
75e2065
Fix: try fix remote player race conditions
tornac1234 Sep 16, 2026
64294d9
Fix certain entities dispawning because of wrong LargeWorldEntity reg…
tornac1234 Sep 19, 2026
5711784
Feat: allow simulation of underwater rocks (those with floaters)
tornac1234 Sep 19, 2026
f9471da
Refactoring according to reviews
tornac1234 Sep 19, 2026
f811050
Set PrefabLoadInitialSyncProcessor to be public so it can be accessed…
tornac1234 Sep 21, 2026
3861f6d
Fix entity spawn misplacements issues
tornac1234 Sep 27, 2026
3385e12
Bump cache version because of modifications to prefab cache contents
tornac1234 Sep 27, 2026
e7b82de
Reduced allocations in EntityPositionBroadcaster
Measurity Sep 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Runtime.Serialization;
using BinaryPack.Attributes;
using Nitrox.Model.DataStructures;

namespace Nitrox.Model.Subnautica.DataStructures.GameLogic.Entities.Metadata;

Expand All @@ -10,19 +11,23 @@ public class CrashHomeMetadata : EntityMetadata
[DataMember(Order = 1)]
public float SpawnTime { get; }

[DataMember(Order = 2)]
public Optional<NitroxId> SpawnedCrashId { get; }

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

public CrashHomeMetadata(float spawnTime)
public CrashHomeMetadata(float spawnTime, Optional<NitroxId> spawnedCrashId)
{
SpawnTime = spawnTime;
SpawnedCrashId = spawnedCrashId;
}

public override string ToString()
{
return $"[CrashHomeMetadata SpawnTime: {SpawnTime}]";
return $"[{nameof(CrashHomeMetadata)} SpawnTime: {SpawnTime}, SpawnedCrashId: {SpawnedCrashId}]";
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
using System.Collections.Generic;
using Nitrox.Model.Subnautica.DataStructures.GameLogic;
using Nitrox.Model.Subnautica.DataStructures.GameLogic.Entities;

namespace Nitrox.Server.Subnautica.Models.GameLogic.Entities;
namespace Nitrox.Model.Subnautica.Helper;

internal static class SimulationWhitelist
public static class SimulationWhitelist
{
/// <summary>
/// We don't want to give out simulation to all entities that the server sent out because there is a lot of stationary items and junk (TechType.None).
/// It is easier to maintain a list of items we should simulate than try to blacklist items. This list should not be checked for non-server spawned items
/// as they were probably dropped by the player and are mostly guaranteed to move.
/// </summary>
public static readonly HashSet<NitroxTechType> MovementWhitelist =
private static readonly HashSet<NitroxTechType> movementTechTypeWhitelist =
[
TechType.Shocker.ToDto(),
TechType.Biter.ToDto(),
Expand Down Expand Up @@ -73,12 +74,26 @@ internal static class SimulationWhitelist
TechType.PipeSurfaceFloater.ToDto()
];

private static readonly HashSet<string> movementClassIdWhitelist = [
"f895696c-cdc6-4427-a87f-2b62666ea0cb", // FloatingStone4_Floaters
"9a9cdb4e-f110-412d-b16b-b9ace904b569" // FloatingStone5_Floaters
];

/// <summary>
/// We differentiate the entities which should be simulated because of one of their behaviour (ie for utility)
/// from those are simulated for their movements.
/// </summary>
public static readonly HashSet<NitroxTechType> UtilityWhitelist = new()
private static readonly HashSet<NitroxTechType> utilityWhitelist = [
TechType.CrashHome.ToDto(),
];

public static bool ShouldSimulateEntity(WorldEntity entity)
{
return utilityWhitelist.Contains(entity.TechType) || ShouldSimulateEntityMovement(entity);
}

public static bool ShouldSimulateEntityMovement(WorldEntity entity)
{
TechType.CrashHome.ToDto()
};
return !entity.SpawnedByServer || movementTechTypeWhitelist.Contains(entity.TechType) || movementClassIdWhitelist.Contains(entity.ClassId);
}
}
10 changes: 5 additions & 5 deletions Nitrox.Model.Subnautica/Packets/EntityTransformUpdates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ public EntityTransformUpdates(List<EntityTransformUpdate> updates)

public override string ToString()
{
return $"[EntityTransformUpdates: {String.Join(" ", Updates)} ]";
return $"[{nameof(EntityTransformUpdates)} [{string.Join(" ", Updates)}]]";
}

[Serializable]
public abstract class EntityTransformUpdate
{
public NitroxId Id { get; }
public NitroxVector3 Position { get; }
public NitroxQuaternion Rotation { get; }
public NitroxVector3 Position { get; set; }
public NitroxQuaternion Rotation { get; set; }

public EntityTransformUpdate(NitroxId id, NitroxVector3 position, NitroxQuaternion rotation)
{
Expand All @@ -46,7 +46,7 @@ public RawTransformUpdate(NitroxId id, NitroxVector3 position, NitroxQuaternion

public override string ToString()
{
return $"[RawTransformUpdate Id:{Id} Position:{Position} Rotation:{Rotation}]";
return $"[{nameof(RawTransformUpdate)} Id: {Id}, Position: {Position}, Rotation: {Rotation}]";
}
}

Expand All @@ -66,7 +66,7 @@ public SplineTransformUpdate(NitroxId id, NitroxVector3 position, NitroxQuaterni

public override string ToString()
{
return $"[SplineTransformUpdate Id:{Id} Position:{Position} Rotation:{Rotation} DestinationPosition:{DestinationPosition} DestinationDirection:{DestinationDirection} Velocity:{Velocity} ]";
return $"[{nameof(SplineTransformUpdate)} Id: {Id}, Position: {Position}, Rotation: {Rotation}, DestinationPosition: {DestinationPosition}, DestinationDirection: {DestinationDirection}, Velocity: {Velocity}]";
}
}
}
11 changes: 11 additions & 0 deletions Nitrox.Model.Subnautica/Packets/LastEntityTransformUpdate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using Nitrox.Model.Packets;
using static Nitrox.Model.Subnautica.Packets.EntityTransformUpdates;

namespace Nitrox.Model.Subnautica.Packets;

[Serializable]
public class LastEntityTransformUpdate(EntityTransformUpdate lastUpdate) : Packet
{
public EntityTransformUpdate LastUpdate { get; set; } = lastUpdate;
}
57 changes: 24 additions & 33 deletions Nitrox.Model.Subnautica/Packets/SpawnEntities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,37 @@
using Nitrox.Model.Packets;
using Nitrox.Model.Subnautica.DataStructures.GameLogic;

namespace Nitrox.Model.Subnautica.Packets
namespace Nitrox.Model.Subnautica.Packets;

[Serializable]
public class SpawnEntities : Packet
{
[Serializable]
public class SpawnEntities : Packet
{
public List<Entity> Entities { get; }
public List<SimulatedEntity> Simulations { get; }
public List<Entity> Entities { get; }
public List<SimulatedEntity> SimulatedEntities { get; }

public List<AbsoluteEntityCell> SpawnedCells { get; }
public List<AbsoluteEntityCell> SpawnedCells { get; }

public bool ForceRespawn { get; }
public bool ForceRespawn { get; }

public SpawnEntities(List<Entity> entities, List<AbsoluteEntityCell> spawnedCells, bool forceRespawn = false)
public SpawnEntities(Entity entity, SimulatedEntity? simulatedEntity = null, bool forceRespawn = false)
{
Entities = [entity];
SimulatedEntities = [];
SpawnedCells = [];
if (simulatedEntity != null)
{
Entities = entities;
Simulations = [];
SpawnedCells = spawnedCells;
ForceRespawn = forceRespawn;
SimulatedEntities.Add(simulatedEntity);
}

public SpawnEntities(Entity entity, SimulatedEntity? simulatedEntity = null, bool forceRespawn = false)
{
Entities = [entity];
Simulations = [];
SpawnedCells = [];
if (simulatedEntity != null)
{
Simulations.Add(simulatedEntity);
}

ForceRespawn = forceRespawn;
}
ForceRespawn = forceRespawn;
}

// Constructor for serialization.
public SpawnEntities(List<Entity> entities, List<SimulatedEntity> simulations, List<AbsoluteEntityCell> spawnedCells, bool forceRespawn)
{
Entities = entities;
Simulations = simulations;
SpawnedCells = spawnedCells;
ForceRespawn = forceRespawn;
}
// Constructor for serialization.
public SpawnEntities(List<Entity> entities, List<SimulatedEntity> simulatedEntities, List<AbsoluteEntityCell> spawnedCells, bool forceRespawn)
{
Entities = entities;
SimulatedEntities = simulatedEntities;
SpawnedCells = spawnedCells;
ForceRespawn = forceRespawn;
}
}
48 changes: 48 additions & 0 deletions Nitrox.Model/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,54 @@ public static void RemoveWhere<TKey, TValue, TParameter>(this IDictionary<TKey,
}
}

public static void RemoveWhere<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, Func<KeyValuePair<TKey, TValue>, bool> predicate)
{
int toRemoveIndex = 0;
TKey[] toRemove = ArrayPool<TKey>.Shared.Rent(dictionary.Count);
try
{
foreach (KeyValuePair<TKey, TValue> item in dictionary)
{
if (predicate(item))
{
toRemove[toRemoveIndex++] = item.Key;
}
}
for (int i = 0; i < toRemoveIndex; i++)
{
dictionary.Remove(toRemove[i]);
}
}
finally
{
ArrayPool<TKey>.Shared.Return(toRemove, true);
}
}

public static void RemoveWhere<TParam, TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TParam parameter, Func<TParam, KeyValuePair<TKey, TValue>, bool> predicate)
{
int toRemoveIndex = 0;
TKey[] toRemove = ArrayPool<TKey>.Shared.Rent(dictionary.Count);
try
{
foreach (KeyValuePair<TKey, TValue> item in dictionary)
{
if (predicate(parameter, item))
{
toRemove[toRemoveIndex++] = item.Key;
}
}
for (int i = 0; i < toRemoveIndex; i++)
{
dictionary.Remove(toRemove[i]);
}
}
finally
{
ArrayPool<TKey>.Shared.Return(toRemove, true);
}
}

Comment thread
tornac1234 marked this conversation as resolved.
#if NETFRAMEWORK
public static bool TryAdd<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue value)
{
Expand Down
32 changes: 32 additions & 0 deletions Nitrox.Model/Extensions/SetExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Buffers;
using System.Collections.Generic;

namespace Nitrox.Model.Extensions;

public static class SetExtensions
{
public static void RemoveWhere<TParam, T>(this ISet<T> self, TParam parameter, Func<TParam, T, bool> predicate)
{
int toRemoveIndex = 0;
T[] toRemove = ArrayPool<T>.Shared.Rent(self.Count);
try
{
foreach (T item in self)
{
if (predicate(parameter, item))
{
toRemove[toRemoveIndex++] = item;
}
}
for (int i = 0; i < toRemoveIndex; i++)
{
self.Remove(toRemove[i]);
}
}
finally
{
ArrayPool<T>.Shared.Return(toRemove, true);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#if DEBUG
using System.Collections.Generic;
using System.ComponentModel;
using Nitrox.Model.Core;
using Nitrox.Model.DataStructures.GameLogic;
using Nitrox.Model.DataStructures.Unity;
using Nitrox.Model.Subnautica.DataStructures.GameLogic;
Expand Down Expand Up @@ -36,7 +35,7 @@ public Task Execute(ICommandContext context, [Description("name of the target pl
foreach (AbsoluteEntityCell visibleCell in visibleCells)
{
string simulatedEntities = "";
foreach (WorldEntity worldEntity in entityManager.GetEntities(visibleCell))
foreach (WorldEntity worldEntity in entityManager.EnumerateCellEntities(visibleCell))
{
if (simulationOwnership.TryGetLock(worldEntity.Id, out SimulationOwnershipData.PlayerLock playerLock) &&
playerLock.Player.Id == player.Id)
Expand Down
Loading
Loading