Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Join queue despaghettification #2006

Open
wants to merge 55 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
b4e462a
Draft 1
SpaceMonkeyy86 Dec 6, 2022
2521bac
Finished join queue loop
SpaceMonkeyy86 Dec 8, 2022
d6404e6
Enter join queue after base game finishes loading
SpaceMonkeyy86 Dec 8, 2022
02ee6c6
Changed OnLateUpdate to UpdatePings (#1913)
Coding-Hen Dec 10, 2022
e43c176
Merge master
SpaceMonkeyy86 Jan 10, 2023
f161aac
Merge master (again)
SpaceMonkeyy86 Mar 18, 2023
4cb25d9
Move initial sync code to the new spot after the merge reset it
SpaceMonkeyy86 Mar 18, 2023
eddd834
Fix broken in-game log for join queue stage
SpaceMonkeyy86 Mar 18, 2023
5dc17a9
Use WaitScreen to stay on loading screen
SpaceMonkeyy86 Mar 18, 2023
1717850
Reduce default initial sync timeout
SpaceMonkeyy86 Mar 18, 2023
ef14264
Merge branch 'master' into join-queue-fix
SpaceMonkeyy86 Mar 22, 2023
86010a6
Remove unnecessary using
SpaceMonkeyy86 Apr 15, 2023
d613ec9
Merge master (this is so not going to work)
SpaceMonkeyy86 Jan 2, 2024
17e9c09
It almost worked (it works now)
SpaceMonkeyy86 Jan 2, 2024
5c9ffef
Show modal when timed out
SpaceMonkeyy86 Feb 7, 2024
5fd6aa5
Merge master
SpaceMonkeyy86 Feb 7, 2024
932edb9
Tweaks and fixes
SpaceMonkeyy86 Feb 8, 2024
708c8cf
Instantly continue the queue if a client disconnects while syncing
SpaceMonkeyy86 Feb 9, 2024
2eb654a
Send info about the queue to the client
SpaceMonkeyy86 Feb 9, 2024
1b5920f
Remove join queue "lobby"
SpaceMonkeyy86 Feb 12, 2024
708f753
Some cleanups
SpaceMonkeyy86 Feb 12, 2024
5d618c7
Merge branch 'master' into join-queue-fix
SpaceMonkeyy86 Feb 12, 2024
34b2c18
Revert a file that wasn't actually modified
SpaceMonkeyy86 Feb 12, 2024
906d1c6
I love merge conflicts
SpaceMonkeyy86 Mar 20, 2024
131bac7
Merge branch 'master' into join-queue-fix
SpaceMonkeyy86 Aug 14, 2024
eb1ce78
Fix another conflict (did not test but it's probably fine)
SpaceMonkeyy86 Sep 2, 2024
099f8f2
Fix merge conflicts
SpaceMonkeyy86 Nov 12, 2024
201d221
Merge branch 'join-queue-fix' of https://github.com/TwinBuilderOne/Ni…
SpaceMonkeyy86 Nov 12, 2024
a8f742f
Merge branch 'master' into join-queue-fix
SpaceMonkeyy86 Nov 16, 2024
76e5a9d
Merge branch 'master' into join-queue-fix
SpaceMonkeyy86 Jan 7, 2025
efba962
Apply Jannify's patch
SpaceMonkeyy86 Jan 7, 2025
ef9d8d5
Small tweaks
SpaceMonkeyy86 Jan 7, 2025
a1cf75b
Fix DI for JoiningManager
SpaceMonkeyy86 Jan 7, 2025
4de4fa7
Handle case where client receives a timeout after finishing the sync
SpaceMonkeyy86 Jan 7, 2025
8043c13
Remove thread unsafety when a joining player disconnects
SpaceMonkeyy86 Jan 12, 2025
95fc884
Some cleanup
SpaceMonkeyy86 Jan 12, 2025
5cc1f6e
Merge branch 'master' into join-queue-fix
SpaceMonkeyy86 Jan 26, 2025
1a771f9
Display in-game log correctly when time is paused
SpaceMonkeyy86 Feb 9, 2025
2733ba7
Add sanity check support for multi-transpilers
SpaceMonkeyy86 Feb 9, 2025
29f5305
Improve join queue messages shown to player
SpaceMonkeyy86 Feb 9, 2025
f4ad666
Notify timeout using modal instead of logs
SpaceMonkeyy86 Feb 9, 2025
c310ff8
Only run queue task when there are players in the queue
SpaceMonkeyy86 Feb 9, 2025
ad18170
Use if-else
SpaceMonkeyy86 Feb 9, 2025
b1f170e
Fix race conditions with locks
SpaceMonkeyy86 Feb 10, 2025
9ff4d18
Minor cleanup
SpaceMonkeyy86 Feb 10, 2025
6b759ec
Remove seemingly redundant check when handling packets
SpaceMonkeyy86 Feb 10, 2025
7f4fc41
Remove unnecessary DI dependency
SpaceMonkeyy86 Feb 10, 2025
228f5dc
Remove out-of-place comma on main menu of launcher (I don't want to c…
SpaceMonkeyy86 Feb 10, 2025
c4f9888
Merge branch 'master' into join-queue-fix
SpaceMonkeyy86 Feb 10, 2025
37d1831
Use a single integer for IL difference in transpiler sanity check
SpaceMonkeyy86 Feb 13, 2025
663ac27
Remove manual translation (will be automatically merged later)
SpaceMonkeyy86 Feb 13, 2025
220e1a6
Suggested changes inside JoiningManager
SpaceMonkeyy86 Feb 13, 2025
bee00b1
Use CodeMatcher::Repeat in transpiler
SpaceMonkeyy86 Feb 13, 2025
7ec398a
Move comment to the correct line
SpaceMonkeyy86 Feb 13, 2025
004cce4
Remove partial keyword
SpaceMonkeyy86 Feb 14, 2025
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
1 change: 1 addition & 0 deletions Nitrox.Assets.Subnautica/LanguageFiles/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"Nitrox_PlayerKicked": "You've been kicked from the server",
"Nitrox_PlayerLeft": "{PLAYER} left the game.",
"Nitrox_PlayerListTabName": "Player List",
"Nitrox_QueueInfo": "You are at position #{POSITION} in the join queue. Maximum possible wait: {TIME}",
"Nitrox_RejectedSessionPolicy": "Reservation rejected…",
"Nitrox_RemotePlayerObstacle": "Another player's either inside or too close to the deconstructable target.",
"Nitrox_RequestingSessionPolicy": "Requesting session policy info…",
Expand Down
2 changes: 1 addition & 1 deletion Nitrox.Launcher/Views/LaunchGameView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
Grid.Column="0"
Margin="0,0,20,0"
FontSize="14"
Text="Start your Subnautica adventure in multiplayer mode together with your friends, powered by the Nitrox mod: An open-source, modification for the game Subnautica. The project is maintained by the community with regular support and updates from its contributors." />
Text="Start your Subnautica adventure in multiplayer mode together with your friends, powered by the Nitrox mod: An open-source modification for the game Subnautica. The project is maintained by the community with regular support and updates from its contributors." />
<!-- Play buttons - Negative offset to add some overlap with the background image -->
<StackPanel Grid.Column="1" Margin="0,-110,0,0">
<Border ClipToBounds="True" CornerRadius="10">
Expand Down
46 changes: 35 additions & 11 deletions Nitrox.Test/Patcher/Patches/PatchesTranspilerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class PatchesTranspilerTest
[typeof(EntityCell_AwakeAsync_Patch), 2],
[typeof(EntityCell_SleepAsync_Patch), 2],
[typeof(Equipment_RemoveItem_Patch), 7],
[typeof(ErrorMessage_OnLateUpdate_Patch), new[] {0, 0}],
[typeof(EscapePod_Start_Patch), 43],
[typeof(FireExtinguisherHolder_TakeTankAsync_Patch), 2],
[typeof(FireExtinguisherHolder_TryStoreTank_Patch), 3],
Expand Down Expand Up @@ -103,23 +104,46 @@ public void AllTranspilerPatchesHaveSanityTest()

[TestMethod]
[DynamicData(nameof(TranspilerPatchClasses))]
public void AllPatchesTranspilerSanity(Type patchClassType, int ilDifference, bool logInstructions = false)
public void AllPatchesTranspilerSanity(Type patchClassType, object ilDifference, bool logInstructions = false)
{
MethodInfo transpilerMethod = patchClassType.GetMethod("Transpiler");
if (transpilerMethod == null)
{
Assert.Fail($"Could not find a \"Transpiler\" method inside {patchClassType.Name}");
}

FieldInfo targetMethodInfo = patchClassType.GetRuntimeFields().FirstOrDefault(x => string.Equals(x.Name.Replace("_", ""), "targetMethod", StringComparison.OrdinalIgnoreCase));
if (targetMethodInfo == null)
if (targetMethodInfo != null)
{
Assert.Fail($"Could not find either \"TARGET_METHOD\" nor \"targetMethod\" inside {patchClassType.Name}");
MethodInfo targetMethod = targetMethodInfo.GetValue(null) as MethodInfo;
TestTranspilerMethod(patchClassType, targetMethod, transpilerMethod, (int)ilDifference, logInstructions);
}
else
{
FieldInfo[] targetMethodInfos = patchClassType.GetRuntimeFields()
.Where(x => x.Name.Replace("_", "").StartsWith("targetMethod", StringComparison.OrdinalIgnoreCase))
.OrderBy(fieldInfo => fieldInfo.Name)
.ToArray();
if (targetMethodInfos.Length == 0)
{
Assert.Fail($"Could not find a \"TARGET_METHOD\" or \"targetMethod\" field inside {patchClassType.Name}");
}

MethodInfo targetMethod = targetMethodInfo.GetValue(null) as MethodInfo;
List<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(targetMethod).ToList();
List<CodeInstruction> originalIlCopy = PatchTestHelper.GetInstructionsFromMethod(targetMethod).ToList(); // Our custom pattern matching replaces OpCode/Operand in place, therefor we need a copy to compare if changes are present
// Should be put in alphabetical order of the corresponding "TARGET_METHOD" field name
int[] ilDifferences = (int[])ilDifference;

MethodInfo transpilerMethod = patchClassType.GetMethod("Transpiler");
if (transpilerMethod == null)
{
Assert.Fail($"Could not find \"Transpiler\" inside {patchClassType.Name}");
for (int i = 0; i < targetMethodInfos.Length; i++)
{
MethodInfo targetMethod = targetMethodInfos[i].GetValue(null) as MethodInfo;
TestTranspilerMethod(patchClassType, targetMethod, transpilerMethod, ilDifferences[i], logInstructions);
}
}
}

private static void TestTranspilerMethod(Type patchClassType, MethodInfo targetMethod, MethodInfo transpilerMethod, int ilDifference, bool logInstructions = false)
{
List<CodeInstruction> originalIl = PatchTestHelper.GetInstructionsFromMethod(targetMethod).ToList();
List<CodeInstruction> originalIlCopy = PatchTestHelper.GetInstructionsFromMethod(targetMethod).ToList(); // Our custom pattern matching replaces OpCode/Operand in place, therefor we need a copy to compare if changes are present

List<object> injectionParameters = [];
foreach (ParameterInfo parameterInfo in transpilerMethod.GetParameters())
Expand All @@ -143,7 +167,7 @@ public void AllPatchesTranspilerSanity(Type patchClassType, int ilDifference, bo
}

List<CodeInstruction> transformedIl = (transpilerMethod.Invoke(null, injectionParameters.ToArray()) as IEnumerable<CodeInstruction>)?.ToList();

if (logInstructions)
{
Console.WriteLine(transformedIl.ToPrettyString());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using NitroxClient.Communication.Abstract;
using NitroxClient.Communication.MultiplayerSession.ConnectionState;
Expand Down Expand Up @@ -82,28 +82,13 @@ public void ProcessSessionPolicy(MultiplayerSessionPolicy policy)

public void RequestSessionReservation(PlayerSettings playerSettings, AuthenticationContext authenticationContext)
{
// If a reservation has already been sent (in which case the client is enqueued in the join queue)
if (CurrentState.CurrentStage == MultiplayerSessionConnectionStage.AWAITING_SESSION_RESERVATION)
{
Log.Info("Waiting in join queue…");
Log.InGame(Language.main.Get("Nitrox_Waiting"));
return;
}

PlayerSettings = playerSettings;
AuthenticationContext = authenticationContext;
CurrentState.NegotiateReservationAsync(this);
}

public void ProcessReservationResponsePacket(MultiplayerSessionReservation reservation)
{
if (reservation.ReservationState == MultiplayerSessionReservationState.ENQUEUED_IN_JOIN_QUEUE)
{
Log.Info("Waiting in join queue…");
Log.InGame(Language.main.Get("Nitrox_Waiting"));
return;
}

Reservation = reservation;
CurrentState.NegotiateReservationAsync(this);
}
Expand All @@ -123,7 +108,7 @@ public void Disconnect()

public bool Send<T>(T packet) where T : Packet
{
if (!PacketSuppressor<T>.IsSuppressed)
if (Client.IsConnected && !PacketSuppressor<T>.IsSuppressed)
{
Client.Send(packet);
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class InitialPlayerSyncProcessor : ClientPacketProcessor<InitialPlayerSyn
{
private readonly IPacketSender packetSender;
private readonly HashSet<IInitialSyncProcessor> processors;
private readonly HashSet<Type> alreadyRan = new();
private readonly HashSet<Type> alreadyRan = [];
private InitialPlayerSync packet;

private WaitScreen.ManualWaitItem loadingMultiplayerWaitItem;
Expand All @@ -31,7 +31,10 @@ public InitialPlayerSyncProcessor(IPacketSender packetSender, IEnumerable<IIniti
public override void Process(InitialPlayerSync packet)
{
this.packet = packet;

loadingMultiplayerWaitItem = WaitScreen.Add(Language.main.Get("Nitrox_SyncingWorld"));
Log.InGame(Language.main.Get("Nitrox_SyncingWorld"));

cumulativeProcessorsRan = 0;
Multiplayer.Main.StartCoroutine(ProcessInitialSyncPacket(this, null));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using NitroxClient.Communication.Packets.Processors.Abstract;
using NitroxModel.Packets;

namespace NitroxClient.Communication.Packets.Processors;

public class JoinQueueInfoProcessor : ClientPacketProcessor<JoinQueueInfo>
{
public override void Process(JoinQueueInfo packet)
{
Log.InGame(Language.main.Get("Nitrox_QueueInfo")
.Replace("{POSITION}", packet.Position.ToString())
.Replace("{TIME}", TimeSpan.FromMilliseconds(packet.Timeout * packet.Position).ToString(@"mm\:ss")));
}
}
7 changes: 5 additions & 2 deletions NitroxClient/MonoBehaviours/Multiplayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,14 @@ public static IEnumerator LoadAsync()

WaitScreen.Remove(worldSettleItem);

WaitScreen.ManualWaitItem item = WaitScreen.Add(Language.main.Get("Nitrox_JoiningSession"));
WaitScreen.ManualWaitItem joiningItem = WaitScreen.Add(Language.main.Get("Nitrox_JoiningSession"));
yield return Main.StartCoroutine(Main.StartSession());
WaitScreen.Remove(item);
WaitScreen.Remove(joiningItem);

WaitScreen.ManualWaitItem waitingItem = WaitScreen.Add(Language.main.Get("Nitrox_Waiting"));
Log.InGame(Language.main.Get("Nitrox_Waiting"));
yield return new WaitUntil(() => Main.InitialSyncCompleted);
WaitScreen.Remove(waitingItem);

SetLoadingComplete();
OnLoadingComplete?.Invoke();
Expand Down
18 changes: 17 additions & 1 deletion NitroxModel/DataStructures/ThreadSafeQueue.cs
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 System.Diagnostics;
Expand Down Expand Up @@ -121,6 +121,22 @@ public IEnumerable<T> Clone()
}
}

public void Filter(Func<T, bool> predicate)
{
lock (locker)
{
int count = queue.Count;
for (int i = 0; i < count; i++)
{
T item = queue.Dequeue();
if (predicate(item))
{
queue.Enqueue(item);
}
}
}
}

private Queue<T> CreateCopy(IEnumerable<T> data)
{
return new Queue<T>(data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@ public enum MultiplayerSessionReservationState
[Description("The server is using hardcore gamemode, player is dead.")]
HARDCORE_PLAYER_DEAD = 1 << 4,

[Description("Another user is currently joining the server.")]
ENQUEUED_IN_JOIN_QUEUE = 1 << 5,

[Description("The player name is invalid, It must not contain any space or doubtful characters\n Allowed characters : A-Z a-z 0-9 _ . -\nLength : [3, 25]")]
INCORRECT_USERNAME = 1 << 6
INCORRECT_USERNAME = 1 << 5
}

public static class MultiplayerSessionReservationStateExtensions
Expand Down
16 changes: 16 additions & 0 deletions NitroxModel/Packets/JoinQueueInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace NitroxModel.Packets;

[Serializable]
public class JoinQueueInfo : Packet
{
public int Position { get; }
public int Timeout { get; }

public JoinQueueInfo(int position, int timeout)
{
Position = position;
Timeout = timeout;
}
}
2 changes: 1 addition & 1 deletion NitroxModel/Serialization/SubnauticaServerConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class SubnauticaServerConfig : NitroxConfig<SubnauticaServerConfig>
{
private int maxConnectionsSetting = 100;

private int initialSyncTimeoutSetting = 300000;
private int initialSyncTimeoutSetting = 120000;

[PropertyDescription("Set to true to Cache entities for the whole map on next run. \nWARNING! Will make server load take longer on the cache run but players will gain a performance boost when entering new areas.")]
public bool CreateFullEntityCache { get; set; } = false;
Expand Down
52 changes: 52 additions & 0 deletions NitroxPatcher/Patches/Dynamic/ErrorMessage_OnLateUpdate_Patch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using NitroxModel.Helper;
using NitroxPatcher.Patches;
using UnityEngine;

/// <summary>
/// Ensures the in-game log is animated smoothly regardless of the time scale.
/// </summary>
public sealed partial class ErrorMessage_OnLateUpdate_Patch : NitroxPatch, IDynamicPatch
{
private static readonly MethodInfo TARGET_METHOD_ON_LATE_UPDATE = Reflect.Method((ErrorMessage t) => t.OnLateUpdate());
private static readonly MethodInfo TARGET_METHOD_ADD_MESSAGE = Reflect.Method((ErrorMessage t) => t._AddMessage(default));
private static readonly MethodInfo TARGET_OPERAND_TIME = Reflect.Property(() => PDA.time).GetMethod;
private static readonly MethodInfo TARGET_OPERAND_DELTA_TIME = Reflect.Property(() => PDA.deltaTime).GetMethod;
private static readonly MethodInfo INJECTION_OPERAND_UNSCALED_TIME = Reflect.Property(() => Time.unscaledTime).GetMethod;
private static readonly MethodInfo INJECTION_OPERAND_UNSCALED_DELTA_TIME = Reflect.Property(() => Time.unscaledDeltaTime).GetMethod;


/*
* Replace all calls to PDA.time with Time.unscaledTime and to
* PDA.deltaTime with Time.unscaledDeltaTime
*/
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
CodeMatcher matcher = new CodeMatcher(instructions);

while (matcher.MatchStartForward(new CodeMatch(OpCodes.Call, TARGET_OPERAND_TIME)).IsValid)
{
matcher.SetOperandAndAdvance(INJECTION_OPERAND_UNSCALED_TIME);
}

matcher.Start();

while (matcher.MatchStartForward(new CodeMatch(OpCodes.Call, TARGET_OPERAND_DELTA_TIME)).IsValid)
{
matcher.SetOperandAndAdvance(INJECTION_OPERAND_UNSCALED_DELTA_TIME);
}

return matcher.InstructionEnumeration();
}

public override void Patch(Harmony harmony)
{
MethodInfo transpilerInfo = Reflect.Method(() => Transpiler(default));

PatchTranspiler(harmony, TARGET_METHOD_ON_LATE_UPDATE, transpilerInfo);
PatchTranspiler(harmony, TARGET_METHOD_ADD_MESSAGE, transpilerInfo);
}
}
3 changes: 1 addition & 2 deletions NitroxServer/Communication/LiteNetLib/LiteNetLibServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using LiteNetLib;
using LiteNetLib.Utils;
using Mono.Nat;
using NitroxModel.Helper;
using NitroxModel.Packets;
using NitroxModel.Serialization;
using NitroxServer.Communication.Packets;
Expand All @@ -18,7 +17,7 @@ public class LiteNetLibServer : NitroxServer
private readonly EventBasedNetListener listener;
private readonly NetManager server;

public LiteNetLibServer(PacketHandler packetHandler, PlayerManager playerManager, EntitySimulation entitySimulation, SubnauticaServerConfig serverConfig) : base(packetHandler, playerManager, entitySimulation, serverConfig)
public LiteNetLibServer(PacketHandler packetHandler, PlayerManager playerManager, JoiningManager joiningManager, EntitySimulation entitySimulation, SubnauticaServerConfig serverConfig) : base(packetHandler, playerManager, joiningManager, entitySimulation, serverConfig)
{
listener = new EventBasedNetListener();
server = new NetManager(listener);
Expand Down
31 changes: 16 additions & 15 deletions NitroxServer/Communication/NitroxServer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Threading;
using NitroxModel.DataStructures;
Expand Down Expand Up @@ -26,11 +26,13 @@ static NitroxServer()
protected readonly EntitySimulation entitySimulation;
protected readonly Dictionary<int, INitroxConnection> connectionsByRemoteIdentifier = new();
protected readonly PlayerManager playerManager;
protected readonly JoiningManager joiningManager;

public NitroxServer(PacketHandler packetHandler, PlayerManager playerManager, EntitySimulation entitySimulation, SubnauticaServerConfig serverConfig)
public NitroxServer(PacketHandler packetHandler, PlayerManager playerManager, JoiningManager joiningManager, EntitySimulation entitySimulation, SubnauticaServerConfig serverConfig)
{
this.packetHandler = packetHandler;
this.playerManager = playerManager;
this.joiningManager = joiningManager;
this.entitySimulation = entitySimulation;

portNumber = serverConfig.ServerPort;
Expand All @@ -47,24 +49,23 @@ protected void ClientDisconnected(INitroxConnection connection)
{
Player player = playerManager.GetPlayer(connection);

if (player != null)
if (player == null)
{
playerManager.PlayerDisconnected(connection);
joiningManager.JoiningPlayerDisconnected(connection);
return;
}

Disconnect disconnect = new(player.Id);
playerManager.SendPacketToAllPlayers(disconnect);
playerManager.PlayerDisconnected(connection);

List<SimulatedEntity> ownershipChanges = entitySimulation.CalculateSimulationChangesFromPlayerDisconnect(player);
Disconnect disconnect = new(player.Id);
playerManager.SendPacketToAllPlayers(disconnect);

if (ownershipChanges.Count > 0)
{
SimulationOwnershipChange ownershipChange = new(ownershipChanges);
playerManager.SendPacketToAllPlayers(ownershipChange);
}
}
else
List<SimulatedEntity> ownershipChanges = entitySimulation.CalculateSimulationChangesFromPlayerDisconnect(player);

if (ownershipChanges.Count > 0)
{
playerManager.NonPlayerDisconnected(connection);
SimulationOwnershipChange ownershipChange = new(ownershipChanges);
playerManager.SendPacketToAllPlayers(ownershipChange);
}
}

Expand Down
2 changes: 1 addition & 1 deletion NitroxServer/Communication/Packets/PacketHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using NitroxModel.Core;
using NitroxModel.Packets;
Expand Down
Loading