extensions and actor changes
This commit is contained in:
		| @@ -23,6 +23,13 @@ namespace RebootKit.Engine.Extensions { | ||||
|     } | ||||
|  | ||||
|     public static class float3Ex { | ||||
|         [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
|         public static float3 With(this float3 vec, float? x = null, float? y = null, float? z = null) { | ||||
|             return new float3(x ?? vec.x, | ||||
|                                y ?? vec.y, | ||||
|                                z ?? vec.z); | ||||
|         } | ||||
|          | ||||
|         [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
|         public static bool IsZero(this float3 vec, float epsilon = float.Epsilon) { | ||||
|             return math.abs(vec.x) < epsilon && math.abs(vec.y) < epsilon && math.abs(vec.z) < epsilon; | ||||
|   | ||||
| @@ -1,32 +1,25 @@ | ||||
| using System; | ||||
| using System.Threading; | ||||
| using Cysharp.Threading.Tasks; | ||||
| using RebootKit.Engine.Foundation; | ||||
| using RebootKit.Engine.Foundation; | ||||
| using UnityEngine; | ||||
|  | ||||
| namespace RebootKit.Engine.Services.Simulation { | ||||
|     public class Actor : MonoBehaviour { | ||||
|     public abstract class Actor : MonoBehaviour { | ||||
|         [field: SerializeField] | ||||
|         public SerializableGuid ActorGuid { get; private set; } = SerializableGuid.New(); | ||||
|  | ||||
|         public bool IsInitialized { get; private set; } | ||||
|  | ||||
|         bool m_Simulate; | ||||
|         public bool Simulate { | ||||
|             get => m_Simulate; | ||||
|         bool m_IsPlaying = false; | ||||
|         public bool IsPlaying { | ||||
|             get { | ||||
|                 return m_IsPlaying; | ||||
|             } | ||||
|  | ||||
|             set { | ||||
|                 if (m_Simulate == value) { | ||||
|                 if (m_IsPlaying == value) { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 m_Simulate = value; | ||||
|                 m_IsPlaying = value; | ||||
|  | ||||
|                 if (!IsInitialized) { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 if (m_Simulate) { | ||||
|                 if (m_IsPlaying) { | ||||
|                     OnBeginPlay(); | ||||
|                 } else { | ||||
|                     OnEndPlay(); | ||||
| @@ -34,24 +27,10 @@ namespace RebootKit.Engine.Services.Simulation { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         async void Start() { | ||||
|             IsInitialized = false; | ||||
|             await InitAsync(destroyCancellationToken); | ||||
|             IsInitialized = true; | ||||
|  | ||||
|             if (Simulate) { | ||||
|                 OnBeginPlay(); | ||||
|             } | ||||
|         public virtual void OnSpawned() { | ||||
|         } | ||||
|  | ||||
|         void Update() { | ||||
|             if (m_Simulate && IsInitialized) { | ||||
|                 OnTick(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         protected virtual async UniTask InitAsync(CancellationToken cancellationToken) { | ||||
|             await UniTask.Yield(cancellationToken); | ||||
|         public virtual void OnDespawned() { | ||||
|         } | ||||
|  | ||||
|         public virtual void OnBeginPlay() { | ||||
| @@ -60,7 +39,7 @@ namespace RebootKit.Engine.Services.Simulation { | ||||
|         public virtual void OnEndPlay() { | ||||
|         } | ||||
|  | ||||
|         public virtual void OnTick() { | ||||
|         public virtual void OnTick(float deltaTime) { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,7 +1,8 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading; | ||||
| using Cysharp.Threading.Tasks; | ||||
| using R3; | ||||
| using RebootKit.Engine.Foundation; | ||||
| using UnityEngine; | ||||
| using UnityEngine.AddressableAssets; | ||||
| @@ -12,12 +13,11 @@ using UnityEngine.SceneManagement; | ||||
| using Logger = RebootKit.Engine.Foundation.Logger; | ||||
|  | ||||
| namespace RebootKit.Engine.Services.Simulation { | ||||
|     public interface IWorldContext { | ||||
|     } | ||||
|      | ||||
|     public interface IWorldContext { } | ||||
|  | ||||
|     public class WorldService : IService { | ||||
|         static readonly Logger s_Logger = new Logger(nameof(WorldService)); | ||||
|          | ||||
|  | ||||
|         enum WorldState { | ||||
|             Unloaded, | ||||
|             Loading, | ||||
| @@ -28,14 +28,31 @@ namespace RebootKit.Engine.Services.Simulation { | ||||
|         WorldConfig m_Config; | ||||
|         AsyncOperationHandle<SceneInstance> m_SceneInstance; | ||||
|  | ||||
|         struct ActorData { | ||||
|             public Actor Actor; | ||||
|             public readonly bool ManagedByAddressabled; | ||||
|              | ||||
|             public ActorData(Actor actor, bool managedByAddressabled) { | ||||
|                 Actor = actor; | ||||
|                 ManagedByAddressabled = managedByAddressabled; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         readonly List<ActorData> m_Actors = new List<ActorData>(); | ||||
|         readonly IDisposable m_UpdateSubscription; | ||||
|  | ||||
|         public IWorldContext Context { get; private set; } | ||||
|          | ||||
|         readonly List<Actor> m_Actors = new List<Actor>(); | ||||
|  | ||||
|         public WorldService() { | ||||
|             m_UpdateSubscription = Observable.EveryUpdate() | ||||
|                                              .Subscribe(_ => { Tick(Time.deltaTime); }); | ||||
|         } | ||||
|  | ||||
|         public void Dispose() { | ||||
|             m_UpdateSubscription.Dispose(); | ||||
|             Unload(); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         public async UniTask LoadAsync(WorldConfig worldConfig, CancellationToken cancellationToken) { | ||||
|             await UniTask.WaitWhile(() => m_WorldState == WorldState.Loading, cancellationToken: cancellationToken); | ||||
|  | ||||
| @@ -46,35 +63,24 @@ namespace RebootKit.Engine.Services.Simulation { | ||||
|  | ||||
|             m_SceneInstance = worldConfig.mainScene.LoadSceneAsync(LoadSceneMode.Additive, false); | ||||
|             await m_SceneInstance.ToUniTask(cancellationToken: cancellationToken); | ||||
|              | ||||
|  | ||||
|             await m_SceneInstance.Result.ActivateAsync(); | ||||
|             SceneManager.SetActiveScene(m_SceneInstance.Result.Scene); | ||||
|  | ||||
|             foreach (GameObject root in m_SceneInstance.Result.Scene.GetRootGameObjects()) { | ||||
|                 if (root.TryGetComponent(out IWorldContext worldContext)) { | ||||
|                     Assert.IsNull(Context, "WorldContext is already set. There should be only one WorldContext in the scene."); | ||||
|                     Assert.IsNull(Context, | ||||
|                                   "WorldContext is already set. There should be only one WorldContext in the scene."); | ||||
|                     Context = worldContext; | ||||
|                 } | ||||
|  | ||||
|                 foreach (Actor actor in root.GetComponentsInChildren<Actor>()) { | ||||
|                     RegisterActor(actor); | ||||
|                     m_Actors.Add(new ActorData(actor, false)); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             m_WorldState = WorldState.Loaded; | ||||
|         } | ||||
|          | ||||
|         public async UniTask<TRequiredActor> LoadAsync<TRequiredActor>(WorldConfig worldConfig, CancellationToken cancellationToken) where TRequiredActor : Actor { | ||||
|             await LoadAsync(worldConfig, cancellationToken); | ||||
|              | ||||
|             TRequiredActor actor = m_Actors.FirstOrDefault(t => t is TRequiredActor) as TRequiredActor; | ||||
|             if (actor is null) { | ||||
|                 s_Logger.Error($"Actor of type {typeof(TRequiredActor)} not found in the scene"); | ||||
|                 return null; | ||||
|             } | ||||
|              | ||||
|             return actor; | ||||
|         } | ||||
|  | ||||
|         public void Unload() { | ||||
|             KillAllActors(); | ||||
| @@ -88,7 +94,13 @@ namespace RebootKit.Engine.Services.Simulation { | ||||
|             Context = null; | ||||
|         } | ||||
|  | ||||
|         public async UniTask<TActor> SpawnActor<TActor>(AssetReferenceT<GameObject> asset, CancellationToken cancellationToken) where TActor : Actor { | ||||
|         public async UniTask<TActor> SpawnActor<TActor>(AssetReferenceT<GameObject> asset, | ||||
|                                                         CancellationToken cancellationToken) where TActor : Actor { | ||||
|             if (m_WorldState != WorldState.Loaded) { | ||||
|                 s_Logger.Error("World is not loaded. Cannot spawn actor."); | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             GameObject gameObject = await Addressables.InstantiateAsync(asset); | ||||
|             if (cancellationToken.IsCancellationRequested) { | ||||
|                 asset.ReleaseInstance(gameObject); | ||||
| @@ -96,6 +108,9 @@ namespace RebootKit.Engine.Services.Simulation { | ||||
|             } | ||||
|  | ||||
|             if (gameObject.TryGetComponent(out TActor actor)) { | ||||
|                 actor.OnSpawned(); | ||||
|                 actor.IsPlaying = true; | ||||
|                 m_Actors.Add(new ActorData(actor, true)); | ||||
|                 return actor; | ||||
|             } | ||||
|  | ||||
| @@ -103,20 +118,52 @@ namespace RebootKit.Engine.Services.Simulation { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         public void RegisterActor(Actor actor) { | ||||
|             m_Actors.Add(actor); | ||||
|         } | ||||
|  | ||||
|         public void KillActor(Actor actor) { | ||||
|             Addressables.ReleaseInstance(actor.gameObject); | ||||
|             ActorData actorData = default; | ||||
|             bool found = false; | ||||
|             for (int i = m_Actors.Count - 1; i >= 0; i--) { | ||||
|                 if (m_Actors[i].Actor == actor) { | ||||
|                     found = true; | ||||
|                     actorData = m_Actors[i]; | ||||
|                     m_Actors.RemoveAt(i); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             Assert.IsTrue(found, $"Actor {actor.name} not found in the world actors list."); | ||||
|  | ||||
|             actor.IsPlaying = false; | ||||
|             actor.OnDespawned(); | ||||
|  | ||||
|             if (actorData.ManagedByAddressabled) { | ||||
|                 Addressables.ReleaseInstance(actor.gameObject); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public void KillAllActors() { | ||||
|             foreach (Actor actor in m_Actors) { | ||||
|                 Addressables.ReleaseInstance(actor.gameObject); | ||||
|             foreach (ActorData actorData in m_Actors) { | ||||
|                 actorData.Actor.IsPlaying = false; | ||||
|                 actorData.Actor.OnDespawned(); | ||||
|  | ||||
|                 if (actorData.ManagedByAddressabled) { | ||||
|                     Addressables.ReleaseInstance(actorData.Actor.gameObject); | ||||
|                 } else { | ||||
|                     UnityEngine.Object.Destroy(actorData.Actor.gameObject); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             m_Actors.Clear(); | ||||
|         } | ||||
|  | ||||
|         void Tick(float deltaTime) { | ||||
|             if (m_WorldState != WorldState.Loaded) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             foreach (ActorData actorData in m_Actors) { | ||||
|                 if (actorData.Actor.IsPlaying) { | ||||
|                     actorData.Actor.OnTick(deltaTime); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user