diff --git a/Runtime/Engine/Code/Foundation/AppLoopManager.cs b/Runtime/Engine/Code/Foundation/AppLoopManager.cs new file mode 100644 index 0000000..cde09a1 --- /dev/null +++ b/Runtime/Engine/Code/Foundation/AppLoopManager.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace RebootKit.Engine.Foundation { + public class AppLoopManager : MonoBehaviour { + static readonly Logger s_Logger = new Logger(nameof(AppLoopManager)); + + public delegate void TickDelegate(float dt); + + readonly List m_Delegates = new List(); + + void Update() { + float dt = Time.deltaTime; + foreach (TickDelegate tick in m_Delegates) { + tick(dt); + } + } + + public void Add(TickDelegate tick) { + if (m_Delegates.Contains(tick)) { + s_Logger.Warning("Tick is already registered!"); + } + + m_Delegates.Add(tick); + } + + public void Remove(TickDelegate tick) { + m_Delegates.Remove(tick); + } + } +} \ No newline at end of file diff --git a/Runtime/Engine/Code/Foundation/AppLoopManager.cs.meta b/Runtime/Engine/Code/Foundation/AppLoopManager.cs.meta new file mode 100644 index 0000000..6aec79c --- /dev/null +++ b/Runtime/Engine/Code/Foundation/AppLoopManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 64a923b7732440d1ab5505b4dd250fc2 +timeCreated: 1759181550 \ No newline at end of file diff --git a/Runtime/Engine/Code/Foundation/ConfigVarsContainer.cs b/Runtime/Engine/Code/Foundation/ConfigVarsContainer.cs index a4b505e..2256db1 100755 --- a/Runtime/Engine/Code/Foundation/ConfigVarsContainer.cs +++ b/Runtime/Engine/Code/Foundation/ConfigVarsContainer.cs @@ -4,7 +4,6 @@ using System.IO; using System.Reflection; using System.Text; using UnityEngine; -using ZLinq; namespace RebootKit.Engine.Foundation { [AttributeUsage(AttributeTargets.Field)] @@ -49,7 +48,7 @@ namespace RebootKit.Engine.Foundation { static readonly List s_configVars = new List(); public static void Register(ConfigVar cvar) { - if (s_configVars.AsValueEnumerable().Any(c => c.name.Equals(cvar.name, StringComparison.Ordinal))) { + if (Get(cvar.name) != null) { throw new Exception($"CVar with name '{cvar.name}' already exists"); } @@ -63,7 +62,13 @@ namespace RebootKit.Engine.Foundation { } public static ConfigVar Get(string name) { - return s_configVars.AsValueEnumerable().FirstOrDefault(c => c.name.Equals(name, StringComparison.Ordinal)); + foreach (ConfigVar configVar in s_configVars) { + if (configVar.name.Equals(name, StringComparison.Ordinal)) { + return configVar; + } + } + + return null; } public static IEnumerable All() => s_configVars; diff --git a/Runtime/Engine/Code/Main/RR.cs b/Runtime/Engine/Code/Main/RR.cs index e6cbedb..32a6fac 100755 --- a/Runtime/Engine/Code/Main/RR.cs +++ b/Runtime/Engine/Code/Main/RR.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; using Cysharp.Threading.Tasks; -using R3; using RebootKit.Engine.Console; +using RebootKit.Engine.Extensions; using RebootKit.Engine.Foundation; using RebootKit.Engine.Input; using RebootKit.Engine.Network; @@ -32,10 +32,10 @@ namespace RebootKit.Engine.Main { internal static EngineConfigAsset EngineConfig; - static DisposableBag s_DisposableBag; - static DisposableBag s_ServicesBag; - static AsyncOperationHandle s_MainMenuSceneHandle; + + internal static GameObject SystemGameObject; + internal static AppLoopManager LoopManager; internal static NetworkSystem Network; internal static byte NetworkProtocolVersion { @@ -62,14 +62,16 @@ namespace RebootKit.Engine.Main { EngineConfig = configAsset; s_Logger.Info("Initializing"); - s_ServicesBag = new DisposableBag(); - s_DisposableBag = new DisposableBag(); s_Logger.Info("Registering core services"); - Console = CreateService(); + Console = new ConsoleService(); Input = new InputService(EngineConfig.inputConfig); - s_ServicesBag.Add(Input); - World = CreateService(); + World = new WorldService(); + + SystemGameObject = new GameObject("__RebootReality__"); + Object.DontDestroyOnLoad(SystemGameObject); + + LoopManager = SystemGameObject.AddComponent(); #if RR_STEAM await SteamManager.InitializeAsync(cancellationToken); @@ -83,9 +85,7 @@ namespace RebootKit.Engine.Main { // @NOTE: This method is called after the main scene is loaded. internal static async UniTask RunAsync(CancellationToken cancellationToken) { - Observable.EveryUpdate() - .Subscribe(_ => Tick()) - .AddTo(ref s_DisposableBag); + LoopManager.Add(Tick); await OpenMainMenuAsync(cancellationToken); @@ -116,9 +116,14 @@ namespace RebootKit.Engine.Main { #if RR_STEAM SteamManager.Shutdown(); #endif - - s_ServicesBag.Dispose(); - s_DisposableBag.Dispose(); + World.Dispose(); + Input.Dispose(); + Console.Dispose(); + + LoopManager = null; + if (SystemGameObject.OrNull() != null) { + Object.Destroy(SystemGameObject); + } } // Assets API @@ -140,8 +145,7 @@ namespace RebootKit.Engine.Main { throw new ArgumentException("World config name cannot be null or empty", nameof(name)); } - WorldConfigAsset worldConfig = - s_WorldConfigsAssets.Find(asset => asset.Config.name.Equals(name, StringComparison.Ordinal)); + WorldConfigAsset worldConfig = s_WorldConfigsAssets.Find(asset => asset.Config.name.Equals(name, StringComparison.Ordinal)); if (worldConfig is null) { throw new KeyNotFoundException($"World config '{name}' not found"); } @@ -271,26 +275,6 @@ namespace RebootKit.Engine.Main { } } - // - // @MARK: Service API - // Services seems to be useless in the current architecture. Consider removing this API in the future. - // - public static TService CreateService(ServiceAsset asset) where TService : class, IService { - if (asset is null) { - throw new ArgumentNullException($"Null asset of type {typeof(TService)}"); - } - - TService service = asset.Create(); - s_ServicesBag.Add(service); - return service; - } - - public static TService CreateService() where TService : class, IService { - TService service = Activator.CreateInstance(); - s_ServicesBag.Add(service); - return service; - } - // // @MARK: Logging API // @@ -425,9 +409,8 @@ namespace RebootKit.Engine.Main { throw new NotSupportedException("Cannot send chat message. Not connected to a server."); } - static void Tick() { - float deltaTime = Time.deltaTime; - Network.Tick(deltaTime); + static void Tick(float dt) { + Network.Tick(dt); } internal static void OnServerStarted() { diff --git a/Runtime/Engine/Code/Network/UnityNetworkManager.cs b/Runtime/Engine/Code/Network/UnityNetworkManager.cs index 33e0aaa..5ac4839 100644 --- a/Runtime/Engine/Code/Network/UnityNetworkManager.cs +++ b/Runtime/Engine/Code/Network/UnityNetworkManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using R3; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Networking.Transport; diff --git a/Runtime/Engine/Code/Simulation/Actor.cs b/Runtime/Engine/Code/Simulation/Actor.cs index 1f7eaca..dcb302e 100644 --- a/Runtime/Engine/Code/Simulation/Actor.cs +++ b/Runtime/Engine/Code/Simulation/Actor.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; using System.Globalization; using RebootKit.Engine.Foundation; using RebootKit.Engine.Main; @@ -280,7 +279,7 @@ namespace RebootKit.Engine.Simulation { [Serializable] public struct AttachmentSocket { - [MaxLength(32)] + [InfoBox("Max length: 32")] public string socketName; public Transform root; diff --git a/Runtime/Engine/Code/Steam/SteamManager.cs b/Runtime/Engine/Code/Steam/SteamManager.cs index 94cbe83..e52dfe9 100644 --- a/Runtime/Engine/Code/Steam/SteamManager.cs +++ b/Runtime/Engine/Code/Steam/SteamManager.cs @@ -1,7 +1,6 @@ using System; using System.Threading; using Cysharp.Threading.Tasks; -using R3; using RebootKit.Engine.Main; using Steamworks; using Logger = RebootKit.Engine.Foundation.Logger;