You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

361 lines
12 KiB
C#

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using MalbersAnimations.Events;
using UnityEngine.Events;
using System;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditorInternal;
#endif
namespace MalbersAnimations.Conditions
{
[HelpURL("https://malbersanimations.gitbook.io/animal-controller/global-components/conditions")]
[AddComponentMenu("Malbers/Interactions/Conditions"),DisallowMultipleComponent]
public class MConditions : MonoBehaviour
{
public List<MCondition> conditions;
public UnityEvent Then = new UnityEvent();
public UnityEvent Else = new UnityEvent();
public bool debug;
[HideInInspector] public int SelectedState = -1;
/// <summary> Set the Target of the conditions depending of the Object Type</summary>
public virtual void SetConditionsTarget(UnityEngine.Object target)
{
foreach (var c in conditions)
{
c.SetTarget(target);
}
}
public void Evaluate() => TryEvaluate();
[ContextMenu("Show Conditions")]
private void ShowAllConditions()
{
var conditions = GetComponents<MCondition>();
foreach (var item in conditions)
{
item.hideFlags = HideFlags.None;
}
}
[ContextMenu("Hide Conditions")]
private void HideAllConditions()
{
var conditions = GetComponents<MCondition>();
foreach (var item in conditions)
{
item.hideFlags = HideFlags.HideInInspector;
}
}
public bool TryEvaluate()
{
if (conditions != null && conditions.Count > 0)
{
var c = conditions[0];
bool result = c.Evaluate(); //Get the first one
Debuggin(c, result);
for (int i = 1; i < conditions.Count; i++)
{
c = conditions[i];
var nextResult = c.Evaluate();
Debuggin(c, nextResult);
result = c.OrAnd ? (result || nextResult) : (result && nextResult);
}
if (result) Then.Invoke();
else Else.Invoke();
if (debug) Debug.Log($"[{name}] → Conditions Result → <B><color={(result ? "green" : "red")}>[{result}] </color></B>");
return result;
}
return false;
}
public void InvokeThen() => Then.Invoke();
public void InvokeElse() => Else.Invoke();
private void Debuggin(MCondition c, bool result)
{
if (debug) Debug.Log($"[{name}] → Cond: <B>[{c.GetType().Name}] {(c.invert ? "[!]" : " ")} → <color={(result ? "green" : "red")}>[{result}] </color></B>.");
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(MConditions))]
public class MConditionsEditor : Editor
{
SerializedObject so;
MConditions M;
SerializedProperty conditions, Then, Else, SelectedState, debug;
private List<Type> StatesType = new List<Type>();
private ReorderableList Reo_List_States;
private void OnEnable()
{
so = serializedObject;
M = (MConditions)target;
conditions = so.FindProperty("conditions");
Then = so.FindProperty("Then");
Else = so.FindProperty("Else");
debug = so.FindProperty("debug");
SelectedState = so.FindProperty("SelectedState");
Reo_List_States = new ReorderableList(serializedObject, conditions, true, true, true, true)
{
drawHeaderCallback = Draw_Header_State,
drawElementCallback = Draw_Element_State,
//onReorderCallbackWithDetails = OnReorderCallback_States_Details,
onAddCallback = OnAddCallback_State,
onRemoveCallback = OnRemove_Condition,
onSelectCallback = Selected_Cond,
};
StatesType.Clear();
StatesType = MTools.GetAllTypes<MCondition>();
Reo_List_States.index = SelectedState.intValue;
}
private void Draw_Header_State(Rect rect)
{
var r = new Rect(rect);
r.x += 13;
r.width -= 60;
EditorGUI.LabelField(r, new GUIContent(" Conditions", "Description or Name for the Condition"), EditorStyles.boldLabel);
Rect R_2 = new Rect(rect.width, rect.y, 25, EditorGUIUtility.singleLineHeight - 3);
MalbersEditor.DrawDebugIcon(R_2, debug);
}
private void Draw_Element_State(Rect rect, int index, bool isActive, bool isFocused)
{
var element = conditions.GetArrayElementAtIndex(index);
if (element != null && element.objectReferenceValue != null)
{
SerializedObject elementSo = new SerializedObject(element.objectReferenceValue);
elementSo.Update();
var name = elementSo.FindProperty("Name");
var OrAnd = elementSo.FindProperty("OrAnd");
// var invert = elementSo.FindProperty("invert");
var AndORWidth = 38;
// var InvertWidth = 45;
var elRect = new Rect(rect)
{
height = EditorGUIUtility.singleLineHeight,
y = rect.y + 2,
x = rect.x + AndORWidth + 2,
width = rect.width - AndORWidth - 2 - 2,
};
var AndOrRect = new Rect(rect)
{
height = EditorGUIUtility.singleLineHeight,
y = rect.y + 2,
width = AndORWidth,
};
var dC = GUI.color;
if (index != 0)
{
GUI.color = OrAnd.boolValue ? Color.cyan : Color.green;
OrAnd.boolValue = GUI.Toggle(AndOrRect, OrAnd.boolValue, new GUIContent(OrAnd.boolValue ? "OR" : "AND"), EditorStyles.miniButton);
GUI.color = dC;
}
var DC = GUI.color;
GUI.color = index == SelectedState.intValue ? Color.green : DC;
EditorGUI.PropertyField(elRect, name, GUIContent.none);
GUI.color = DC;
elementSo.ApplyModifiedProperties();
}
}
void OnDisable()
{
if (target == null)
{
foreach (var item in M.conditions)
{
DestroyImmediate(item); //Destroy all Monobehaviours added
}
}
}
private void OnAddCallback_State(ReorderableList list)
{
var addMenu = new GenericMenu();
for (int i = 0; i < StatesType.Count; i++)
{
Type st = StatesType[i];
//Fast Ugly get the name of the Asset thing
MCondition cond = M.gameObject.AddComponent(st) as MCondition;
var name = cond.DisplayName;
DestroyImmediate(cond);
addMenu.AddItem(new GUIContent(name), false, () => AddCondition(st,list.count));
}
addMenu.ShowAsContext();
}
private void AddCondition(Type st, int listcount)
{
MCondition cond = M.gameObject.AddComponent(st) as MCondition;
cond.hideFlags = HideFlags.HideInInspector;
conditions.serializedObject.Update();
var ind = Mathf.Clamp( conditions.arraySize, 0 ,conditions.arraySize);
cond.Name += $"({ind})";
conditions.InsertArrayElementAtIndex(ind);
conditions.GetArrayElementAtIndex(ind).objectReferenceValue = cond;
conditions.serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(target);
}
/// <summary> The ReordableList remove button has been pressed. Remove the selected ability.</summary>
private void OnRemove_Condition(ReorderableList list)
{
var objRef = conditions.GetArrayElementAtIndex(list.index).objectReferenceValue;
if (objRef != null)
{
var state = objRef as MCondition;
DestroyImmediate(state);
}
conditions.DeleteArrayElementAtIndex(list.index);
list.index -= 1;
SelectedState.intValue = list.index;
EditorUtility.SetDirty(target);
}
private void Selected_Cond(ReorderableList list) => SelectedState.intValue = list.index;
public override void OnInspectorGUI()
{
MalbersEditor.DrawDescription($"Global Conditions. Call MConditions.Evaluate() to invoke the response");
so.Update();
if (Application.isPlaying)
{
if (GUILayout.Button("Evaluate All"))
{
M.TryEvaluate();
}
}
Reo_List_States.DoLayoutList();
var index = Mathf.Clamp(Reo_List_States.index, -1, Reo_List_States.count);
if (index != -1)
{
var element = conditions.GetArrayElementAtIndex(index);
if (element != null)
{
using (new GUILayout.VerticalScope(EditorStyles.helpBox))
{
using (new GUILayout.HorizontalScope())
{
EditorGUI.indentLevel++;
element.isExpanded = GUILayout.Toggle(element.isExpanded,
$"Condition [{index}] : [{M.conditions[index].Name}] ",
EditorStyles.foldoutHeader, GUILayout.MinWidth(40));
EditorGUI.indentLevel--;
SerializedObject elementSo = new SerializedObject(element.objectReferenceValue);
var invert = elementSo.FindProperty("invert");
elementSo.Update();
var dC = GUI.color;
GUI.color = invert.boolValue ? Color.red : dC;
invert.boolValue = GUILayout.Toggle(invert.boolValue, new GUIContent("NOT", "Inverts the result of the condition"),
EditorStyles.miniButton, GUILayout.Width(38));
GUI.color = dC;
elementSo.ApplyModifiedProperties();
}
if (element.isExpanded)
{
MTools.DrawObjectReferenceInspector(element);
}
}
}
}
using (new GUILayout.VerticalScope(EditorStyles.helpBox))
{
Then.isExpanded = MalbersEditor.Foldout(Then.isExpanded, "Response");
if (Then.isExpanded)
{
EditorGUILayout.PropertyField(Then);
EditorGUILayout.PropertyField(Else);
}
}
so.ApplyModifiedProperties();
}
protected virtual void ShowConditionEditor(SerializedObject serializedObject)
{
var skip = 1;
var property = serializedObject.GetIterator();
property.NextVisible(true);
for (int i = 0; i < skip; i++)
property.NextVisible(false);
do
{
EditorGUILayout.PropertyField(property, true);
} while (property.NextVisible(false));
serializedObject.ApplyModifiedProperties();
}
}
#endif
}