diff --git a/Source/Entities/Activity.cpp b/Source/Entities/Activity.cpp index 5744f95143..795ea63532 100644 --- a/Source/Entities/Activity.cpp +++ b/Source/Entities/Activity.cpp @@ -16,6 +16,8 @@ #include "GUIFont.h" #include "AllegroBitmap.h" +#include "RTETools.h" + namespace RTE { AbstractClassInfo(Activity, Entity); @@ -284,6 +286,9 @@ void Activity::Clear() { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Activity::Start() { + // Reseed the RNG for determinism + SeedRNG(); + if (m_ActivityState != ActivityState::Editing) { m_ActivityState = ActivityState::Running; } diff --git a/Source/Entities/Actor.cpp b/Source/Entities/Actor.cpp index 2f8aa42f5b..a94e3f94c3 100644 --- a/Source/Entities/Actor.cpp +++ b/Source/Entities/Actor.cpp @@ -1287,15 +1287,17 @@ void Actor::OnNewMovePath() { ////////////////////////////////////////////////////////////////////////////////////////// void Actor::PreControllerUpdate() { - if (m_UpdateMovePath) { - UpdateMovePath(); - } - if (m_PathRequest && m_PathRequest->complete) { m_MovePath = const_cast &>(m_PathRequest->path); m_PathRequest.reset(); OnNewMovePath(); } + + // We update this after, because pathing requests are forced to take at least 1 frame for the sake of determinism for now. + // In future maybe we can move this back, but it doesn't make much difference (the threadpool submission overhead makes it extremely unlikely that it would complete in less time anyways) + if (m_UpdateMovePath) { + UpdateMovePath(); + } } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Source/Managers/LuaMan.cpp b/Source/Managers/LuaMan.cpp index 0882b89985..c6443f6e81 100644 --- a/Source/Managers/LuaMan.cpp +++ b/Source/Managers/LuaMan.cpp @@ -294,7 +294,12 @@ namespace RTE { void LuaMan::Initialize() { m_MasterScriptState.Initialize(); - m_ScriptStates = std::vector(std::thread::hardware_concurrency()); + int luaStateCount = std::thread::hardware_concurrency(); + if (g_SettingsMan.GetNumberOfLuaStatesOverride() != -1) { + luaStateCount = g_SettingsMan.GetNumberOfLuaStatesOverride(); + } + + m_ScriptStates = std::vector(luaStateCount); for (LuaStateWrapper &luaState : m_ScriptStates) { luaState.Initialize(); } diff --git a/Source/Managers/MovableMan.cpp b/Source/Managers/MovableMan.cpp index 22206c9d96..ec29af0c4e 100644 --- a/Source/Managers/MovableMan.cpp +++ b/Source/Managers/MovableMan.cpp @@ -1688,6 +1688,11 @@ void MovableMan::Update() // Travel MOs Travel(); + // If our debug settings switch is forcing all pathing requests to immediately complete, make sure they're done here + if (g_SettingsMan.GetForceImmediatePathingRequestCompletion() && g_SceneMan.GetScene()) { + g_SceneMan.GetScene()->BlockUntilAllPathingRequestsComplete(); + } + // Prior to controller/AI update, execute lua callbacks g_LuaMan.ExecuteLuaScriptCallbacks(); diff --git a/Source/Managers/SettingsMan.cpp b/Source/Managers/SettingsMan.cpp index c036f2bf69..6afd9221b4 100644 --- a/Source/Managers/SettingsMan.cpp +++ b/Source/Managers/SettingsMan.cpp @@ -52,6 +52,9 @@ namespace RTE { m_DisableFactionBuyMenuThemeCursors = false; m_PathFinderGridNodeSize = c_PPM; m_AIUpdateInterval = 2; + + m_NumberOfLuaStatesOverride = -1; + m_ForceImmediatePathingRequestCompletion = false; m_SkipIntro = false; m_ShowToolTips = true; @@ -170,6 +173,8 @@ namespace RTE { MatchProperty("DisableFactionBuyMenuThemeCursors", { reader >> m_DisableFactionBuyMenuThemeCursors; }); MatchProperty("PathFinderGridNodeSize", { reader >> m_PathFinderGridNodeSize; }); MatchProperty("AIUpdateInterval", { reader >> m_AIUpdateInterval; }); + MatchProperty("NumberOfLuaStatesOverride", { reader >> m_NumberOfLuaStatesOverride; }); + MatchProperty("ForceImmediatePathingRequestCompletion", { reader >> m_ForceImmediatePathingRequestCompletion; }); MatchProperty("EnableParticleSettling", { reader >> g_MovableMan.m_SettlingEnabled; }); MatchProperty("EnableMOSubtraction", { reader >> g_MovableMan.m_MOSubtractionEnabled; }); MatchProperty("DeltaTime", { g_TimerMan.SetDeltaTimeSecs(std::stof(reader.ReadPropValue())); }); @@ -315,6 +320,8 @@ namespace RTE { writer.NewPropertyWithValue("DisableFactionBuyMenuThemeCursors", m_DisableFactionBuyMenuThemeCursors); writer.NewPropertyWithValue("PathFinderGridNodeSize", m_PathFinderGridNodeSize); writer.NewPropertyWithValue("AIUpdateInterval", m_AIUpdateInterval); + writer.NewPropertyWithValue("NumberOfLuaStatesOverride", m_NumberOfLuaStatesOverride); + writer.NewPropertyWithValue("ForceImmediatePathingRequestCompletion", m_ForceImmediatePathingRequestCompletion); writer.NewPropertyWithValue("EnableParticleSettling", g_MovableMan.m_SettlingEnabled); writer.NewPropertyWithValue("EnableMOSubtraction", g_MovableMan.m_MOSubtractionEnabled); writer.NewPropertyWithValue("DeltaTime", g_TimerMan.GetDeltaTimeSecs()); diff --git a/Source/Managers/SettingsMan.h b/Source/Managers/SettingsMan.h index cc00b65ec8..5e30ca27bb 100644 --- a/Source/Managers/SettingsMan.h +++ b/Source/Managers/SettingsMan.h @@ -134,6 +134,18 @@ namespace RTE { /// /// How often Actor's AI will now be updated, in simulation updates. void SetAIUpdateInterval(int newAIUpdateInterval) { m_AIUpdateInterval = newAIUpdateInterval; } + + /// + /// Gets how many threaded Lua states we'll use. -1 represents no override, which defaults to the maximum number of concurrent hardware threads. + /// + /// How many threaded Lua states we'll use. + int GetNumberOfLuaStatesOverride() const { return m_NumberOfLuaStatesOverride; } + + /// + /// Gets whether pathing requests will be forced to immediately complete for the next frame, or if they can take multiple frames to calculate. + /// + /// Whether pathing requests will be forced to immediately complete for the next frame + bool GetForceImmediatePathingRequestCompletion() const { return m_ForceImmediatePathingRequestCompletion; } #pragma endregion #pragma region Gameplay Settings @@ -549,6 +561,8 @@ namespace RTE { bool m_DisableFactionBuyMenuThemeCursors; //!< Whether custom cursor support in faction BuyMenu themes is disabled. int m_PathFinderGridNodeSize; //!< The grid size used by the PathFinder, in pixels. int m_AIUpdateInterval; //!< How often actor's AI should be updated, i.e. every n simulation updates. + int m_NumberOfLuaStatesOverride; //!< Overrides how many threaded Lua states we'll use. -1 for no override, which defaults to the maximum number of concurrent hardware threads. + bool m_ForceImmediatePathingRequestCompletion; //!< Whether pathing requests will be forced to immediately complete for the next frame, or if they can take multiple frames to calculate. bool m_SkipIntro; //!< Whether to play the intro of the game or skip directly to the main menu. bool m_ShowToolTips; //!< Whether ToolTips are enabled or not.