idk
This commit is contained in:
@@ -1,24 +1,53 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace RebootKit.Engine.Animations {
|
||||
[Serializable]
|
||||
public class AnimationClipNode : IReAnimatorNode {
|
||||
[field: SerializeField] public string Name { get; private set; }
|
||||
|
||||
AnimationClipPlayable m_Playable;
|
||||
|
||||
bool m_PlayOnce;
|
||||
Action m_Callback;
|
||||
|
||||
public AnimationClip Clip;
|
||||
|
||||
public void Tick(float deltaTime) {
|
||||
if (m_Playable.GetPlayState() == PlayState.Paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_PlayOnce) {
|
||||
if (m_Playable.GetTime() >= m_Playable.GetAnimationClip().length) {
|
||||
m_Playable.Pause();
|
||||
|
||||
m_Callback?.Invoke();
|
||||
m_Callback = null;
|
||||
|
||||
m_PlayOnce = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IPlayable Build(PlayableGraph graph) {
|
||||
AnimationClipPlayable playable = AnimationClipPlayable.Create(graph, Clip);
|
||||
return playable;
|
||||
m_Playable = AnimationClipPlayable.Create(graph, Clip);
|
||||
return m_Playable;
|
||||
}
|
||||
|
||||
public bool TryFindChild(string name, out IReAnimatorNode node) {
|
||||
node = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void PlayOnceWithCallback(Action callback) {
|
||||
m_Playable.SetTime(0.0);
|
||||
m_Playable.Play();
|
||||
|
||||
m_Callback = callback;
|
||||
m_PlayOnce = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Runtime/Engine/Code/Animations/LayerMixerNode.cs
Normal file
88
Runtime/Engine/Code/Animations/LayerMixerNode.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace RebootKit.Engine.Animations {
|
||||
[Serializable]
|
||||
public class LayerMixerNode : IReAnimatorNode {
|
||||
[Serializable]
|
||||
struct LayerState {
|
||||
[SerializeReference] public IReAnimatorNode node;
|
||||
|
||||
public AvatarMask mask;
|
||||
public bool isAdditive;
|
||||
|
||||
[Range(0.0f, 1.0f)] public float targetWeight;
|
||||
[NonSerialized] public float CurrentWeight;
|
||||
}
|
||||
|
||||
[field: SerializeField] public string Name { get; private set; }
|
||||
|
||||
AnimationLayerMixerPlayable m_LayerMixer;
|
||||
|
||||
[SerializeField] float m_TransitionSpeed = 5.0f;
|
||||
[SerializeField] LayerState[] m_Layers;
|
||||
|
||||
public void Tick(float deltaTime) {
|
||||
for (int i = 0; i < m_Layers.Length; ++i){
|
||||
if (m_TransitionSpeed > 0.0f) {
|
||||
m_Layers[i].CurrentWeight = Mathf.MoveTowards(m_Layers[i].CurrentWeight,
|
||||
m_Layers[i].targetWeight,
|
||||
m_TransitionSpeed * deltaTime);
|
||||
} else {
|
||||
m_Layers[i].CurrentWeight = m_Layers[i].targetWeight;
|
||||
}
|
||||
|
||||
m_LayerMixer.SetInputWeight(i, m_Layers[i].CurrentWeight);
|
||||
|
||||
m_Layers[i].node.Tick(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public IPlayable Build(PlayableGraph graph) {
|
||||
m_LayerMixer = AnimationLayerMixerPlayable.Create(graph, m_Layers.Length);
|
||||
|
||||
for (int i = 0; i < m_Layers.Length; ++i) {
|
||||
IPlayable playable = m_Layers[i].node.Build(graph);
|
||||
|
||||
if (playable is AnimationMixerPlayable mixerPlayable) {
|
||||
m_LayerMixer.ConnectInput(i, mixerPlayable, 0, m_Layers[i].targetWeight);
|
||||
} else if (playable is AnimationClipPlayable clipPlayable) {
|
||||
m_LayerMixer.ConnectInput(i, clipPlayable, 0, m_Layers[i].targetWeight);
|
||||
} else if (playable is AnimationLayerMixerPlayable layerMixerPlayable) {
|
||||
m_LayerMixer.ConnectInput(i, layerMixerPlayable, 0, m_Layers[i].targetWeight);
|
||||
}
|
||||
|
||||
m_LayerMixer.SetLayerAdditive((uint)i, m_Layers[i].isAdditive);
|
||||
|
||||
if (m_Layers[i].mask != null) {
|
||||
m_LayerMixer.SetLayerMaskFromAvatarMask((uint)i, m_Layers[i].mask);
|
||||
}
|
||||
}
|
||||
|
||||
return m_LayerMixer;
|
||||
}
|
||||
|
||||
public bool TryFindChild(string name, out IReAnimatorNode node) {
|
||||
for (int i = 0; i < m_Layers.Length; i++) {
|
||||
if (m_Layers[i].node.Name.Equals(name, StringComparison.Ordinal)) {
|
||||
node = m_Layers[i].node;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_Layers[i].node.TryFindChild(name, out IReAnimatorNode childNode)) {
|
||||
node = childNode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
node = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetLayerWeight(int index, float weight) {
|
||||
m_Layers[index].targetWeight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Runtime/Engine/Code/Animations/LayerMixerNode.cs.meta
Normal file
3
Runtime/Engine/Code/Animations/LayerMixerNode.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 977149bceb2944b1b405035704d40f52
|
||||
timeCreated: 1754706607
|
||||
@@ -47,6 +47,8 @@ namespace RebootKit.Engine.Animations {
|
||||
m_Mixer.ConnectInput(i, mixerPlayable, 0, m_Inputs[i].targetWeight);
|
||||
} else if (playable is AnimationClipPlayable clipPlayable) {
|
||||
m_Mixer.ConnectInput(i, clipPlayable, 0, m_Inputs[i].targetWeight);
|
||||
} else if (playable is AnimationLayerMixerPlayable layerMixerPlayable) {
|
||||
m_Mixer.ConnectInput(i, layerMixerPlayable, 0, m_Inputs[i].targetWeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,54 +18,26 @@ namespace RebootKit.Engine.Animations {
|
||||
bool TryFindChild(string name, out IReAnimatorNode node);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class ReAnimatorLayer {
|
||||
public string name;
|
||||
public AvatarMask mask;
|
||||
public bool isAdditive;
|
||||
[Range(0.0f, 1.0f)] public float weight = 1.0f;
|
||||
|
||||
[SerializeReference] public IReAnimatorNode root;
|
||||
}
|
||||
|
||||
[DefaultExecutionOrder(-100)]
|
||||
public class ReAnimator : MonoBehaviour {
|
||||
static readonly Logger s_Logger = new Logger(nameof(ReAnimator));
|
||||
|
||||
[SerializeField] Animator m_Animator;
|
||||
[SerializeField] ReAnimatorLayer[] m_Layers;
|
||||
[SerializeField] LayerMixerNode m_Root;
|
||||
|
||||
PlayableGraph m_Graph;
|
||||
AnimationPlayableOutput m_Output;
|
||||
|
||||
AnimationLayerMixerPlayable m_LayerMixer;
|
||||
|
||||
void Awake() {
|
||||
Assert.IsNotNull(m_Animator, "Animator is not set");
|
||||
Assert.IsTrue(m_Layers.Length > 0, "Atleast one layer must be defined!");
|
||||
|
||||
m_Animator.runtimeAnimatorController = null;
|
||||
|
||||
m_Graph = PlayableGraph.Create(name);
|
||||
m_Output = AnimationPlayableOutput.Create(m_Graph, "Animation Output", m_Animator);
|
||||
|
||||
m_LayerMixer = AnimationLayerMixerPlayable.Create(m_Graph, m_Layers.Length);
|
||||
m_Output.SetSourcePlayable(m_LayerMixer, 0);
|
||||
|
||||
for (int i = 0; i < m_Layers.Length; ++i) {
|
||||
IPlayable playable = m_Layers[i].root.Build(m_Graph);
|
||||
|
||||
if (playable is AnimationMixerPlayable mixerPlayable) {
|
||||
m_LayerMixer.ConnectInput(i, mixerPlayable, 0, m_Layers[i].weight);
|
||||
} else if (playable is AnimationClipPlayable clipPlayable) {
|
||||
m_LayerMixer.ConnectInput(i, clipPlayable, 0, m_Layers[i].weight);
|
||||
}
|
||||
|
||||
m_LayerMixer.SetLayerAdditive((uint)i, m_Layers[i].isAdditive);
|
||||
|
||||
if (m_Layers[i].mask != null) {
|
||||
m_LayerMixer.SetLayerMaskFromAvatarMask((uint)i, m_Layers[i].mask);
|
||||
}
|
||||
if (m_Root.Build(m_Graph) is AnimationLayerMixerPlayable layerMixer) {
|
||||
m_Output.SetSourcePlayable(layerMixer, 0);
|
||||
}
|
||||
|
||||
m_Graph.Play();
|
||||
@@ -78,25 +50,16 @@ namespace RebootKit.Engine.Animations {
|
||||
}
|
||||
|
||||
void Update() {
|
||||
for (int i = 0; i < m_Layers.Length; i++) {
|
||||
m_Layers[i].root.Tick(Time.deltaTime);
|
||||
}
|
||||
m_Root.Tick(Time.deltaTime);
|
||||
}
|
||||
|
||||
public void SetLayerWeight(int layer, float weight) {
|
||||
m_Layers[layer].weight = weight;
|
||||
m_LayerMixer.SetInputWeight(layer, weight);
|
||||
m_Root.SetLayerWeight(layer, weight);
|
||||
}
|
||||
|
||||
public IReAnimatorNode FindNode(string nodeName) {
|
||||
foreach (ReAnimatorLayer layer in m_Layers) {
|
||||
if (layer.root.Name.Equals(nodeName, StringComparison.Ordinal)) {
|
||||
return layer.root;
|
||||
}
|
||||
|
||||
if (layer.root.TryFindChild(nodeName, out IReAnimatorNode childNode)) {
|
||||
return childNode;
|
||||
}
|
||||
if (m_Root.TryFindChild(nodeName, out IReAnimatorNode node)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
s_Logger.Error($"Couldn't find node with name: {nodeName}");
|
||||
|
||||
@@ -224,6 +224,15 @@ namespace RebootKit.Engine.Main {
|
||||
return Network.Actors.SpawnActor(assetReference, position, rotation);
|
||||
}
|
||||
|
||||
public static void DestroyActor(Actor actor) {
|
||||
if (actor == null) {
|
||||
s_Logger.Error("Cannot destroy actor. Actor is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
Network.Actors.DestroyActor(actor);
|
||||
}
|
||||
|
||||
public static Actor FindSpawnedActor(ushort actorID) {
|
||||
if (Network is null) {
|
||||
s_Logger.Error("NetworkSystemInstance is not initialized. Cannot find actor.");
|
||||
@@ -252,6 +261,16 @@ namespace RebootKit.Engine.Main {
|
||||
Network.SendPossessedActor(clientID, actorID);
|
||||
}
|
||||
|
||||
public static IEnumerable<Actor> Actors() {
|
||||
foreach (Actor actor in Network.Actors.InSceneActors) {
|
||||
yield return actor;
|
||||
}
|
||||
|
||||
foreach (Actor actor in Network.Actors.SpawnedActors) {
|
||||
yield return actor;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Service API
|
||||
// Services seems to be useless in the current architecture. Consider removing this API in the future.
|
||||
|
||||
3
Runtime/Engine/Code/Shaders.meta
Normal file
3
Runtime/Engine/Code/Shaders.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f2313df373f454f9f49020342ed07a8
|
||||
timeCreated: 1754968660
|
||||
22
Runtime/Engine/Code/Shaders/StencilMask.shader
Normal file
22
Runtime/Engine/Code/Shaders/StencilMask.shader
Normal file
@@ -0,0 +1,22 @@
|
||||
Shader "Unlit/StencilMask" {
|
||||
Properties {
|
||||
[IntRange] _StencilID("Stencil ID", Range(0, 255)) = 0
|
||||
}
|
||||
SubShader {
|
||||
Tags {
|
||||
"RenderType"="Opaque"
|
||||
"Queue"="Geometry-1"
|
||||
"RenderPipeline" = "UniversalPipeline"
|
||||
}
|
||||
|
||||
Pass {
|
||||
Blend Zero One
|
||||
ZWrite Off
|
||||
Stencil {
|
||||
Ref [_StencilID]
|
||||
Comp Always
|
||||
Pass Replace
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Runtime/Engine/Code/Shaders/StencilMask.shader.meta
Normal file
3
Runtime/Engine/Code/Shaders/StencilMask.shader.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20ca2eacae4c45dd891af0222af0295a
|
||||
timeCreated: 1754968671
|
||||
@@ -10,6 +10,7 @@ using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
namespace RebootKit.Engine.Simulation {
|
||||
@@ -233,16 +234,17 @@ namespace RebootKit.Engine.Simulation {
|
||||
}
|
||||
}
|
||||
|
||||
[DeclareFoldoutGroup("Actor")]
|
||||
public abstract class Actor : MonoBehaviour {
|
||||
static readonly Logger s_ActorLogger = new Logger(nameof(Actor));
|
||||
|
||||
[field: SerializeField, TriInspector.ReadOnly] public string SourceActorPath { get; internal set; } = "";
|
||||
[field: SerializeField, TriInspector.ReadOnly] public ulong ActorStaticID { get; internal set; }
|
||||
[field: SerializeField, TriInspector.ReadOnly] public ushort ActorID { get; internal set; }
|
||||
[field: SerializeField, TriInspector.ReadOnly, Group("Actor")] public string SourceActorPath { get; internal set; } = "";
|
||||
[field: SerializeField, TriInspector.ReadOnly, Group("Actor")] public ulong ActorStaticID { get; internal set; }
|
||||
[field: SerializeField, TriInspector.ReadOnly, Group("Actor")] public ushort ActorID { get; internal set; }
|
||||
|
||||
[NonSerialized] internal IActorData Data;
|
||||
|
||||
[SerializeField] string m_ActorName = "";
|
||||
[SerializeField, Group("Actor")] string m_ActorName = "";
|
||||
|
||||
public string ActorName {
|
||||
get {
|
||||
@@ -252,20 +254,20 @@ namespace RebootKit.Engine.Simulation {
|
||||
|
||||
internal bool IsLocalOnly;
|
||||
|
||||
[SerializeField] internal Rigidbody actorRigidbody;
|
||||
[SerializeField, Group("Actor")] internal Rigidbody actorRigidbody;
|
||||
[InfoBox("If empty, will use GetComponentsInChildren<Collider>() to find colliders.")]
|
||||
[SerializeField] Collider[] m_OverrideActorColliders;
|
||||
[SerializeField, Group("Actor")] Collider[] m_OverrideActorColliders;
|
||||
|
||||
[SerializeField] bool m_SetKinematicOnMount = true;
|
||||
[SerializeField] bool m_DisableCollidersOnMount = true;
|
||||
[SerializeField, Group("Actor")] bool m_SetKinematicOnMount = true;
|
||||
[SerializeField, Group("Actor")] bool m_DisableCollidersOnMount = true;
|
||||
|
||||
internal ActorFlags Flags = ActorFlags.None;
|
||||
|
||||
// @NOTE: Sync won't happen if actor is mounted to another actor.
|
||||
[SerializeField] internal bool syncTransform = true;
|
||||
[SerializeField] internal bool syncPosition = true;
|
||||
[SerializeField] internal bool syncRotation = true;
|
||||
[SerializeField] internal bool syncScale = false;
|
||||
[SerializeField, Group("Actor")] internal bool syncTransform = true;
|
||||
[SerializeField, Group("Actor")] internal bool syncPosition = true;
|
||||
[SerializeField, Group("Actor")] internal bool syncRotation = true;
|
||||
[SerializeField, Group("Actor")] internal bool syncScale = false;
|
||||
|
||||
class ActorClientState {
|
||||
public ulong LastSyncTick;
|
||||
@@ -286,7 +288,7 @@ namespace RebootKit.Engine.Simulation {
|
||||
public Quaternion localRotation;
|
||||
}
|
||||
|
||||
[SerializeField] AttachmentSocket[] m_AttachmentSockets;
|
||||
[SerializeField, Group("Actor")] AttachmentSocket[] m_AttachmentSockets;
|
||||
|
||||
// @NOTE: Master actor is the actor that this actor is attached to, if any.
|
||||
internal Actor MasterActor;
|
||||
@@ -296,6 +298,8 @@ namespace RebootKit.Engine.Simulation {
|
||||
public bool IsDataDirty { get; protected internal set; }
|
||||
|
||||
internal ActorsManager Manager;
|
||||
internal AsyncOperationHandle<GameObject> AssetHandle;
|
||||
|
||||
internal DateTime LastCoreStateSyncTime = DateTime.MinValue;
|
||||
|
||||
//
|
||||
|
||||
@@ -9,6 +9,7 @@ using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
@@ -21,14 +22,15 @@ namespace RebootKit.Engine.Simulation {
|
||||
|
||||
readonly NetworkSystem m_Network;
|
||||
|
||||
readonly List<Actor> m_InSceneActors = new List<Actor>();
|
||||
readonly List<Actor> m_SpawnedActors = new List<Actor>();
|
||||
internal readonly List<Actor> InSceneActors = new List<Actor>();
|
||||
internal readonly List<Actor> SpawnedActors = new List<Actor>();
|
||||
|
||||
// @NOTE: 0 is reserved for no actor so we should start assigning IDs from 1.
|
||||
ushort m_ActorIDCounter;
|
||||
List<ushort> m_ActorIDFreeList = new List<ushort>(ushort.MaxValue);
|
||||
|
||||
public ushort InSceneActorsCount { get { return (ushort) m_InSceneActors.Count; } }
|
||||
public ushort SpawnedActorsCount { get { return (ushort) m_SpawnedActors.Count; } }
|
||||
public ushort InSceneActorsCount { get { return (ushort) InSceneActors.Count; } }
|
||||
public ushort SpawnedActorsCount { get { return (ushort) SpawnedActors.Count; } }
|
||||
public int TotalActorsCount { get { return InSceneActorsCount + SpawnedActorsCount; } }
|
||||
|
||||
public ActorsManager(NetworkSystem networkSystem) {
|
||||
@@ -41,11 +43,11 @@ namespace RebootKit.Engine.Simulation {
|
||||
// @MARK: Update
|
||||
//
|
||||
public void Tick(float deltaTime) {
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
foreach (Actor actor in InSceneActors) {
|
||||
actor.OnClientTick(deltaTime);
|
||||
}
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
foreach (Actor actor in SpawnedActors) {
|
||||
actor.OnClientTick(deltaTime);
|
||||
}
|
||||
}
|
||||
@@ -58,8 +60,8 @@ namespace RebootKit.Engine.Simulation {
|
||||
return;
|
||||
}
|
||||
|
||||
TickActorsList(m_InSceneActors, dt);
|
||||
TickActorsList(m_SpawnedActors, dt);
|
||||
TickActorsList(InSceneActors, dt);
|
||||
TickActorsList(SpawnedActors, dt);
|
||||
}
|
||||
|
||||
void TickActorsList(List<Actor> actors, float deltaTime) {
|
||||
@@ -137,19 +139,14 @@ namespace RebootKit.Engine.Simulation {
|
||||
return null;
|
||||
}
|
||||
|
||||
GameObject actorObject = assetReference.InstantiateAsync(position, rotation).WaitForCompletion();
|
||||
Actor actor = actorObject.GetComponent<Actor>();
|
||||
if (actor is null) {
|
||||
s_Logger.Error($"GameObject {actorObject.name} does not have an Actor component.");
|
||||
Object.Destroy(actorObject);
|
||||
return null;
|
||||
}
|
||||
|
||||
actor.Manager = this;
|
||||
actor.SourceActorPath = assetReference.AssetGUID;
|
||||
actor.ActorID = actorID;
|
||||
actor.Data = actor.InternalCreateActorData();
|
||||
m_SpawnedActors.Add(actor);
|
||||
Actor actor = InstantiateActor(assetReference.AssetGUID,
|
||||
actorID,
|
||||
position,
|
||||
rotation,
|
||||
null,
|
||||
default);
|
||||
actor.IsLocalOnly = false;
|
||||
SpawnedActors.Add(actor);
|
||||
|
||||
foreach (NetworkClientState client in m_Network.Clients.Values) {
|
||||
if (client.IsServer) {
|
||||
@@ -166,6 +163,18 @@ namespace RebootKit.Engine.Simulation {
|
||||
}
|
||||
|
||||
bool TryGenerateNextActorID(out ushort actorID) {
|
||||
if (m_ActorIDFreeList.Count > 0) {
|
||||
actorID = m_ActorIDFreeList[0];
|
||||
m_ActorIDFreeList.RemoveAtSwapBack(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_ActorIDCounter >= ushort.MaxValue) {
|
||||
s_Logger.Error("Reached maximum number of actor ids which is: " + ushort.MaxValue);
|
||||
actorID = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ActorIDCounter += 1;
|
||||
actorID = m_ActorIDCounter;
|
||||
return true;
|
||||
@@ -178,8 +187,9 @@ namespace RebootKit.Engine.Simulation {
|
||||
}
|
||||
|
||||
m_ActorIDCounter = 0;
|
||||
m_ActorIDFreeList.Clear();
|
||||
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
foreach (Actor actor in InSceneActors) {
|
||||
if (!TryGenerateNextActorID(out ushort actorID)) {
|
||||
s_Logger.Error("Failed to generate actor ID. Probably reached the limit of 65535 actors.");
|
||||
return;
|
||||
@@ -189,33 +199,30 @@ namespace RebootKit.Engine.Simulation {
|
||||
}
|
||||
}
|
||||
|
||||
public Actor SpawnLocalOnlyActor(AssetReferenceGameObject assetReference, Vector3 position, Quaternion rotation) {
|
||||
if (!assetReference.RuntimeKeyIsValid()) {
|
||||
s_Logger.Error("Trying to spawn an actor with an invalid asset reference.");
|
||||
return null;
|
||||
public void DestroyActor(Actor actor) {
|
||||
if (actor.IsLocalOnly) {
|
||||
Object.Destroy(actor.gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryGenerateNextActorID(out ushort actorID)) {
|
||||
s_Logger.Error("Cannot spawn actor: Failed to generate next actor ID.");
|
||||
return null;
|
||||
if (!RR.IsServer()) {
|
||||
s_Logger.Error("Only the server can destroy non-local only actors");
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject actorObject = assetReference.InstantiateAsync(position, rotation).WaitForCompletion();
|
||||
Actor actor = actorObject.GetComponent<Actor>();
|
||||
if (actor is null) {
|
||||
s_Logger.Error($"GameObject {actorObject.name} does not have an Actor component.");
|
||||
Object.Destroy(actorObject);
|
||||
return null;
|
||||
if (InSceneActors.Contains(actor)) {
|
||||
s_Logger.Error("InScene actors cannot be destroyed!");
|
||||
return;
|
||||
}
|
||||
|
||||
actor.Manager = this;
|
||||
actor.IsLocalOnly = true;
|
||||
actor.SourceActorPath = assetReference.AssetGUID;
|
||||
actor.ActorID = actorID;
|
||||
actor.Data = actor.InternalCreateActorData();
|
||||
// m_SpawnedActors.Add(actor);
|
||||
for (int i = SpawnedActors.Count - 1; i >= 0; --i) {
|
||||
if (SpawnedActors[i] == actor) {
|
||||
m_ActorIDFreeList.Add(actor.ActorID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return actor;
|
||||
s_Logger.Error($"Failed to destroy an actor(name: {actor.ActorName}, id: {actor.ActorID})");
|
||||
}
|
||||
|
||||
//
|
||||
@@ -228,11 +235,11 @@ namespace RebootKit.Engine.Simulation {
|
||||
|
||||
actor.Manager = this;
|
||||
|
||||
m_InSceneActors.Add(actor);
|
||||
InSceneActors.Add(actor);
|
||||
}
|
||||
|
||||
Actor FindInSceneActorWithStaticID(ulong staticID) {
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
foreach (Actor actor in InSceneActors) {
|
||||
if (actor.ActorStaticID == staticID) {
|
||||
return actor;
|
||||
}
|
||||
@@ -242,13 +249,13 @@ namespace RebootKit.Engine.Simulation {
|
||||
}
|
||||
|
||||
public Actor FindActorByID(ushort actorID) {
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
foreach (Actor actor in InSceneActors) {
|
||||
if (actor.ActorID == actorID) {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
foreach (Actor actor in SpawnedActors) {
|
||||
if (actor.ActorID == actorID) {
|
||||
return actor;
|
||||
}
|
||||
@@ -258,15 +265,40 @@ namespace RebootKit.Engine.Simulation {
|
||||
}
|
||||
|
||||
public void CleanUp() {
|
||||
m_InSceneActors.Clear();
|
||||
InSceneActors.Clear();
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
foreach (Actor actor in SpawnedActors) {
|
||||
if (actor.OrNull() != null) {
|
||||
Object.Destroy(actor.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
m_SpawnedActors.Clear();
|
||||
SpawnedActors.Clear();
|
||||
}
|
||||
|
||||
public Actor SpawnLocalOnlyActor(AssetReferenceGameObject assetReference, Vector3 position, Quaternion rotation) {
|
||||
if (!assetReference.RuntimeKeyIsValid()) {
|
||||
s_Logger.Error("Trying to spawn an actor with an invalid asset reference.");
|
||||
return null;
|
||||
}
|
||||
|
||||
AsyncOperationHandle<GameObject> handle = Addressables.InstantiateAsync(assetReference, position, rotation);
|
||||
GameObject actorObject = handle.WaitForCompletion();
|
||||
Actor actor = actorObject.GetComponent<Actor>();
|
||||
if (actor == null) {
|
||||
s_Logger.Error($"GameObject {actorObject.name} does not have an Actor component.");
|
||||
handle.Release();
|
||||
return null;
|
||||
}
|
||||
|
||||
actor.Manager = this;
|
||||
actor.AssetHandle = handle;
|
||||
actor.IsLocalOnly = true;
|
||||
actor.SourceActorPath = assetReference.AssetGUID;
|
||||
actor.ActorID = 0;
|
||||
actor.Data = actor.InternalCreateActorData();
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
///
|
||||
@@ -355,50 +387,55 @@ namespace RebootKit.Engine.Simulation {
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnLocalActor(assetGUID.ToString(),
|
||||
coreState,
|
||||
stateData);
|
||||
InstantiateActor(assetGUID.ToString(),
|
||||
coreState.ActorID,
|
||||
coreState.Position,
|
||||
coreState.Rotation,
|
||||
coreState,
|
||||
stateData);
|
||||
}
|
||||
|
||||
void SpawnLocalActor(string guid,
|
||||
ActorCoreStateSnapshot coreStateSnapshot,
|
||||
NativeSlice<byte> stateData) {
|
||||
Actor InstantiateActor(string guid,
|
||||
ushort actorID,
|
||||
Vector3 position,
|
||||
Quaternion rotation,
|
||||
ActorCoreStateSnapshot? coreStateSnapshot,
|
||||
NativeSlice<byte> stateData) {
|
||||
AssetReferenceGameObject assetReference = new AssetReferenceGameObject(guid);
|
||||
if (!assetReference.RuntimeKeyIsValid()) {
|
||||
s_Logger.Error($"Invalid asset reference for actor with GUID {guid}");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
GameObject actorObject = assetReference
|
||||
.InstantiateAsync(coreStateSnapshot.Position, coreStateSnapshot.Rotation)
|
||||
.WaitForCompletion();
|
||||
if (actorObject == null) {
|
||||
s_Logger.Error($"Failed to instantiate actor with GUID {guid}");
|
||||
return;
|
||||
}
|
||||
AsyncOperationHandle<GameObject> handle = Addressables.InstantiateAsync(assetReference, position, rotation);
|
||||
GameObject actorObject = handle.WaitForCompletion();
|
||||
|
||||
Actor actor = actorObject.GetComponent<Actor>();
|
||||
if (actor is null) {
|
||||
if (actor == null) {
|
||||
s_Logger.Error($"GameObject {actorObject.name} does not have an Actor component.");
|
||||
Object.Destroy(actorObject);
|
||||
return;
|
||||
Addressables.ReleaseInstance(handle);
|
||||
return null;
|
||||
}
|
||||
|
||||
actor.Manager = this;
|
||||
actor.AssetHandle = handle;
|
||||
actor.SourceActorPath = guid;
|
||||
actor.ActorID = coreStateSnapshot.ActorID;
|
||||
actor.ActorID = actorID;
|
||||
actor.Data = actor.InternalCreateActorData();
|
||||
|
||||
if (!RR.IsServer()) {
|
||||
actor.InitializeOnClient();
|
||||
}
|
||||
|
||||
actor.RestoreCoreState(coreStateSnapshot);
|
||||
if (coreStateSnapshot.HasValue) {
|
||||
actor.RestoreCoreState(coreStateSnapshot.Value);
|
||||
}
|
||||
|
||||
if (stateData.Length > 0) {
|
||||
DataSerializationUtils.Deserialize(stateData, ref actor.Data);
|
||||
}
|
||||
|
||||
m_SpawnedActors.Add(actor);
|
||||
return actor;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -427,7 +464,7 @@ namespace RebootKit.Engine.Simulation {
|
||||
internal void WriteInSceneActorsStates(NetworkBufferWriter writer) {
|
||||
writer.Write((ushort) InSceneActorsCount);
|
||||
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
foreach (Actor actor in InSceneActors) {
|
||||
writer.Write(actor.ActorStaticID);
|
||||
writer.Write(actor.ActorID);
|
||||
actor.GetCoreStateSnapshot().Serialize(writer);
|
||||
@@ -468,7 +505,7 @@ namespace RebootKit.Engine.Simulation {
|
||||
s_Logger.Info("Actor id set to " + actor.ActorID);
|
||||
}
|
||||
|
||||
foreach (Actor inSceneActor in m_InSceneActors) {
|
||||
foreach (Actor inSceneActor in InSceneActors) {
|
||||
s_Logger.Info($"InSceneActor: StaticID={inSceneActor.ActorStaticID}, ID={inSceneActor.ActorID}, Path={inSceneActor.SourceActorPath}");
|
||||
}
|
||||
|
||||
@@ -481,7 +518,7 @@ namespace RebootKit.Engine.Simulation {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
foreach (Actor actor in SpawnedActors) {
|
||||
if (actor.OrNull() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user