增加A2WToolBox工具集,增加Launch场景核LaunchPanel
This commit is contained in:
8
Assets/A2WToolBox/3rd/StateMachine/Runtime/Drivers.meta
Normal file
8
Assets/A2WToolBox/3rd/StateMachine/Runtime/Drivers.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d19f3162564ec54aa39985d42873958
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Made With Monster Love (Pty) Ltd
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace MonsterLove.StateMachine
|
||||
{
|
||||
public class StateDriverRunner
|
||||
{
|
||||
public StateEvent FixedUpdate;
|
||||
public StateEvent Update;
|
||||
public StateEvent LateUpdate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8580b7087fdeecd4fb42025a957800f3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Made With Monster Love (Pty) Ltd
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace MonsterLove.StateMachine
|
||||
{
|
||||
public class StateDriverUnity
|
||||
{
|
||||
public StateEvent Awake;
|
||||
public StateEvent LateUpdate;
|
||||
public StateEvent<int> OnAnimatorIK;
|
||||
public StateEvent OnAnimatorMove;
|
||||
public StateEvent<bool> OnApplicationFocus;
|
||||
public StateEvent OnApplicationPause;
|
||||
public StateEvent OnApplicationQuit;
|
||||
public StateEvent<float[], int> OnAudioFilterRead;
|
||||
public StateEvent OnBecameInvisible;
|
||||
public StateEvent OnBecameVisible;
|
||||
public StateEvent<Collider> OnCollisionEnter;
|
||||
public StateEvent<Collision2D> OnCollisionEnter2D;
|
||||
public StateEvent<Collider> OnCollisionExit;
|
||||
public StateEvent<Collider2D> OnCollisionExit2D;
|
||||
public StateEvent<Collision> OnCollisionStay;
|
||||
public StateEvent<Collision2D> OnCollisionStay2D;
|
||||
public StateEvent OnConnectedToServer;
|
||||
public StateEvent<ControllerColliderHit> OnControllerColliderHit;
|
||||
public StateEvent OnDestroy;
|
||||
public StateEvent OnDisable;
|
||||
public StateEvent OnDrawGizmos;
|
||||
public StateEvent OnDrawGizmosSelected;
|
||||
public StateEvent OnEnable;
|
||||
public StateEvent OnGUI;
|
||||
public StateEvent<float> OnJointBreak;
|
||||
public StateEvent<Joint2D> OnJointBreak2D;
|
||||
public StateEvent OnMouseDown;
|
||||
public StateEvent OnMouseDrag;
|
||||
public StateEvent OnMouseEnter;
|
||||
public StateEvent OnMouseExit;
|
||||
public StateEvent OnMouseOver;
|
||||
public StateEvent OnMouseUp;
|
||||
public StateEvent OnMouseUpAsButton;
|
||||
public StateEvent<GameObject> OnParticleCollision;
|
||||
public StateEvent OnParticleSystemStopped;
|
||||
public StateEvent OnParticleTrigger;
|
||||
public StateEvent OnPostRender;
|
||||
public StateEvent OnPreCull;
|
||||
public StateEvent<RenderTexture, RenderTexture> OnRenderImage;
|
||||
public StateEvent OnRenderObject;
|
||||
public StateEvent OnTransformChildrenChanged;
|
||||
public StateEvent OnTransformParentChanged;
|
||||
public StateEvent<Collider> OnTriggerEnter;
|
||||
public StateEvent<Collider2D> OnTriggerEnter2D;
|
||||
public StateEvent<Collider> OnTriggerExit;
|
||||
public StateEvent<Collider2D> OnTriggerExit2D;
|
||||
public StateEvent<Collider> OnTriggerStay;
|
||||
public StateEvent<Collider2D> OnTriggerStay2D;
|
||||
public StateEvent OnValidate;
|
||||
public StateEvent OnWillRenderOjbect;
|
||||
public StateEvent Reset;
|
||||
public StateEvent Start;
|
||||
public StateEvent Update;
|
||||
|
||||
//Unity Networking Deprecated
|
||||
//public StateEvent<NetworkDisconnection> OnDisconnectedFromServer;
|
||||
//public StateEvent<NetworkConnectionError> OnFailedToConnect;
|
||||
//public StateEvent<NetworkConnectionError> OnFailedToConnectToMasterServer;
|
||||
//public StateEvent<MasterServerEvent> OnMasterServerEvent;
|
||||
//public StateEvent<NetworkMessageInfo> OnNetworkInstantiate;
|
||||
//public StateEvent<NetworkPlayer> OnPlayerConnected;
|
||||
//public StateEvent<NetworkPlayer> OnPlayerDisconnected;
|
||||
//public StateEvent<BitStream, NetworkMessageInfo> OnSerializeNetworkView;
|
||||
//public StateEvent OnSeverInitialized;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de0d37dba910471099253a3cc12484fb
|
||||
timeCreated: 1567762416
|
||||
3
Assets/A2WToolBox/3rd/StateMachine/Runtime/Events.meta
Normal file
3
Assets/A2WToolBox/3rd/StateMachine/Runtime/Events.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26a1a054d8aa3a94cac21be251c4e634
|
||||
timeCreated: 1568024794
|
||||
132
Assets/A2WToolBox/3rd/StateMachine/Runtime/Events/StateEvent.cs
Normal file
132
Assets/A2WToolBox/3rd/StateMachine/Runtime/Events/StateEvent.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Made With Monster Love (Pty) Ltd
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// Warning!
|
||||
// This is somewhat fragile Event pattern implementation. Recommended they aren't used outside of the state machine
|
||||
//
|
||||
namespace MonsterLove.StateMachine
|
||||
{
|
||||
public class StateEvent
|
||||
{
|
||||
private Func<int> getStateInt;
|
||||
private Func<bool> isInvokeAllowed;
|
||||
private Action[] routingTable;
|
||||
|
||||
public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity)
|
||||
{
|
||||
this.isInvokeAllowed = isInvokeAllowed;
|
||||
this.getStateInt = stateProvider;
|
||||
routingTable = new Action[capacity];
|
||||
}
|
||||
|
||||
internal void AddListener(int stateInt, Action listener)
|
||||
{
|
||||
routingTable[stateInt] = listener;
|
||||
}
|
||||
|
||||
public void Invoke()
|
||||
{
|
||||
if (isInvokeAllowed != null && !isInvokeAllowed())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Action call = routingTable[getStateInt()];
|
||||
if (call != null)
|
||||
{
|
||||
call();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class StateEvent<T>
|
||||
{
|
||||
private Func<int> getStateInt;
|
||||
private Func<bool> isInvokeAllowed;
|
||||
private Action<T>[] routingTable;
|
||||
|
||||
public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity)
|
||||
{
|
||||
this.isInvokeAllowed = isInvokeAllowed;
|
||||
this.getStateInt = stateProvider;
|
||||
routingTable = new Action<T>[capacity];
|
||||
}
|
||||
|
||||
internal void AddListener(int stateInt, Action<T> listener)
|
||||
{
|
||||
routingTable[stateInt] = listener;
|
||||
}
|
||||
|
||||
public void Invoke(T param)
|
||||
{
|
||||
if (isInvokeAllowed != null && !isInvokeAllowed())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Action<T> call = routingTable[getStateInt()];
|
||||
if (call != null)
|
||||
{
|
||||
call(param);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class StateEvent<T1, T2>
|
||||
{
|
||||
private Func<int> getStateInt;
|
||||
private Func<bool> isInvokeAllowed;
|
||||
private Action<T1,T2>[] routingTable;
|
||||
|
||||
public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity)
|
||||
{
|
||||
this.isInvokeAllowed = isInvokeAllowed;
|
||||
this.getStateInt = stateProvider;
|
||||
routingTable = new Action<T1, T2>[capacity];
|
||||
}
|
||||
|
||||
internal void AddListener(int stateInt, Action<T1, T2> listener)
|
||||
{
|
||||
routingTable[stateInt] = listener;
|
||||
}
|
||||
|
||||
public void Invoke(T1 param1, T2 param2)
|
||||
{
|
||||
if (isInvokeAllowed != null && !isInvokeAllowed())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Action<T1, T2> call = routingTable[getStateInt()];
|
||||
if (call != null)
|
||||
{
|
||||
call(param1, param2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a130ac4a15eb4a0cabf018a385e09999
|
||||
timeCreated: 1568024803
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "MonsterLove.StateMachine.Runtime",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39f9fc2c98cf6654498562b4bdd17a1e
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
659
Assets/A2WToolBox/3rd/StateMachine/Runtime/StateMachine.cs
Normal file
659
Assets/A2WToolBox/3rd/StateMachine/Runtime/StateMachine.cs
Normal file
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Made With Monster Love (Pty) Ltd
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
using Object = System.Object;
|
||||
|
||||
namespace MonsterLove.StateMachine
|
||||
{
|
||||
public enum StateTransition
|
||||
{
|
||||
Safe,
|
||||
Overwrite,
|
||||
}
|
||||
|
||||
public interface IStateMachine<TDriver>
|
||||
{
|
||||
MonoBehaviour Component { get; }
|
||||
TDriver Driver { get; }
|
||||
bool IsInTransition { get; }
|
||||
}
|
||||
|
||||
public class StateMachine<TState> : StateMachine<TState, StateDriverRunner> where TState : struct, IConvertible, IComparable
|
||||
{
|
||||
public StateMachine(MonoBehaviour component) : base(component)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class StateMachine<TState, TDriver> : IStateMachine<TDriver> where TState : struct, IConvertible, IComparable where TDriver : class, new()
|
||||
{
|
||||
public event Action<TState> Changed;
|
||||
|
||||
public bool reenter = false;
|
||||
private MonoBehaviour component;
|
||||
|
||||
private StateMapping<TState, TDriver> lastState;
|
||||
private StateMapping<TState, TDriver> currentState;
|
||||
private StateMapping<TState, TDriver> destinationState;
|
||||
private StateMapping<TState, TDriver> queuedState;
|
||||
private TDriver rootDriver;
|
||||
|
||||
private Dictionary<object, StateMapping<TState, TDriver>> stateLookup;
|
||||
private Func<TState, int> enumConverter;
|
||||
|
||||
private bool isInTransition = false;
|
||||
private IEnumerator currentTransition;
|
||||
private IEnumerator exitRoutine;
|
||||
private IEnumerator enterRoutine;
|
||||
private IEnumerator queuedChange;
|
||||
|
||||
private static BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
|
||||
#region Initialization
|
||||
|
||||
public StateMachine(MonoBehaviour component)
|
||||
{
|
||||
this.component = component;
|
||||
|
||||
//Compiler shenanigans to get ints from generic enums
|
||||
Func<int, int> identity = Identity;
|
||||
enumConverter = Delegate.CreateDelegate(typeof(Func<TState, int>), identity.Method) as Func<TState, int>;
|
||||
|
||||
//Define States
|
||||
var enumValues = Enum.GetValues(typeof(TState));
|
||||
if (enumValues.Length < 1)
|
||||
{
|
||||
throw new ArgumentException("Enum provided to Initialize must have at least 1 visible definition");
|
||||
}
|
||||
|
||||
var enumBackingType = Enum.GetUnderlyingType(typeof(TState));
|
||||
if(enumBackingType != typeof(int))
|
||||
{
|
||||
throw new ArgumentException("Only enums with an underlying type of int are supported");
|
||||
}
|
||||
|
||||
//Find all items in Driver class
|
||||
// public class Driver
|
||||
// {
|
||||
// StateEvent Foo; <- Selected
|
||||
// StateEvent<int> Boo; <- Selected
|
||||
// float x; <- Throw exception
|
||||
// }
|
||||
List<FieldInfo> eventFields = GetFilteredFields(typeof(TDriver), "MonsterLove.StateMachine.StateEvent");
|
||||
Dictionary<string, FieldInfo> eventFieldsLookup = CreateFieldsLookup(eventFields);
|
||||
|
||||
//Instantiate driver
|
||||
// driver = new Driver();
|
||||
// for each StateEvent:
|
||||
// StateEvent foo = new StateEvent(isAllowed, getStateInt, capacity);
|
||||
rootDriver = CreateDriver(IsDispatchAllowed, GetStateInt, enumValues.Length, eventFields);
|
||||
|
||||
// Create a state mapping for each state defined in the enum
|
||||
stateLookup = CreateStateLookup(this, enumValues);
|
||||
|
||||
//Collect methods in target component
|
||||
MethodInfo[] methods = component.GetType().GetMethods(bindingFlags);
|
||||
|
||||
//Bind methods to states
|
||||
for (int i = 0; i < methods.Length; i++)
|
||||
{
|
||||
TState state;
|
||||
string evtName;
|
||||
if (!ParseName(methods[i], out state, out evtName))
|
||||
{
|
||||
continue; //Skip methods where State_Event name convention could not be parsed
|
||||
}
|
||||
|
||||
StateMapping<TState, TDriver> mapping = stateLookup[state];
|
||||
|
||||
if (eventFieldsLookup.ContainsKey(evtName))
|
||||
{
|
||||
//Bind methods defined in TDriver
|
||||
// driver.Foo.AddListener(StateOne_Foo);
|
||||
FieldInfo eventField = eventFieldsLookup[evtName];
|
||||
BindEvents(rootDriver, component, state, enumConverter(state), methods[i], eventField);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Bind Enter, Exit and Finally Methods
|
||||
BindEventsInternal(mapping, component, methods[i], evtName);
|
||||
}
|
||||
}
|
||||
|
||||
//Create nil state mapping
|
||||
currentState = null;
|
||||
}
|
||||
|
||||
static List<FieldInfo> GetFilteredFields(Type type, string searchTerm)
|
||||
{
|
||||
List<FieldInfo> list = new List<FieldInfo>();
|
||||
|
||||
FieldInfo[] fields = type.GetFields(bindingFlags);
|
||||
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
FieldInfo item = fields[i];
|
||||
if (item.FieldType.ToString().Contains(searchTerm))
|
||||
{
|
||||
list.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(string.Format("{0} contains unsupported type {1}", type, item.FieldType));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static Dictionary<string, FieldInfo> CreateFieldsLookup(List<FieldInfo> fields)
|
||||
{
|
||||
var dict = new Dictionary<string, FieldInfo>();
|
||||
|
||||
for (int i = 0; i < fields.Count; i++)
|
||||
{
|
||||
FieldInfo item = fields[i];
|
||||
|
||||
dict.Add(item.Name, item);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
static Dictionary<object, StateMapping<TState, TDriver>> CreateStateLookup(StateMachine<TState, TDriver> fsm, Array values)
|
||||
{
|
||||
var stateLookup = new Dictionary<object, StateMapping<TState, TDriver>>();
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
var mapping = new StateMapping<TState, TDriver>(fsm, (TState) values.GetValue(i), fsm.GetState);
|
||||
stateLookup.Add(mapping.state, mapping);
|
||||
}
|
||||
|
||||
return stateLookup;
|
||||
}
|
||||
|
||||
static TDriver CreateDriver(Func<bool> isInvokeAllowedCallback, Func<int> getStateIntCallback, int capacity, List<FieldInfo> fieldInfos)
|
||||
{
|
||||
if (fieldInfos == null)
|
||||
{
|
||||
throw new ArgumentException(string.Format("Arguments cannot be null. Callback {0} fieldInfos {1}", isInvokeAllowedCallback, fieldInfos));
|
||||
}
|
||||
|
||||
TDriver driver = new TDriver();
|
||||
|
||||
for (int i = 0; i < fieldInfos.Count; i++)
|
||||
{
|
||||
//driver.Event = new StateEvent(callback)
|
||||
FieldInfo fieldInfo = fieldInfos[i]; //Event
|
||||
ConstructorInfo constructorInfo = fieldInfo.FieldType.GetConstructor(new Type[] {typeof(Func<bool>), typeof(Func<int>), typeof(int)}); //StateEvent(Func<Bool> invokeAllowed, Func<in> getState, int capacity)
|
||||
object obj = constructorInfo.Invoke(new object[] {isInvokeAllowedCallback, getStateIntCallback, capacity}); //obj = new StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity);
|
||||
fieldInfo.SetValue(driver, obj); //driver.Event = obj;
|
||||
}
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
static bool ParseName(MethodInfo methodInfo, out TState state, out string eventName)
|
||||
{
|
||||
state = default(TState);
|
||||
eventName = null;
|
||||
|
||||
if (methodInfo.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Length != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string name = methodInfo.Name;
|
||||
int index = name.IndexOf('_');
|
||||
|
||||
//Ignore functions without an underscore
|
||||
if (index < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string stateName = name.Substring(0, index);
|
||||
eventName = name.Substring(index + 1);
|
||||
|
||||
try
|
||||
{
|
||||
state = (TState) Enum.Parse(typeof(TState), stateName);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
//Not an method as listed in the state enum
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void BindEvents(TDriver driver, Component component, TState state, int stateInt, MethodInfo stateTargetDef, FieldInfo driverEvtDef)
|
||||
{
|
||||
var genericTypes = driverEvtDef.FieldType.GetGenericArguments(); //get T1,T2,...TN from StateEvent<T1,T2,...TN>
|
||||
var actionType = GetActionType(genericTypes); //typeof(Action<T1,T2,...TN>)
|
||||
|
||||
//evt.AddListener(State_Method);
|
||||
var obj = driverEvtDef.GetValue(driver); //driver.Foo
|
||||
var addMethodInfo = driverEvtDef.FieldType.GetMethod("AddListener", bindingFlags); // driver.Foo.AddListener
|
||||
|
||||
Delegate del = null;
|
||||
try
|
||||
{
|
||||
del = Delegate.CreateDelegate(actionType, component, stateTargetDef);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
throw new ArgumentException(string.Format("State ({0}_{1}) requires a callback of type: {2}, type found: {3}", state, driverEvtDef.Name, actionType, stateTargetDef));
|
||||
}
|
||||
|
||||
addMethodInfo.Invoke(obj, new object[] {stateInt, del}); //driver.Foo.AddListener(stateInt, component.State_Event);
|
||||
}
|
||||
|
||||
static void BindEventsInternal(StateMapping<TState, TDriver> targetState, Component component, MethodInfo method, string evtName)
|
||||
{
|
||||
switch (evtName)
|
||||
{
|
||||
case "Enter":
|
||||
if (method.ReturnType == typeof(IEnumerator))
|
||||
{
|
||||
targetState.hasEnterRoutine = true;
|
||||
targetState.EnterRoutine = CreateDelegate<Func<IEnumerator>>(method, component);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetState.hasEnterRoutine = false;
|
||||
targetState.EnterCall = CreateDelegate<Action>(method, component);
|
||||
}
|
||||
|
||||
break;
|
||||
case "Exit":
|
||||
if (method.ReturnType == typeof(IEnumerator))
|
||||
{
|
||||
targetState.hasExitRoutine = true;
|
||||
targetState.ExitRoutine = CreateDelegate<Func<IEnumerator>>(method, component);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetState.hasExitRoutine = false;
|
||||
targetState.ExitCall = CreateDelegate<Action>(method, component);
|
||||
}
|
||||
|
||||
break;
|
||||
case "Finally":
|
||||
targetState.Finally = CreateDelegate<Action>(method, component);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static V CreateDelegate<V>(MethodInfo method, Object target) where V : class
|
||||
{
|
||||
var ret = (Delegate.CreateDelegate(typeof(V), target, method) as V);
|
||||
|
||||
if (ret == null)
|
||||
{
|
||||
throw new ArgumentException("Unable to create delegate for method called " + method.Name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Type GetActionType(Type[] genericArgs)
|
||||
{
|
||||
switch (genericArgs.Length)
|
||||
{
|
||||
case 0:
|
||||
return typeof(Action);
|
||||
case 1:
|
||||
return typeof(Action<>).MakeGenericType(genericArgs);
|
||||
case 2:
|
||||
return typeof(Action<,>).MakeGenericType(genericArgs);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(string.Format("Cannot create Action Type with {0} type arguments", genericArgs.Length));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ChangeStates
|
||||
|
||||
public void ChangeState(TState newState)
|
||||
{
|
||||
ChangeState(newState, StateTransition.Safe);
|
||||
}
|
||||
|
||||
public void ChangeState(TState newState, StateTransition transition)
|
||||
{
|
||||
if (stateLookup == null)
|
||||
{
|
||||
throw new Exception("States have not been configured, please call initialized before trying to set state");
|
||||
}
|
||||
|
||||
if (!stateLookup.ContainsKey(newState))
|
||||
{
|
||||
throw new Exception("No state with the name " + newState.ToString() + " can be found. Please make sure you are called the correct type the statemachine was initialized with");
|
||||
}
|
||||
|
||||
var nextState = stateLookup[newState];
|
||||
|
||||
if (!reenter && currentState == nextState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Cancel any queued changes.
|
||||
if (queuedChange != null)
|
||||
{
|
||||
component.StopCoroutine(queuedChange);
|
||||
queuedChange = null;
|
||||
}
|
||||
|
||||
switch (transition)
|
||||
{
|
||||
//case StateMachineTransition.Blend:
|
||||
//Do nothing - allows the state transitions to overlap each other. This is a dumb idea, as previous state might trigger new changes.
|
||||
//A better way would be to start the two couroutines at the same time. IE don't wait for exit before starting start.
|
||||
//How does this work in terms of overwrite?
|
||||
//Is there a way to make this safe, I don't think so?
|
||||
//break;
|
||||
case StateTransition.Safe:
|
||||
if (isInTransition)
|
||||
{
|
||||
if (exitRoutine != null) //We are already exiting current state on our way to our previous target state
|
||||
{
|
||||
//Overwrite with our new target
|
||||
destinationState = nextState;
|
||||
return;
|
||||
}
|
||||
|
||||
if (enterRoutine != null) //We are already entering our previous target state. Need to wait for that to finish and call the exit routine.
|
||||
{
|
||||
//Damn, I need to test this hard
|
||||
queuedChange = WaitForPreviousTransition(nextState);
|
||||
component.StartCoroutine(queuedChange);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case StateTransition.Overwrite:
|
||||
if (currentTransition != null)
|
||||
{
|
||||
component.StopCoroutine(currentTransition);
|
||||
}
|
||||
|
||||
if (exitRoutine != null)
|
||||
{
|
||||
component.StopCoroutine(exitRoutine);
|
||||
}
|
||||
|
||||
if (enterRoutine != null)
|
||||
{
|
||||
component.StopCoroutine(enterRoutine);
|
||||
}
|
||||
|
||||
//Note: if we are currently in an EnterRoutine and Exit is also a routine, this will be skipped in ChangeToNewStateRoutine()
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if ((currentState != null && currentState.hasExitRoutine) || nextState.hasEnterRoutine)
|
||||
{
|
||||
isInTransition = true;
|
||||
currentTransition = ChangeToNewStateRoutine(nextState, transition);
|
||||
component.StartCoroutine(currentTransition);
|
||||
}
|
||||
else //Same frame transition, no coroutines are present
|
||||
{
|
||||
destinationState = nextState; //Assign here so Exit() has a valid reference
|
||||
|
||||
if (currentState != null)
|
||||
{
|
||||
currentState.ExitCall();
|
||||
currentState.Finally();
|
||||
}
|
||||
|
||||
lastState = currentState;
|
||||
currentState = destinationState;
|
||||
if (currentState != null)
|
||||
{
|
||||
currentState.EnterCall();
|
||||
if (Changed != null)
|
||||
{
|
||||
Changed((TState) currentState.state);
|
||||
}
|
||||
}
|
||||
|
||||
isInTransition = false;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator ChangeToNewStateRoutine(StateMapping<TState, TDriver> newState, StateTransition transition)
|
||||
{
|
||||
destinationState = newState; //Cache this so that we can overwrite it and hijack a transition
|
||||
|
||||
if (currentState != null)
|
||||
{
|
||||
if (currentState.hasExitRoutine)
|
||||
{
|
||||
exitRoutine = currentState.ExitRoutine();
|
||||
|
||||
if (exitRoutine != null && transition != StateTransition.Overwrite) //Don't wait for exit if we are overwriting
|
||||
{
|
||||
yield return component.StartCoroutine(exitRoutine);
|
||||
}
|
||||
|
||||
exitRoutine = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentState.ExitCall();
|
||||
}
|
||||
|
||||
currentState.Finally();
|
||||
}
|
||||
|
||||
lastState = currentState;
|
||||
currentState = destinationState;
|
||||
|
||||
if (currentState != null)
|
||||
{
|
||||
if (currentState.hasEnterRoutine)
|
||||
{
|
||||
enterRoutine = currentState.EnterRoutine();
|
||||
|
||||
if (enterRoutine != null)
|
||||
{
|
||||
yield return component.StartCoroutine(enterRoutine);
|
||||
}
|
||||
|
||||
enterRoutine = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentState.EnterCall();
|
||||
}
|
||||
|
||||
//Broadcast change only after enter transition has begun.
|
||||
if (Changed != null)
|
||||
{
|
||||
Changed((TState) currentState.state);
|
||||
}
|
||||
}
|
||||
|
||||
isInTransition = false;
|
||||
}
|
||||
|
||||
IEnumerator WaitForPreviousTransition(StateMapping<TState, TDriver> nextState)
|
||||
{
|
||||
queuedState = nextState; //Cache this so fsm.NextState is accurate;
|
||||
|
||||
while (isInTransition)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
queuedState = null;
|
||||
ChangeState((TState) nextState.state);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Helpers
|
||||
|
||||
public bool LastStateExists
|
||||
{
|
||||
get { return lastState != null; }
|
||||
}
|
||||
|
||||
public TState LastState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastState == null)
|
||||
{
|
||||
throw new NullReferenceException("LastState cannot be accessed before ChangeState() has been called at least twice");
|
||||
}
|
||||
|
||||
return (TState) lastState.state;
|
||||
}
|
||||
}
|
||||
|
||||
public TState NextState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (queuedState != null) //In safe mode sometimes we need to wait for the destination state to complete, and will be stored in queued state
|
||||
{
|
||||
return (TState) queuedState.state;
|
||||
}
|
||||
|
||||
if (destinationState == null)
|
||||
{
|
||||
return State;
|
||||
}
|
||||
|
||||
return (TState) destinationState.state;
|
||||
}
|
||||
}
|
||||
|
||||
public TState State
|
||||
{
|
||||
get
|
||||
{
|
||||
if (currentState == null)
|
||||
{
|
||||
throw new NullReferenceException("State cannot be accessed before ChangeState() has been called at least once");
|
||||
}
|
||||
|
||||
return (TState) currentState.state;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInTransition
|
||||
{
|
||||
get { return isInTransition; }
|
||||
}
|
||||
|
||||
public TDriver Driver
|
||||
{
|
||||
get { return rootDriver; }
|
||||
}
|
||||
|
||||
public MonoBehaviour Component
|
||||
{
|
||||
get { return component; }
|
||||
}
|
||||
|
||||
//format as method so can be passed as Func<TState>
|
||||
private TState GetState()
|
||||
{
|
||||
return State;
|
||||
}
|
||||
|
||||
private int GetStateInt()
|
||||
{
|
||||
return enumConverter(State);
|
||||
}
|
||||
|
||||
//Compiler shenanigans to get ints from generic enums
|
||||
private static int Identity(int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
private bool IsDispatchAllowed()
|
||||
{
|
||||
if (currentState == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsInTransition)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static API
|
||||
|
||||
//Static Methods
|
||||
|
||||
/// <summary>
|
||||
/// Inspects a MonoBehaviour for state methods as defined by the supplied Enum, and returns a stateMachine instance used to transition states.
|
||||
/// </summary>
|
||||
/// <param name="component">The component with defined state methods</param>
|
||||
/// <returns>A valid stateMachine instance to manage MonoBehaviour state transitions</returns>
|
||||
public static StateMachine<TState> Initialize(MonoBehaviour component)
|
||||
{
|
||||
var engine = component.GetComponent<StateMachineRunner>();
|
||||
if (engine == null) engine = component.gameObject.AddComponent<StateMachineRunner>();
|
||||
|
||||
return engine.Initialize<TState>(component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inspects a MonoBehaviour for state methods as defined by the supplied Enum, and returns a stateMachine instance used to transition states.
|
||||
/// </summary>
|
||||
/// <param name="component">The component with defined state methods</param>
|
||||
/// <param name="startState">The default starting state</param>
|
||||
/// <returns>A valid stateMachine instance to manage MonoBehaviour state transitions</returns>
|
||||
public static StateMachine<TState> Initialize(MonoBehaviour component, TState startState)
|
||||
{
|
||||
var engine = component.GetComponent<StateMachineRunner>();
|
||||
if (engine == null) engine = component.gameObject.AddComponent<StateMachineRunner>();
|
||||
|
||||
return engine.Initialize<TState>(component, startState);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6da868d186fa05342bd37fb8e63d3666
|
||||
timeCreated: 1457605040
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
110
Assets/A2WToolBox/3rd/StateMachine/Runtime/StateMachineRunner.cs
Normal file
110
Assets/A2WToolBox/3rd/StateMachine/Runtime/StateMachineRunner.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Made With Monster Love (Pty) Ltd
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MonsterLove.StateMachine
|
||||
{
|
||||
public class StateMachineRunner : MonoBehaviour
|
||||
{
|
||||
private List<IStateMachine<StateDriverRunner>> stateMachineList = new List<IStateMachine<StateDriverRunner>>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a stateMachine token object which is used to managed to the state of a monobehaviour.
|
||||
/// </summary>
|
||||
/// <typeparam name="TState">An Enum listing different state transitions</typeparam>
|
||||
/// <param name="component">The component whose state will be managed</param>
|
||||
/// <returns></returns>
|
||||
public StateMachine<TState> Initialize<TState>(MonoBehaviour component) where TState : struct, IConvertible, IComparable
|
||||
{
|
||||
var fsm = new StateMachine<TState>(component);
|
||||
|
||||
stateMachineList.Add(fsm);
|
||||
|
||||
return fsm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a stateMachine token object which is used to managed to the state of a monobehaviour. Will automatically transition the startState
|
||||
/// </summary>
|
||||
/// <typeparam name="TState">An Enum listing different state transitions</typeparam>
|
||||
/// <param name="component">The component whose state will be managed</param>
|
||||
/// <param name="startState">The default start state</param>
|
||||
/// <returns></returns>
|
||||
public StateMachine<TState> Initialize<TState>(MonoBehaviour component, TState startState) where TState : struct, IConvertible, IComparable
|
||||
{
|
||||
var fsm = Initialize<TState>(component);
|
||||
|
||||
fsm.ChangeState(startState);
|
||||
|
||||
return fsm;
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
for (int i = 0; i < stateMachineList.Count; i++)
|
||||
{
|
||||
var fsm = stateMachineList[i];
|
||||
if (!fsm.IsInTransition && fsm.Component.enabled)
|
||||
{
|
||||
fsm.Driver.FixedUpdate.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
for (int i = 0; i < stateMachineList.Count; i++)
|
||||
{
|
||||
var fsm = stateMachineList[i];
|
||||
if (!fsm.IsInTransition && fsm.Component.enabled)
|
||||
{
|
||||
fsm.Driver.Update.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
for (int i = 0; i < stateMachineList.Count; i++)
|
||||
{
|
||||
var fsm = stateMachineList[i];
|
||||
if (!fsm.IsInTransition && fsm.Component.enabled)
|
||||
{
|
||||
fsm.Driver.LateUpdate.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DoNothing()
|
||||
{
|
||||
}
|
||||
|
||||
public static IEnumerator DoNothingCoroutine()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e2a0c63ef281b44a823365c3d5bffcd
|
||||
timeCreated: 1457616174
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
55
Assets/A2WToolBox/3rd/StateMachine/Runtime/StateMapping.cs
Normal file
55
Assets/A2WToolBox/3rd/StateMachine/Runtime/StateMapping.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Made With Monster Love (Pty) Ltd
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MonsterLove.StateMachine
|
||||
{
|
||||
internal class StateMapping<TState, TDriver> where TState : struct, IConvertible, IComparable
|
||||
where TDriver : class, new()
|
||||
{
|
||||
public TState state;
|
||||
|
||||
public bool hasEnterRoutine;
|
||||
public Action EnterCall = StateMachineRunner.DoNothing;
|
||||
public Func<IEnumerator> EnterRoutine = StateMachineRunner.DoNothingCoroutine;
|
||||
|
||||
public bool hasExitRoutine;
|
||||
public Action ExitCall = StateMachineRunner.DoNothing;
|
||||
public Func<IEnumerator> ExitRoutine = StateMachineRunner.DoNothingCoroutine;
|
||||
|
||||
public Action Finally = StateMachineRunner.DoNothing;
|
||||
|
||||
private Func<TState> stateProviderCallback;
|
||||
private StateMachine<TState, TDriver> fsm;
|
||||
|
||||
public StateMapping(StateMachine<TState, TDriver> fsm, TState state, Func<TState> stateProvider)
|
||||
{
|
||||
this.fsm = fsm;
|
||||
this.state = state;
|
||||
stateProviderCallback = stateProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a9d115393f24d76a917d05ac6a87127
|
||||
timeCreated: 1568111091
|
||||
Reference in New Issue
Block a user