projectEli/Assets/NeoFPS/Core/MotionGraphs/MotionGraphConnectable.cs
2022-11-06 20:28:33 -05:00

297 lines
9.2 KiB
C#

using System;
using UnityEngine;
using System.Collections.Generic;
using NeoCC;
using NeoSaveGames.Serialization;
namespace NeoFPS.CharacterMotion
{
public abstract class MotionGraphConnectable : ScriptableObject, IMotionGraphElement, INeoSerializableObject
{
private const float k_PositionClamp = 2000f;
#if UNITY_EDITOR
[HideInInspector] public Vector2 uiPosition = Vector2.zero;
[HideInInspector] public string defaultName = "NewState";
Dictionary<int, MotionGraphConnectable> m_KeyMap = null;
protected bool CheckSerializationKey(int key, MotionGraphConnectable connectable)
{
// Check if not initialised
if (key == 0)
return false;
// Values are tracked in the root
if (parent == null)
{
if (m_KeyMap == null)
m_KeyMap = new Dictionary<int, MotionGraphConnectable>();
// Check if it's already in use
MotionGraphConnectable found = null;
if (m_KeyMap.TryGetValue(key, out found))
{
return (found == connectable);
}
else
{
// Track key
m_KeyMap.Add(key, connectable);
return true;
}
}
else
return parent.CheckSerializationKey(key, connectable);
}
#endif
[SerializeField, HideInInspector] private MotionGraph m_Parent = null;
[SerializeField, HideInInspector] private List<MotionGraphConnection> m_Connections = new List<MotionGraphConnection>();
[SerializeField, HideInInspector] private List<MotionGraphBehaviour> m_Behaviours = new List<MotionGraphBehaviour>();
[SerializeField] private int m_SerializationKey = 0;
private static readonly NeoSerializationKey k_ElapsedKey = new NeoSerializationKey("elapsed");
private static readonly NeoSerializationKey k_EnabledKey = new NeoSerializationKey("enabled");
public bool active
{
get;
private set;
}
public float elapsedTime
{
get;
private set;
}
public int serializationKey
{
get { return m_SerializationKey; }
}
public virtual void OnValidate ()
{
// Remove invalid transitions
for (int i = m_Connections.Count; i > 0; --i)
{
if (m_Connections[i - 1] == null)
m_Connections.RemoveAt(i - 1);
else
{
if (!m_Connections[i - 1].isValid)
{
DestroyImmediate(m_Connections[i - 1], true);
m_Connections.RemoveAt(i - 1);
}
else
m_Connections[i - 1].OnValidate();
}
}
// Remove invalid behaviours
for (int i = m_Behaviours.Count; i > 0; --i)
{
if (m_Behaviours[i - 1] == null)
m_Behaviours.RemoveAt(i - 1);
else
m_Behaviours[i - 1].OnValidate();
}
#if UNITY_EDITOR
// Clamp position
uiPosition.x = Mathf.Clamp(uiPosition.x, -k_PositionClamp, k_PositionClamp);
uiPosition.y = Mathf.Clamp(uiPosition.y, -k_PositionClamp, k_PositionClamp);
// Check serialization key
if (parent != null)
{
while (!CheckSerializationKey(m_SerializationKey, this))
m_SerializationKey = UnityEngine.Random.Range(int.MinValue, int.MaxValue);
}
// Check behaviour serialization keys
List<int> behaviourKeys = new List<int>();
for (int i = 0; i < m_Behaviours.Count; ++i)
{
if (m_Behaviours[i].serializationKey == 0 || behaviourKeys.Contains(m_Behaviours[i].serializationKey))
m_Behaviours[i].GenerateSerializationKey();
}
#endif
}
public MotionGraph parent
{
get { return m_Parent; }
}
public IMotionController controller
{
get;
private set;
}
public INeoCharacterController characterController
{
get;
private set;
}
public List<MotionGraphConnection> connections
{
get { return m_Connections; }
}
public List<MotionGraphBehaviour> behaviours
{
get { return m_Behaviours; }
}
public virtual void Initialise (IMotionController c)
{
controller = c;
characterController = c.characterController;
for (int i = 0; i < m_Connections.Count; ++i)
m_Connections[i].Initialise(c);
for (int i = 0; i < m_Behaviours.Count; ++i)
m_Behaviours[i].Initialise(this);
}
public virtual bool CheckCanEnter()
{
return true;
}
public virtual void CheckReferences (IMotionGraphMap map)
{
m_Parent = map.Swap(m_Parent);
for (int i = 0; i < m_Connections.Count; ++i)
m_Connections[i] = map.Swap(m_Connections[i]);
for (int i = 0; i < m_Behaviours.Count; ++i)
m_Behaviours[i] = map.Swap(m_Behaviours[i]);
}
public virtual void Update ()
{
elapsedTime += Time.deltaTime;
for (int i = 0; i < m_Behaviours.Count; ++i)
{
if (m_Behaviours[i].enabled)
m_Behaviours[i].Update();
}
}
public virtual void OnEnter ()
{
active = true;
elapsedTime = 0f;
for (int i = 0; i < m_Behaviours.Count; ++i)
{
if (m_Behaviours[i].enabled)
m_Behaviours[i].OnEnter();
}
}
public virtual void OnExit ()
{
for (int i = 0; i < m_Behaviours.Count; ++i)
{
if (m_Behaviours[i].enabled)
m_Behaviours[i].OnExit();
}
elapsedTime = 0f;
active = false;
}
public bool IsChildOf (MotionGraph graph)
{
if (parent == graph)
return true;
if (parent == null)
return false;
return parent.IsChildOf(graph);
}
public static MotionGraph GetSharedParent (MotionGraphConnectable c1, MotionGraphConnectable c2)
{
if (c1 == null || c2 == null)
return null;
MotionGraph p = c1.parent;
while (p != null)
{
if (c2.IsChildOf(p))
return p;
p = p.parent;
}
return null;
}
public virtual void WriteProperties(INeoSerializer writer)
{
// Write properties
writer.WriteValue(k_ElapsedKey, elapsedTime);
// Write behaviours
for(int i = 0; i < m_Behaviours.Count; ++i)
{
writer.PushContext(SerializationContext.ObjectNeoSerialized, m_Behaviours[i].serializationKey);
writer.WriteValue(k_EnabledKey, m_Behaviours[i].enabled);
m_Behaviours[i].WriteProperties(writer);
writer.PopContext(SerializationContext.ObjectNeoSerialized);
}
// Write parent
if (parent != null)
{
writer.PushContext(SerializationContext.ObjectNeoSerialized, 0);
parent.WriteProperties(writer);
writer.PopContext(SerializationContext.ObjectNeoSerialized);
}
}
public virtual void ReadProperties(INeoDeserializer reader)
{
// Read properties
float floatResult;
if (reader.TryReadValue(k_ElapsedKey, out floatResult, elapsedTime))
elapsedTime = floatResult;
// Read behaviours
for (int i = 0; i < m_Behaviours.Count; ++i)
{
if (reader.PushContext(SerializationContext.ObjectNeoSerialized, m_Behaviours[i].serializationKey))
{
try
{
bool behaviourEnabled;
if (reader.TryReadValue(k_EnabledKey, out behaviourEnabled, true))
m_Behaviours[i].enabled = behaviourEnabled;
m_Behaviours[i].ReadProperties(reader);
}
finally
{
reader.PopContext(SerializationContext.ObjectNeoSerialized, m_Behaviours[i].serializationKey);
}
}
}
// Read parent
if (parent != null)
{
if (reader.PushContext(SerializationContext.ObjectNeoSerialized, 0))
{
try
{
parent.ReadProperties(reader);
}
finally
{
reader.PopContext(SerializationContext.ObjectNeoSerialized, 0);
}
}
}
}
}
}