Skip to content

Instantly share code, notes, and snippets.

@triktron
Created October 17, 2021 21:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save triktron/a6cdb6ace72bccc20d9ec6bc00461fde to your computer and use it in GitHub Desktop.
Save triktron/a6cdb6ace72bccc20d9ec6bc00461fde to your computer and use it in GitHub Desktop.
Priority system
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Triktron.Utils
{
#if UNITY_EDITOR
using UnityEditor;
using UnityEditorInternal;
[CustomPropertyDrawer(typeof(PrioritySystem))]
public class PrioritySystemDrawer : PropertyDrawer
{
private ReorderableList list;
private bool initialized = false;
private const float PAD_SIZE = 4f;
private PrioritySystem proprietySystem;
private void Init(SerializedProperty property)
{
initialized = true;
proprietySystem = fieldInfo.GetValue(property.serializedObject.targetObject) as PrioritySystem;
var Items = proprietySystem.States;
list = new ReorderableList(Items, typeof(List<PrioritySystem.State>), true, true, true, true);
list.drawElementCallback = DrawEllement;
list.drawHeaderCallback = (Rect rect) => {
EditorGUI.LabelField(rect, "States");
};
list.onCanRemoveCallback = (ReorderableList l) =>
{
return l.count > 0;
};
list.onReorderCallback = (ReorderableList l) =>
{
proprietySystem.RelableStates(true);
proprietySystem.Update(true);
};
list.onAddCallback = (ReorderableList l) =>
{
ReorderableList.defaultBehaviours.DoAddButton(l);
proprietySystem.RelableStates(true);
proprietySystem.Update(true);
};
list.onRemoveCallback = (ReorderableList l) =>
{
ReorderableList.defaultBehaviours.DoRemoveButton(l);
proprietySystem.RelableStates(true);
proprietySystem.Update(true);
};
}
private void DrawEllement(Rect rect, int index, bool isActive, bool isFocused)
{
var item = (PrioritySystem.State)list.list[index];
rect.y += 2;
var oldColor = GUI.color;
if (proprietySystem.GetTopEnabledIndex() == index) GUI.color = Color.cyan;
EditorGUI.BeginChangeCheck();
var enabledContent = new GUIContent("Enabled");
var enabledWidth = GUIStyle.none.CalcSize(enabledContent).x + PAD_SIZE;
EditorGUI.LabelField(new Rect(rect.x, rect.y, enabledWidth, EditorGUIUtility.singleLineHeight), "Enabled");
item.Enabled = EditorGUI.Toggle(new Rect(rect.x + enabledWidth, rect.y, 30, EditorGUIUtility.singleLineHeight), item.Enabled);
var nameContent = new GUIContent("Name");
var nameWidth = GUIStyle.none.CalcSize(nameContent).x + PAD_SIZE;
EditorGUI.LabelField(new Rect(rect.x + enabledWidth + EditorGUIUtility.singleLineHeight, rect.y, nameWidth, EditorGUIUtility.singleLineHeight), "Name");
item.Name = EditorGUI.DelayedTextField(new Rect(rect.x + enabledWidth + EditorGUIUtility.singleLineHeight + nameWidth, rect.y, rect.width - (enabledWidth + EditorGUIUtility.singleLineHeight + nameWidth), EditorGUIUtility.singleLineHeight), item.Name);
if (EditorGUI.EndChangeCheck()) proprietySystem.Update(true);
GUI.color = oldColor;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (!initialized) Init(property);
EditorGUI.BeginProperty(position, GUIContent.none, property);
{
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
list.DoList(position);
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (!initialized) Init(property);
return list.GetHeight();
}
}
#endif
[System.Serializable]
public class PrioritySystem
{
public List<State> States = new List<State>();
public delegate void UpdateEvent();
public event UpdateEvent OnUpdate;
public void Register(string name, int priority, object data = null)
{
States.Add(new State() { Name = name, Priority = priority, Data = data });
Update();
}
public void Remove(string name)
{
var index = States.FindIndex(s => s.Name == name);
if (index >= 0)
{
States.RemoveAt(index);
Update();
}
}
public void RelableStates(bool startZero = false)
{
if (startZero)
{
for (int i = 0; i < States.Count; i++) States[i].Priority = States.Count - i - 1;
}
else
{
if (States.Count <= 2) return;
var lastIndex = States[States.Count - 1].Priority;
for (int i = States.Count - 2; i >= 0; i--)
{
if (States[i].Priority <= lastIndex)
{
lastIndex++;
States[i].Priority = lastIndex;
}
else
{
lastIndex = States[i].Priority;
}
}
}
}
public void SortStates()
{
States.Sort((state1, state2) => state2.Priority - state1.Priority);
}
public State GetTopEnabled()
{
foreach (var state in States)
{
if (state.Enabled) return state;
}
return States.Last();
}
public int GetTopEnabledIndex()
{
for (int i = 0; i < States.Count; i++)
{
if (States[i].Enabled) return i;
}
return States.Count - 1;
}
public void SetStateEnabled(State state, bool enabled)
{
SetStateEnabled(States.FindIndex(s => s == state), enabled);
}
public void SetStateEnabled(int index, bool enabled)
{
var was = States[index].Enabled;
States[index].Enabled = enabled;
if (was != enabled) Update(true);
}
public void SetStateEnabled(string name, bool enabled)
{
var state = States.Find(s => s.Name == name);
if (state == null) return;
var was = state.Enabled;
state.Enabled = enabled;
if (was != enabled) Update(true);
}
public void Update(bool dontSort = false)
{
if (!dontSort)
{
SortStates();
RelableStates();
}
OnUpdate?.Invoke();
}
[Serializable]
public class State
{
public string Name;
public bool Enabled;
public int Priority;
public object Data;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment