diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index af94426d02..4312cd07c4 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -3387,21 +3387,9 @@ public static void UpdateAll(float deltaTime, Camera cam) characterUpdateTick++; - if (characterUpdateTick % CharacterUpdateInterval == 0) + for (int i = 0; i < CharacterList.Count; i++) { - for (int i = 0; i < CharacterList.Count; i++) - { - if (GameMain.LuaCs.Game.UpdatePriorityCharacters.Contains(CharacterList[i])) continue; - - CharacterList[i].Update(deltaTime * CharacterUpdateInterval, cam); - } - } - - foreach (Character character in GameMain.LuaCs.Game.UpdatePriorityCharacters) - { - if (character.Removed) { continue; } - Debug.Assert(character is { Removed: false }); - character.Update(deltaTime, cam); + CharacterList[i].Update(deltaTime, cam); } #if CLIENT diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Gap.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Gap.cs index a79e4c1c62..8a6cb6c30a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Gap.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Gap.cs @@ -814,6 +814,7 @@ public bool RefreshOutsideCollider() { SingleThreadWorker.GlobalWorker.AddAction(() => { + if (outsideCollisionBlocker == null) { return; } outsideCollisionBlocker.Enabled = false; }); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/MapEntity.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/MapEntity.cs index d64738684e..97b3a8697d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/MapEntity.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/MapEntity.cs @@ -650,7 +650,8 @@ public static void UpdateAll(float deltaTime, Camera cam, ParallelOptions parall // Buffer lists to avoid repeated allocations var hullList = Hull.HullList.ToList(); var structureList = Structure.WallList.ToList(); - var gapList = Gap.GapList.ToList(); + // First, WHY THIS LINQ GOT A NULL ERROR? Second, WHY?? + List shuffledGaps = Gap.GapList?.OrderBy(g => Rand.Int(int.MaxValue)).ToList() ?? Gap.GapList.ToList(); var itemList = Item.ItemList.ToList(); // First phase: parallel updates that have no order dependencies @@ -679,14 +680,12 @@ public static void UpdateAll(float deltaTime, Camera cam, ParallelOptions parall // moved waterflow reset here to see if we can reduce at least some time { - // if crashed, go ask the god damn physics engine :( - var shuffledGaps = gapList.OrderBy(g => Rand.Int(int.MaxValue)).ToList(); + if (shuffledGaps == null) { shuffledGaps = Gap.GapList; } Parallel.ForEach(shuffledGaps, parallelOptions, gap => { gap.ResetWaterFlowThisFrame(); gap.Update(deltaTime, cam); }); - SingleThreadWorker.GlobalWorker.RunActions(); }, // Powered components update () => @@ -695,6 +694,8 @@ public static void UpdateAll(float deltaTime, Camera cam, ParallelOptions parall } ); + SingleThreadWorker.GlobalWorker.RunActions(); + #if CLIENT // Hull Cheats need to be executed after Hull update Hull.UpdateCheats(deltaTime, cam); @@ -709,7 +710,6 @@ public static void UpdateAll(float deltaTime, Camera cam, ParallelOptions parall // Item update (Item.Update() is not thread-safe and must be executed on the main thread) Item.UpdatePendingConditionUpdates(deltaTime); - float scaledDeltaTime = deltaTime * MapEntityUpdateInterval; Item lastUpdatedItem = null; try @@ -717,7 +717,7 @@ public static void UpdateAll(float deltaTime, Camera cam, ParallelOptions parall foreach (Item item in itemList) { lastUpdatedItem = item; - item.Update(scaledDeltaTime, cam); + item.Update(deltaTime, cam); } } catch (InvalidOperationException e) @@ -729,7 +729,7 @@ public static void UpdateAll(float deltaTime, Camera cam, ParallelOptions parall throw new InvalidOperationException($"Error while updating item {lastUpdatedItem?.Name ?? "null"}", innerException: e); } - UpdateAllProjSpecific(scaledDeltaTime); + UpdateAllProjSpecific(deltaTime); Spawner?.Update(); #if CLIENT diff --git a/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs b/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs index 496d79bb1a..0aa9dcf376 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Screens/GameScreen.cs @@ -1,6 +1,4 @@ -//#define RUN_PHYSICS_IN_SEPARATE_THREAD - -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using System.Threading; using FarseerPhysics.Dynamics; using FarseerPhysics; @@ -23,9 +21,10 @@ partial class GameScreen : Screen private object updateLock = new object(); private double physicsTime; + // -2 here bcuz we alread have a SEEM thread there private static readonly ParallelOptions parallelOptions = new ParallelOptions { - MaxDegreeOfParallelism = Math.Max(4, Environment.ProcessorCount - 1) + MaxDegreeOfParallelism = Math.Max(4, Environment.ProcessorCount - 2) }; #if CLIENT @@ -78,14 +77,6 @@ public override void Select() MapEntity.ClearHighlightedEntities(); -#if RUN_PHYSICS_IN_SEPARATE_THREAD - var physicsThread = new Thread(ExecutePhysics) - { - Name = "Physics thread", - IsBackground = true - }; - physicsThread.Start(); -#endif } public override void Deselect() @@ -114,14 +105,10 @@ public override void Deselect() public override void Update(double deltaTime) { -#warning For now CL side performance counter is partly useless bucz multiple changes on such things. Need time to take care of it - -#if RUN_PHYSICS_IN_SEPARATE_THREAD - physicsTime += deltaTime; - lock (updateLock) - { -#endif + var submarines = Submarine.Loaded.ToList(); + var physicsBodies = PhysicsBody.List.ToList(); +#warning For now CL side performance counter is partly useless bucz multiple changes on such things. Need time to take care of it #if DEBUG && CLIENT if (GameMain.GameSession != null && !DebugConsole.IsOpen && GUI.KeyboardDispatcher.Subscriber == null) @@ -150,8 +137,6 @@ public override void Update(double deltaTime) GameTime += deltaTime; - var physicsBodies = PhysicsBody.List.ToList(); - Parallel.ForEach(physicsBodies, parallelOptions, body => { if ((body.Enabled || body.UserData is Character) && @@ -162,14 +147,6 @@ public override void Update(double deltaTime) }); GameMain.GameSession?.Update((float)deltaTime); - Parallel.ForEach(physicsBodies, parallelOptions, body => - { - if (body.Enabled && body.BodyType != BodyType.Static) - { - body.SetPrevTransform(body.SimPosition, body.Rotation); - } - }); - MapEntity.ClearHighlightedEntities(); #if CLIENT @@ -254,20 +231,19 @@ public override void Update(double deltaTime) StatusEffect.UpdateAll((float)deltaTime); #endif - var submarines = Submarine.Loaded.ToList(); - - Parallel.ForEach(submarines, parallelOptions, sub => + foreach (Submarine sub in submarines) { sub.SetPrevTransform(sub.Position); - }); + } - Parallel.ForEach(physicsBodies, parallelOptions, body => + foreach (var body in physicsBodies) { - if (body.Enabled && body.BodyType != FarseerPhysics.BodyType.Static) - { - body.SetPrevTransform(body.SimPosition, body.Rotation); + if (body.Enabled && body.BodyType != FarseerPhysics.BodyType.Static) + { + body.SetPrevTransform(body.SimPosition, body.Rotation); } - }); + } + #if CLIENT MapEntity.UpdateAll((float)deltaTime, cam, parallelOptions); @@ -306,8 +282,6 @@ public override void Update(double deltaTime) GameMain.PerformanceCounter.AddElapsedTicks("Update:Submarine", sw.ElapsedTicks); sw.Restart(); #endif - -#if !RUN_PHYSICS_IN_SEPARATE_THREAD try { GameMain.World.Step((float)Timing.Step); @@ -318,17 +292,12 @@ public override void Update(double deltaTime) DebugConsole.ThrowError(errorMsg, e); GameAnalyticsManager.AddErrorEventOnce("GameScreen.Update:WorldLockedException" + e.Message, GameAnalyticsManager.ErrorSeverity.Critical, errorMsg); } -#endif #if CLIENT sw.Stop(); GameMain.PerformanceCounter.AddElapsedTicks("Update:Physics", sw.ElapsedTicks); #endif UpdateProjSpecific(deltaTime); - -#if RUN_PHYSICS_IN_SEPARATE_THREAD - } -#endif } partial void UpdateProjSpecific(double deltaTime); diff --git a/Barotrauma/BarotraumaShared/SharedSource/SingleThreadWorker.cs b/Barotrauma/BarotraumaShared/SharedSource/SingleThreadWorker.cs index 6902f8a285..8beef7b858 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/SingleThreadWorker.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/SingleThreadWorker.cs @@ -9,16 +9,27 @@ public class SingleThreadWorker public static SingleThreadWorker GlobalWorker = new SingleThreadWorker(); + /// + /// Initilize a SingleThreadWorker + /// SingleThreadWorker or STW for short is a FIFO queue ensure single-thread execution of a series of actions. + /// public SingleThreadWorker() { ActionQueue = new ConcurrentQueue(); } + /// + /// Add a pending action in a STW queue + /// + /// public void AddAction(Action action) { ActionQueue.Enqueue(action); } + /// + /// Run all pending actions in the STW queue + /// [STAThread] public void RunActions() { @@ -32,8 +43,9 @@ public void RunActions() { // Just try-catch and do nothing but print errorlogs. We cannot afford crashing the game. ConsoleColor originalForeground = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine($"WARNING: Error occurred when running Single Thread Actions \n{e}"); + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"WARNING: Error occurred when running Single Thread Actions. " + + $"If the server didn't crash or stop responding then this should be fine \n{e}"); Console.ForegroundColor = Console.ForegroundColor; } }