extensions and actor changes
This commit is contained in:
		| @@ -23,6 +23,13 @@ namespace RebootKit.Engine.Extensions { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static class float3Ex { |     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)] |         [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||||
|         public static bool IsZero(this float3 vec, float epsilon = float.Epsilon) { |         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; |             return math.abs(vec.x) < epsilon && math.abs(vec.y) < epsilon && math.abs(vec.z) < epsilon; | ||||||
|   | |||||||
| @@ -1,32 +1,25 @@ | |||||||
| using System; | using RebootKit.Engine.Foundation; | ||||||
| using System.Threading; |  | ||||||
| using Cysharp.Threading.Tasks; |  | ||||||
| using RebootKit.Engine.Foundation; |  | ||||||
| using UnityEngine; | using UnityEngine; | ||||||
|  |  | ||||||
| namespace RebootKit.Engine.Services.Simulation { | namespace RebootKit.Engine.Services.Simulation { | ||||||
|     public class Actor : MonoBehaviour { |     public abstract class Actor : MonoBehaviour { | ||||||
|         [field: SerializeField] |         [field: SerializeField] | ||||||
|         public SerializableGuid ActorGuid { get; private set; } = SerializableGuid.New(); |         public SerializableGuid ActorGuid { get; private set; } = SerializableGuid.New(); | ||||||
|  |  | ||||||
|         public bool IsInitialized { get; private set; } |         bool m_IsPlaying = false; | ||||||
|  |         public bool IsPlaying { | ||||||
|         bool m_Simulate; |             get { | ||||||
|         public bool Simulate { |                 return m_IsPlaying; | ||||||
|             get => m_Simulate; |             } | ||||||
|  |  | ||||||
|             set { |             set { | ||||||
|                 if (m_Simulate == value) { |                 if (m_IsPlaying == value) { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 m_Simulate = value; |                 m_IsPlaying = value; | ||||||
|  |  | ||||||
|                 if (!IsInitialized) { |                 if (m_IsPlaying) { | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (m_Simulate) { |  | ||||||
|                     OnBeginPlay(); |                     OnBeginPlay(); | ||||||
|                 } else { |                 } else { | ||||||
|                     OnEndPlay(); |                     OnEndPlay(); | ||||||
| @@ -34,24 +27,10 @@ namespace RebootKit.Engine.Services.Simulation { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         async void Start() { |         public virtual void OnSpawned() { | ||||||
|             IsInitialized = false; |  | ||||||
|             await InitAsync(destroyCancellationToken); |  | ||||||
|             IsInitialized = true; |  | ||||||
|  |  | ||||||
|             if (Simulate) { |  | ||||||
|                 OnBeginPlay(); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         void Update() { |         public virtual void OnDespawned() { | ||||||
|             if (m_Simulate && IsInitialized) { |  | ||||||
|                 OnTick(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         protected virtual async UniTask InitAsync(CancellationToken cancellationToken) { |  | ||||||
|             await UniTask.Yield(cancellationToken); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public virtual void OnBeginPlay() { |         public virtual void OnBeginPlay() { | ||||||
| @@ -60,7 +39,7 @@ namespace RebootKit.Engine.Services.Simulation { | |||||||
|         public virtual void OnEndPlay() { |         public virtual void OnEndPlay() { | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public virtual void OnTick() { |         public virtual void OnTick(float deltaTime) { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1,7 +1,8 @@ | |||||||
| using System.Collections.Generic; | using System; | ||||||
| using System.Linq; | using System.Collections.Generic; | ||||||
| using System.Threading; | using System.Threading; | ||||||
| using Cysharp.Threading.Tasks; | using Cysharp.Threading.Tasks; | ||||||
|  | using R3; | ||||||
| using RebootKit.Engine.Foundation; | using RebootKit.Engine.Foundation; | ||||||
| using UnityEngine; | using UnityEngine; | ||||||
| using UnityEngine.AddressableAssets; | using UnityEngine.AddressableAssets; | ||||||
| @@ -12,8 +13,7 @@ using UnityEngine.SceneManagement; | |||||||
| using Logger = RebootKit.Engine.Foundation.Logger; | using Logger = RebootKit.Engine.Foundation.Logger; | ||||||
|  |  | ||||||
| namespace RebootKit.Engine.Services.Simulation { | namespace RebootKit.Engine.Services.Simulation { | ||||||
|     public interface IWorldContext { |     public interface IWorldContext { } | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public class WorldService : IService { |     public class WorldService : IService { | ||||||
|         static readonly Logger s_Logger = new Logger(nameof(WorldService)); |         static readonly Logger s_Logger = new Logger(nameof(WorldService)); | ||||||
| @@ -28,11 +28,28 @@ namespace RebootKit.Engine.Services.Simulation { | |||||||
|         WorldConfig m_Config; |         WorldConfig m_Config; | ||||||
|         AsyncOperationHandle<SceneInstance> m_SceneInstance; |         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; } |         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() { |         public void Dispose() { | ||||||
|  |             m_UpdateSubscription.Dispose(); | ||||||
|             Unload(); |             Unload(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -52,30 +69,19 @@ namespace RebootKit.Engine.Services.Simulation { | |||||||
|  |  | ||||||
|             foreach (GameObject root in m_SceneInstance.Result.Scene.GetRootGameObjects()) { |             foreach (GameObject root in m_SceneInstance.Result.Scene.GetRootGameObjects()) { | ||||||
|                 if (root.TryGetComponent(out IWorldContext worldContext)) { |                 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; |                     Context = worldContext; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 foreach (Actor actor in root.GetComponentsInChildren<Actor>()) { |                 foreach (Actor actor in root.GetComponentsInChildren<Actor>()) { | ||||||
|                     RegisterActor(actor); |                     m_Actors.Add(new ActorData(actor, false)); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             m_WorldState = WorldState.Loaded; |             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() { |         public void Unload() { | ||||||
|             KillAllActors(); |             KillAllActors(); | ||||||
|  |  | ||||||
| @@ -88,7 +94,13 @@ namespace RebootKit.Engine.Services.Simulation { | |||||||
|             Context = null; |             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); |             GameObject gameObject = await Addressables.InstantiateAsync(asset); | ||||||
|             if (cancellationToken.IsCancellationRequested) { |             if (cancellationToken.IsCancellationRequested) { | ||||||
|                 asset.ReleaseInstance(gameObject); |                 asset.ReleaseInstance(gameObject); | ||||||
| @@ -96,6 +108,9 @@ namespace RebootKit.Engine.Services.Simulation { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (gameObject.TryGetComponent(out TActor actor)) { |             if (gameObject.TryGetComponent(out TActor actor)) { | ||||||
|  |                 actor.OnSpawned(); | ||||||
|  |                 actor.IsPlaying = true; | ||||||
|  |                 m_Actors.Add(new ActorData(actor, true)); | ||||||
|                 return actor; |                 return actor; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -103,20 +118,52 @@ namespace RebootKit.Engine.Services.Simulation { | |||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public void RegisterActor(Actor actor) { |  | ||||||
|             m_Actors.Add(actor); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public void KillActor(Actor 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() { |         public void KillAllActors() { | ||||||
|             foreach (Actor actor in m_Actors) { |             foreach (ActorData actorData in m_Actors) { | ||||||
|                 Addressables.ReleaseInstance(actor.gameObject); |                 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(); |             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