/// <summary> /// draws a foldout with buttons to load and save a preset /// </summary> public static bool PresetFoldout(bool foldout, vp_Component component) { foldout = EditorGUILayout.Foldout(foldout, "Preset"); if (foldout) { GUI.enabled = true; EditorGUILayout.BeginHorizontal(); if (component.DefaultState.TextAsset != null) GUI.enabled = false; if (GUILayout.Button("Load")) ShowLoadDialog(component); GUI.enabled = true; if (GUILayout.Button("Save")) ShowSaveDialog(component, false); if (!Application.isPlaying) GUI.enabled = false; if (GUILayout.Button("Save Tweaks")) ShowSaveDifferenceDialog(component); GUI.enabled = true; EditorGUILayout.EndHorizontal(); } return foldout; }
/// <summary> /// /// </summary> public static vp_State GetState(vp_Component component, string state) { foreach (vp_State s in component.States) { if (s.Name == state) return s; } return null; }
/////////////////////////////////////////////////////////// // allows or disallows 'state' on this object, then scans // the underlying hierarchy for vp_Components and does the // same on every object found /////////////////////////////////////////////////////////// public void AllowStateRecursively(string state, bool isAllowed) { AllowState(state, isAllowed); Component[] components; components = GetComponentsInChildren <vp_Component>(); foreach (Component c in components) { vp_Component vc = (vp_Component)c; vc.AllowState(state, isAllowed); } }
public void CacheChildren() { this.Children.Clear(); vp_Component[] componentsInChildren = base.GetComponentsInChildren <vp_Component>(true); for (int i = 0; i < componentsInChildren.Length; i++) { vp_Component vp_Component = componentsInChildren[i]; if (vp_Component.transform.parent == base.transform) { this.Children.Add(vp_Component); } } }
/// <summary> /// copies a component's type and values into 'this' preset /// </summary> public void InitFromComponent(vp_Component component) { m_ComponentType = component.Type; m_Fields.Clear(); List <FieldInfo> fieldInfos = GetFieldInfos(m_ComponentType); for (int v = 0; v < fieldInfos.Count; v++) { m_Fields.Add(new Field(fieldInfos[v].FieldHandle, fieldInfos[v].GetValue(component))); } }
public void CacheFamily() { this.Family.Clear(); vp_Component[] componentsInChildren = base.transform.root.GetComponentsInChildren <vp_Component>(true); for (int i = 0; i < componentsInChildren.Length; i++) { vp_Component vp_Component = componentsInChildren[i]; if (vp_Component != this) { this.Family.Add(vp_Component); } } }
public void CacheSiblings() { this.Siblings.Clear(); vp_Component[] components = base.GetComponents <vp_Component>(); for (int i = 0; i < components.Length; i++) { vp_Component vp_Component = components[i]; if (vp_Component != this) { this.Siblings.Add(vp_Component); } } }
static private void ShowSaveDialog(vp_Component component, bool showLoadDialogAfterwards) { string path = Application.dataPath; vp_FileDialog.Create(vp_FileDialog.Mode.Save, "Save Preset", path, delegate(string filename) { vp_FileDialog.Result = vp_ComponentPreset.Save(component, filename); if (showLoadDialogAfterwards) { ShowLoadDialog(component); } }, ".txt"); }
/////////////////////////////////////////////////////////// // draws a button showing if a state is on or off, allowing // the user to toggle states at runtime. will also show // a text saying if the state is currently disallowed /////////////////////////////////////////////////////////// public static void RunTimeStateField(vp_Component component, vp_StateInfo state, List <vp_StateInfo> stateList) { EditorGUILayout.BeginHorizontal(); GUI.color = m_ColorTransparentWhite; if (!state.Enabled) { GUILayout.Space(20); GUI.enabled = true; GUILayout.Label((stateList.Count - stateList.IndexOf(state) - 1).ToString() + ":", vp_EditorGUIUtility.RightAlignedPathStyle, GUILayout.MinWidth(20), GUILayout.MaxWidth(20)); GUILayout.BeginHorizontal(); if (GUILayout.Button(state.Name, vp_EditorGUIUtility.CenteredBoxStyle, GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { vp_Component[] compos = component.gameObject.GetComponentsInChildren <vp_Component>(); foreach (vp_Component c in compos) { c.StateManager.SetState(state.Name, true); c.Refresh(); } } if (!state.Allowed) { GUILayout.Label("(Disallowed)"); } GUILayout.EndHorizontal(); GUI.color = m_ColorTransparentWhite; } else { GUILayout.Space(20); GUILayout.Label((stateList.Count - stateList.IndexOf(state) - 1).ToString() + ":", vp_EditorGUIUtility.RightAlignedPathStyle, GUILayout.MinWidth(20), GUILayout.MaxWidth(20)); if (GUILayout.Button(state.Name, vp_EditorGUIUtility.CenteredBoxStyleBold, GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { vp_Component[] compos = component.gameObject.GetComponentsInChildren <vp_Component>(); foreach (vp_Component c in compos) { c.StateManager.SetState(state.Name, false); c.Refresh(); } } } if (state.Name != "Default" && state.TextAsset == null) { GUILayout.TextField("<- Warning: No preset!", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(100)); } EditorGUILayout.EndHorizontal(); }
private int m_TargetId = 0; // id of the last modified state (for triggering enable / disable callbacks) /// <summary> /// manages a list of states and corresponding presets for a /// component. loads the presets into memory on startup, and /// allows applying them from memory to the component. /// states are enabled in a layered manner, that is: the /// default state is always alive, and any enabled states are /// applied on top of it in the order of which they were enabled. /// /// this class doesn't store any preset data between sessions. /// it is merely used to manipulate the component using a list /// of states that is sent along at startup. it is very silent /// and forgiving; it won't complain if a state isn't found /// (since providing a certain state should not be considered /// mandatory for a component, and states can be set recursively). /// it will also ignore empty presets /// </summary> public vp_StateManager(vp_Component component, List <vp_State> states) { m_States = states; m_Component = component; // create default state and add it to the list m_Component.RefreshDefaultState(); // refresh the initial state, needed for being able to save // partial presets in the editor #if UNITY_EDITOR m_Component.RefreshInitialState(); #endif // load states and initialize the state id dictionary m_StateIds = new Dictionary <string, int>(System.StringComparer.CurrentCulture); foreach (vp_State s in m_States) { s.StateManager = this; // store the name and list index of each state in a dictionary for // fast lookup. IMPORTANT: the state list (m_States) must never be // modified at runtime (i.e. have states reordered, added, renamed // or removed) or the dictionary (m_StateIds) will be out of date if (!m_StateIds.ContainsKey(s.Name)) { m_StateIds.Add(s.Name, m_States.IndexOf(s)); } else { Debug.LogWarning("Warning: " + m_Component.GetType() + " on '" + m_Component.name + "' has more than one state named: '" + s.Name + "'. Only the topmost one will be used."); m_States[m_DefaultId].StatesToBlock.Add(m_States.IndexOf(s)); } // load up the preset of each user assigned state and if (s.Preset == null) { s.Preset = new vp_ComponentPreset(); } if (s.TextAsset != null) { s.Preset.LoadFromTextAsset(s.TextAsset); } } // the default state of a component is always the last one in the list m_DefaultId = m_States.Count - 1; }
/// <summary> /// opens a dialog for loading presets /// </summary> static private void ShowLoadDialog(vp_Component component) { string path = Application.dataPath.Replace("\\", "/"); vp_FileDialog.Create(vp_FileDialog.Mode.Open, "Load Preset", path, delegate(string filename) { if (!vp_ComponentPreset.Load(component, filename)) { vp_FileDialog.Result = "Failed to load preset '" + vp_FileDialog.ExtractFilenameFromPath(filename) + "'.\n\nIs it the correct component type? (" + component.GetType().ToString() + ")"; } else { EditorUtility.SetDirty(component); } }, ".txt"); }
private int m_TargetId = 0; // id of the last modified state (for triggering enable / disable callbacks) /// <summary> /// manages a list of states and corresponding presets for a /// component. loads the presets into memory on startup, and /// allows applying them from memory to the component. /// states are enabled in a layered manner, that is: the /// default state is always alive, and any enabled states are /// applied on top of it in the order of which they were enabled. /// /// this class doesn't store any preset data between sessions. /// it is merely used to manipulate the component using a list /// of states that is sent along at startup. it is very silent /// and forgiving; it won't complain if a state isn't found /// (since providing a certain state should not be considered /// mandatory for a component, and states can be set recursively). /// it will also ignore empty presets /// </summary> public vp_StateManager(vp_Component component, List<vp_State> states) { m_States = states; m_Component = component; // create default state and add it to the list m_Component.RefreshDefaultState(); // refresh the initial state, needed for being able to save // partial presets in the editor #if UNITY_EDITOR m_Component.RefreshInitialState(); #endif // load states and initialize the state id dictionary m_StateIds = new Dictionary<string, int>(System.StringComparer.CurrentCulture); foreach (vp_State s in m_States) { s.StateManager = this; // store the name and list index of each state in a dictionary for // fast lookup. IMPORTANT: the state list (m_States) must never be // modified at runtime (i.e. have states reordered, added, renamed // or removed) or the dictionary (m_StateIds) will be out of date if (!m_StateIds.ContainsKey(s.Name)) m_StateIds.Add(s.Name, m_States.IndexOf(s)); else { Debug.LogWarning("Warning: " + m_Component.GetType() + " on '" + m_Component.name + "' has more than one state named: '" + s.Name + "'. Only the topmost one will be used."); m_States[m_DefaultId].StatesToBlock.Add(m_States.IndexOf(s)); } // load up the preset of each user assigned state and if (s.Preset == null) s.Preset = new vp_ComponentPreset(); if (s.TextAsset != null) s.Preset.LoadFromTextAsset(s.TextAsset); } // the default state of a component is always the last one in the list m_DefaultId = m_States.Count - 1; }
/// <summary> /// this method applies a preset onto the passed component, /// returning true on success /// </summary> public static bool Apply(vp_Component component, vp_ComponentPreset preset) { if (preset == null) { Error("Tried to apply a preset that was null in '" + vp_Utility.GetErrorLocation() + "'"); return(false); } if (preset.m_ComponentType == null) { Error("Preset ComponentType was null in '" + vp_Utility.GetErrorLocation() + "'"); return(false); } if (component == null) { UnityEngine.Debug.LogWarning("Warning: Component was null when attempting to apply preset in '" + vp_Utility.GetErrorLocation() + "'"); return(false); } if (component.Type != preset.m_ComponentType) { string type = "a '" + preset.m_ComponentType + "' preset"; if (preset.m_ComponentType == null) { type = "an unknown preset type"; } Error("Applied " + type + " to a '" + component.Type.ToString() + "' component in '" + vp_Utility.GetErrorLocation() + "'"); return(false); } // component and preset both seem ok, so set the preset fields // onto the component foreach (Field f in preset.m_Fields) { foreach (FieldInfo destField in component.Fields) { if (destField.FieldHandle == f.FieldHandle) { destField.SetValue(component, f.Args); } } } return(true); }
/// <summary> /// fills a dictionary with all the states as string keys /// (instead of objects) and their block lists as string-list /// (instead of int-list) values /// </summary> static void BackupBlockLists(vp_Component component) { m_BlockListBackups = new Dictionary <string, List <string> >(); foreach (vp_State blocker in component.States) { List <string> blockees = new List <string>(); foreach (int i in blocker.StatesToBlock) { string blockee = GetStateName(component, i); if (blockee != null) { blockees.Add(blockee); } } if (!m_BlockListBackups.ContainsKey(blocker.Name)) { m_BlockListBackups.Add(blocker.Name, blockees); } } }
public vp_StateManager(vp_Component component, List <vp_State> states) { this.m_States = states; this.m_Component = component; this.m_Component.RefreshDefaultState(); this.m_StateIds = new Dictionary <string, int>(StringComparer.CurrentCulture); foreach (vp_State current in this.m_States) { current.StateManager = this; if (!this.m_StateIds.ContainsKey(current.Name)) { this.m_StateIds.Add(current.Name, this.m_States.IndexOf(current)); } else { Debug.LogWarning(string.Concat(new object[] { "Warning: ", this.m_Component.GetType(), " on '", this.m_Component.name, "' has more than one state named: '", current.Name, "'. Only the topmost one will be used." })); this.m_States[this.m_DefaultId].StatesToBlock.Add(this.m_States.IndexOf(current)); } if (current.Preset == null) { current.Preset = new vp_ComponentPreset(); } if (current.TextAsset != null) { current.Preset.LoadFromTextAsset(current.TextAsset); } } this.m_DefaultId = this.m_States.Count - 1; }
private List<vp_StateInfo> m_States = null; // list sent from the component at startup #endregion Fields #region Constructors /////////////////////////////////////////////////////////// // constructor. creates a default state using the values // currently set on the component, then loads the presets // referenced in the passed list of states. /////////////////////////////////////////////////////////// public vp_StateManager(vp_Component component, List<vp_StateInfo> states) { m_States = states; m_Component = component; // create default state and add it to the list m_Component.RefreshDefaultState(); // refresh the initial state, needed for being able to save // partial presets in the editor #if UNITY_EDITOR m_Component.RefreshInitialState(); #endif // load up the preset of each user assigned state foreach (vp_StateInfo s in m_States) { if(s.Preset == null) s.Preset = new vp_ComponentPreset(); if (s.TextAsset != null) s.Preset.LoadFromTextAsset(s.TextAsset); } }
/// <summary> /// creates an empty preset in memory, copies a component's /// type and values into it and returns the preset /// </summary> public static vp_ComponentPreset CreateFromComponent(vp_Component component) { // TODO: used? vp_ComponentPreset preset = new vp_ComponentPreset(); preset.m_ComponentType = component.Type; foreach (FieldInfo f in preset.m_ComponentType.GetFields()) { if (f.IsPublic) { if (f.FieldType == typeof(float) || f.FieldType == typeof(Vector4) || f.FieldType == typeof(Vector3) || f.FieldType == typeof(Vector2) || f.FieldType == typeof(int) || f.FieldType == typeof(bool) || f.FieldType == typeof(string) #if ANTICHEAT || f.FieldType == typeof(ObscuredFloat) || f.FieldType == typeof(ObscuredVector3) || f.FieldType == typeof(ObscuredVector2) || f.FieldType == typeof(ObscuredInt) || f.FieldType == typeof(ObscuredBool) || f.FieldType == typeof(ObscuredString) #endif ) { preset.m_Fields.Add(new Field(f.FieldHandle, f.GetValue(component))); } } } return(preset); }
/// <summary> /// static overload: creates and loads a preset and sets all /// the values on 'component' /// </summary> public static bool Load(vp_Component component, string fullPath) { vp_ComponentPreset preset = new vp_ComponentPreset(); preset.LoadTextStream(fullPath); return Apply(component, preset); }
/// <summary> /// restores the int block list onto all states by name, by /// fetching block lists in string-list format from the /// backup dictionary and converting them back to int-lists /// to be set on the components /// </summary> static void RestoreBlockLists(vp_Component component) { foreach (string s in m_BlockListBackups.Keys) { vp_State blocker = GetState(component, s); if (blocker == null) continue; List<string> stringBlockList; if (!m_BlockListBackups.TryGetValue(s, out stringBlockList)) continue; List<int> intBlockList = new List<int>(); foreach (string b in stringBlockList) { int blockee = GetStateId(component, b); if (blockee != -1) intBlockList.Add(GetStateId(component, b)); } blocker.StatesToBlock = intBlockList; } }
/// <summary> /// /// </summary> public static string GetStateName(vp_Component component, int id) { if (id == -1) return null; return component.States[id].Name; }
/// <summary> /// draws a button showing if a state is on or off, allowing /// the user to toggle states at runtime. will also show /// a text saying if the state is currently disallowed /// </summary> public static void RunTimeStateField(vp_Component component, vp_State state, List<vp_State> stateList) { EditorGUILayout.BeginHorizontal(); GUI.color = m_ColorTransparentWhite; if (!state.Enabled) { GUILayout.Space(20); GUI.enabled = true; GUILayout.Label((stateList.Count - stateList.IndexOf(state) - 1).ToString() + ":", vp_EditorGUIUtility.RightAlignedPathStyle, GUILayout.MinWidth(20), GUILayout.MaxWidth(20)); GUILayout.BeginHorizontal(); if (GUILayout.Button(state.Name, vp_EditorGUIUtility.CenteredBoxStyle, GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { RunTimeStateButtonTarget = component; vp_Component[] compos = component.gameObject.GetComponentsInChildren<vp_Component>(); foreach (vp_Component c in compos) { c.StateManager.SetState(state.Name, true); c.Refresh(); } } GUILayout.EndHorizontal(); GUI.color = m_ColorTransparentWhite; } else { GUILayout.Space(20); GUILayout.Label((stateList.Count - stateList.IndexOf(state) - 1).ToString() + ":", vp_EditorGUIUtility.RightAlignedPathStyle, GUILayout.MinWidth(20), GUILayout.MaxWidth(20)); if (GUILayout.Button(state.Name, ((!state.Blocked) ? vp_EditorGUIUtility.CenteredBoxStyleBold : vp_EditorGUIUtility.CenteredStyleBold) , GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { RunTimeStateButtonTarget = component; vp_Component[] compos = component.gameObject.GetComponentsInChildren<vp_Component>(); foreach (vp_Component c in compos) { c.StateManager.SetState(state.Name, false); c.Refresh(); } } } if (state.Name != "Default") { if (state.Blocked) GUILayout.TextField("(Blocked on " + component.GetType().ToString() + "(" + state.BlockCount + "))", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(100)); if ((state.TextAsset == null) && (!state.Blocked)) GUILayout.TextField("(No preset)", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(100)); } EditorGUILayout.EndHorizontal(); }
/// <summary> /// this is a utility function for forcing state type names to /// that of the component. these names may potentially contain /// out-of-date type names serialized on earlier versions of UFPS, /// or may be a result of copying fields from one type to a related /// but different type /// </summary> public static void UpdateOldStateTypeNames(vp_Component component) { System.Type componentType = component.Type; // update state type names created on v1.3.3, to the 1.4.x type names for (int v = 0; v < component.States.Count; v++) { vp_State s = component.States[v]; // force states to have the type names of the component if (s.TypeName != componentType.Name) s.TypeName = componentType.Name; // TODO: remove ? if (s.TypeName == "vp_FPSController" || s.TypeName == "vp_FPSCamera" || s.TypeName == "vp_FPSSHooter" || s.TypeName == "vp_FPSWeapon") { s.TypeName = s.TypeName.Replace("vp_FPS", "vp_FP"); Debug.Log("Corrected " + s.Name + " state type name to:" + s.TypeName + "."); } } }
/// <summary> /// opens a dialog for saving presets /// </summary> static private void ShowSaveDifferenceDialog(vp_Component component) { string path = Application.dataPath; // LORE: in order not to overwrite existing values in a disk // preset, we'll load the disk preset before saving over it. // since the file dialog system will execute its callback // twice in case of an already existing file (and delete the // target file in the process) we need to store the preset // in memory outside of the callback and skip loading it on // the second iteration vp_ComponentPreset diskPreset = null; vp_FileDialog.Create(vp_FileDialog.Mode.Save, "Save Tweaks", path, delegate(string filename) { // only attempt to load the disk preset the first time // the callback is executed if (diskPreset == null) { diskPreset = new vp_ComponentPreset(); // attempt to load target preset into memory, ignoring // load errors in the process bool logErrorState = vp_ComponentPreset.LogErrors; vp_ComponentPreset.LogErrors = false; diskPreset.LoadTextStream(filename); vp_ComponentPreset.LogErrors = logErrorState; } vp_FileDialog.Result = vp_ComponentPreset.SaveDifference(component.InitialState.Preset, component, filename, diskPreset); }, ".txt"); }
/////////////////////////////////////////////////////////// // draws a field allowing the user to create, reorganize, // name, assign presets to and delete states on a component /////////////////////////////////////////////////////////// public static bool StateFoldout(bool foldout, vp_Component component, List <vp_StateInfo> stateList, vp_ComponentPersister persister = null) { bool before = foldout; foldout = EditorGUILayout.Foldout(foldout, (foldout && !Application.isPlaying) ? "State Preset" : "States" ); if (foldout != before) { component.RefreshDefaultState(); } if (foldout) { for (int v = 0; v < stateList.Count; v++) { int s = v; if (!Application.isPlaying) { vp_PresetEditorGUIUtility.StateField(stateList[s], stateList); } else { vp_PresetEditorGUIUtility.RunTimeStateField(component, stateList[s], stateList); } } GUILayout.BeginHorizontal(); if (!Application.isPlaying) { if (GUILayout.Button("Add State", GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { stateList.Add(new vp_StateInfo(component.GetType().Name, "New State", "")); component.RefreshDefaultState(); } } else { GUI.color = Color.clear; GUILayout.Button("", GUILayout.MinWidth(36), GUILayout.MaxWidth(36)); GUI.color = Color.white; } if (!Application.isPlaying) { GUILayout.EndHorizontal(); } if (persister != null) { vp_PresetEditorGUIUtility.PersistToggle(persister); } if (Application.isPlaying) { GUILayout.EndHorizontal(); } vp_EditorGUIUtility.Separator(); } return(foldout); }
/// <summary> /// opens a dialog for saving presets /// </summary> static private void ShowSaveDialog(vp_Component component) { ShowSaveDialog(component, false); }
/// <summary> /// this method applies a preset onto the passed component, /// returning true on success /// </summary> public static bool Apply(vp_Component component, vp_ComponentPreset preset) { if (preset == null) { Error("Tried to apply a preset that was null in '" + vp_Utility.GetErrorLocation() + "'"); return false; } if (preset.m_ComponentType == null) { Error("Preset ComponentType was null in '" + vp_Utility.GetErrorLocation() + "'"); return false; } if (component == null) { UnityEngine.Debug.LogWarning("Warning: Component was null when attempting to apply preset in '" + vp_Utility.GetErrorLocation() + "'"); return false; } if (component.Type != preset.m_ComponentType) { string type = "a '" + preset.m_ComponentType + "' preset"; if (preset.m_ComponentType == null) type = "an unknown preset type"; Error("Applied " + type + " to a '" + component.Type.ToString() + "' component in '" + vp_Utility.GetErrorLocation() + "'"); return false; } // component and preset both seem ok, so set the preset fields // onto the component foreach (Field f in preset.m_Fields) { foreach (FieldInfo destField in component.Fields) { if (destField.FieldHandle == f.FieldHandle) destField.SetValue(component, f.Args); } } return true; }
/// <summary> /// static overload: creates and loads a preset and sets all /// the values on 'component', then returns the preset /// </summary> public static vp_ComponentPreset LoadFromTextAsset(vp_Component component, TextAsset file) { vp_ComponentPreset preset = new vp_ComponentPreset(); preset.LoadFromTextAsset(file); Apply(component, preset); return preset; }
/// <summary> /// static overload: creates and loads a preset and sets all /// the values on 'component', then returns the preset /// </summary> public static vp_ComponentPreset LoadFromResources(vp_Component component, string resourcePath) { vp_ComponentPreset preset = new vp_ComponentPreset(); preset.LoadFromResources(resourcePath); Apply(component, preset); return preset; }
/// <summary> /// draws a field allowing the user to create, reorganize, /// name, assign presets to and delete states on a component /// </summary> public static bool StateFoldout(bool foldout, vp_Component component, List <vp_State> stateList, vp_ComponentPersister persister = null) { bool before = foldout; foldout = EditorGUILayout.Foldout(foldout, (foldout && !Application.isPlaying) ? "State Preset" : "States" ); if (foldout != before) { m_ShowBlockListFor = null; component.RefreshDefaultState(); } if (foldout) { if (m_ShowBlockListFor != null) { if (!stateList.Contains(m_ShowBlockListFor)) { foldout = false; } } } if (foldout) { for (int v = 0; v < stateList.Count; v++) { vp_State s = stateList[v]; if (!Application.isPlaying) { vp_PresetEditorGUIUtility.StateField(s, stateList, component); if ((m_ShowBlockListFor != null) && m_ShowBlockListFor == s) { StateBlockList(component, s); } } else { vp_PresetEditorGUIUtility.RunTimeStateField(component, s, stateList); } } GUILayout.BeginHorizontal(); if (!Application.isPlaying) { if (GUILayout.Button("Add State", GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { m_ShowBlockListFor = null; string newStateName = "Untitled"; int n = 1; while (GetStateId(component, newStateName) != -1) { n++; newStateName = newStateName.Substring(0, 8) + (n < 10?"0":"") + n.ToString(); } stateList.Add(new vp_State(component.GetType().Name, newStateName, "")); component.RefreshDefaultState(); EditorUtility.SetDirty(component); } } else { GUI.color = Color.clear; GUILayout.Button("", GUILayout.MinWidth(36), GUILayout.MaxWidth(36)); GUI.color = Color.white; } if (!Application.isPlaying) { GUILayout.EndHorizontal(); } if (persister != null) { vp_PresetEditorGUIUtility.PersistToggle(persister); } if (Application.isPlaying) { GUILayout.EndHorizontal(); } vp_EditorGUIUtility.Separator(); } return(foldout); }
static private void ShowSaveDialog(vp_Component component, bool showLoadDialogAfterwards) { string path = Application.dataPath; vp_FileDialog.Create(vp_FileDialog.Mode.Save, "Save Preset", path, delegate(string filename) { vp_FileDialog.Result = vp_ComponentPreset.Save(component, filename); if (showLoadDialogAfterwards) ShowLoadDialog(component); }, ".txt"); }
/// <summary> /// /// </summary> static void StateBlockList(vp_Component component, vp_State blocker) { GUILayout.BeginHorizontal(); GUILayout.Space(20); GUILayout.BeginVertical(); string componentName = component.GetType().ToString(); if (componentName.Contains("vp_")) { componentName = componentName.Substring(3); } EditorGUILayout.HelpBox("'" + blocker.Name + "' blocks " + ((blocker.StatesToBlock.Count > 0) ? blocker.StatesToBlock.Count.ToString() : "no") + " state" + ((blocker.StatesToBlock.Count == 1) ? "" : "s") + " on this " + componentName + ".", MessageType.None); GUILayout.BeginVertical(); int e = 0; foreach (vp_State blockee in component.States) { if (blockee == blocker) { continue; } if (blockee.Name == "Default") { continue; } int i = component.States.IndexOf(blockee); if (component.States[i].StatesToBlock.Contains(component.States.IndexOf(blocker))) { GUI.enabled = false; } if (e % 2 == 0) { GUILayout.BeginHorizontal(); } GUILayout.Space(20); bool before = blocker.StatesToBlock.Contains(i); bool after = before; after = GUILayout.Toggle(after, blockee.Name); if (before != after) { if (!before) { blocker.StatesToBlock.Add(i); } else { blocker.StatesToBlock.Remove(i); } EditorUtility.SetDirty(component); } if (e % 2 == 1) { GUILayout.Space(10); GUILayout.EndHorizontal(); } e++; GUI.enabled = true; } if (e % 2 == 1) { GUILayout.EndHorizontal(); } GUILayout.EndVertical(); GUILayout.BeginHorizontal(); EditorGUILayout.HelpBox("Select states to be disallowed on this " + componentName + " while the '" + blocker.Name + "' state is enabled. A state can not block itself, a state that blocks it or the Default state.", MessageType.Info); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close", GUILayout.MinWidth(100), GUILayout.MaxWidth(50))) { m_ShowBlockListFor = null; EditorUtility.SetDirty(component); } GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.EndHorizontal(); GUILayout.Space(10); }
/// <summary> /// draws a field allowing the user to create, reorganize, /// name, assign presets to and delete states on a component /// </summary> public static bool StateFoldout(bool foldout, vp_Component component, List<vp_State> stateList, vp_ComponentPersister persister = null) { RunTimeStateButtonTarget = null; bool before = foldout; foldout = EditorGUILayout.Foldout(foldout, (foldout && !Application.isPlaying) ? "State Preset" : "States" ); if (foldout != before) { m_ShowBlockListFor = null; component.RefreshDefaultState(); if (!Application.isPlaying) UpdateOldStateTypeNames(component); } if (foldout) { if (m_ShowBlockListFor != null) { if (!stateList.Contains(m_ShowBlockListFor)) foldout = false; } } if (foldout) { for (int v = 0; v < stateList.Count; v++) { vp_State s = stateList[v]; if (!Application.isPlaying) { vp_PresetEditorGUIUtility.StateField(s, stateList, component); if ((m_ShowBlockListFor != null) && m_ShowBlockListFor == s) { StateBlockList(component, s); } } else { vp_PresetEditorGUIUtility.RunTimeStateField(component, s, stateList); } } GUILayout.BeginHorizontal(); if (!Application.isPlaying) { if (GUILayout.Button("Add State", GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { m_ShowBlockListFor = null; string newStateName = "Untitled"; int n = 1; while (GetStateId(component, newStateName) != -1) { n++; newStateName = newStateName.Substring(0, 8) + (n<10?"0":"") + n.ToString(); } stateList.Add(new vp_State(component.GetType().Name, newStateName, "")); component.RefreshDefaultState(); EditorUtility.SetDirty(component); } } else { GUI.color = Color.clear; GUILayout.Button("", GUILayout.MinWidth(36), GUILayout.MaxWidth(36)); GUI.color = Color.white; } if (!Application.isPlaying) GUILayout.EndHorizontal(); if (persister != null) vp_PresetEditorGUIUtility.PersistToggle(persister); if (Application.isPlaying) GUILayout.EndHorizontal(); vp_EditorGUIUtility.Separator(); } return foldout; }
/// <summary> /// draws a row displaying a preset state name, a path and /// buttons for browsing the path + deleting the state /// </summary> public static void StateField(vp_State state, List <vp_State> stateList, vp_Component component) { GUI.enabled = !Application.isPlaying; // only allow preset field interaction in 'stopped' mode EditorGUILayout.BeginHorizontal(); string orig = state.Name; if (state.Name == "Default") { GUI.enabled = false; EditorGUILayout.TextField(state.Name, GUILayout.MinWidth(90), GUILayout.MaxWidth(90)); GUI.enabled = true; } else { if (m_ShowBlockListFor != null) { if (!component.States.Contains(m_ShowBlockListFor)) { m_ShowBlockListFor = null; } else if (m_ShowBlockListFor.StatesToBlock.Contains(component.States.IndexOf(state))) { GUI.color = m_ColorGrayYellow; } } state.Name = EditorGUILayout.TextField(state.Name, GUILayout.MinWidth(90), GUILayout.MaxWidth(90)); GUI.color = Color.white; } if (orig != state.Name) { int collisions = -1; foreach (vp_State s in stateList) { if (s.Name == state.Name) { collisions++; } } if (state.Name == "Default") { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "'Default' is a reserved state name."); state.Name = orig; } else if (state.Name.Length == 0) { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "State name can't be empty."); state.Name = orig; } else if (collisions > 0) { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "There is already a state named '" + state.Name + "'.\nTIP: If you need a similar state name, begin by adding numbers at the end."); state.Name = orig; } else { EditorUtility.SetDirty(component); } } PresetField(state); if (state.Name == "Default") { if (state.TextAsset == null) { GUI.enabled = false; GUILayout.TextField("(Inspector)", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(60)); } else { GUI.enabled = true; if (GUILayout.Button("Unlock", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(30), GUILayout.MinHeight(15))) { state.TextAsset = null; EditorUtility.SetDirty(component); } } } else { if (stateList.IndexOf(state) == 0) { GUI.enabled = false; } GUI.SetNextControlName("state"); if (GUILayout.Button("^", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(15))) { BackupBlockLists(component); int i = stateList.IndexOf(state); if (i != 0) { stateList.Remove(state); stateList.Insert(i - 1, state); } RestoreBlockLists(component); // focus this button to get rid of possible textfield focus, // or the textfields won't update properly when moving state GUI.FocusControl("state"); EditorUtility.SetDirty(component); } GUI.enabled = true; if (state.StatesToBlock != null) { if ((state.StatesToBlock.Count > 0) && ((m_ShowBlockListFor == null) || (!component.States.Contains(m_ShowBlockListFor)) || m_ShowBlockListFor == state)) { GUI.color = m_ColorGrayYellow; } } GUI.enabled = (component.States.Count > 2); if (GUILayout.Button("B", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(15))) { if (m_ShowBlockListFor == state) { m_ShowBlockListFor = null; } else { m_ShowBlockListFor = state; } EditorUtility.SetDirty(component); } GUI.enabled = true; GUI.color = Color.white; if (GUILayout.Button("X", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(15))) { vp_MessageBox.Create(vp_MessageBox.Mode.YesNo, "Confirm", "Are you sure you want to delete the state '" + state.Name + "'?", delegate(vp_MessageBox.Answer answer) { if (answer == vp_MessageBox.Answer.Yes) { BackupBlockLists(component); stateList.Remove(state); RestoreBlockLists(component); EditorUtility.SetDirty(component); } }); EditorUtility.SetDirty(component); } } GUI.enabled = true; EditorGUILayout.EndHorizontal(); }
/// <summary> /// /// </summary> static void StateBlockList(vp_Component component, vp_State blocker) { GUILayout.BeginHorizontal(); GUILayout.Space(20); GUILayout.BeginVertical(); string componentName = component.GetType().ToString(); if (componentName.Contains("vp_")) componentName = componentName.Substring(3); if (blocker.StatesToBlock == null) blocker.StatesToBlock = new List<int>(); EditorGUILayout.HelpBox("'" + blocker.Name + "' blocks " + ((blocker.StatesToBlock.Count > 0) ? blocker.StatesToBlock.Count.ToString() : "no") + " state" + ((blocker.StatesToBlock.Count == 1) ? "" : "s") + " on this " + componentName + ".", MessageType.None); GUILayout.BeginVertical(); int e = 0; foreach (vp_State blockee in component.States) { if (blockee == blocker) continue; if (blockee.Name == "Default") continue; int i = component.States.IndexOf(blockee); if (component.States[i].StatesToBlock == null) component.States[i].StatesToBlock = new List<int>(); if (component.States[i].StatesToBlock.Contains(component.States.IndexOf(blocker))) GUI.enabled = false; if (e % 2 == 0) GUILayout.BeginHorizontal(); GUILayout.Space(20); bool before = blocker.StatesToBlock.Contains(i); bool after = before; after = GUILayout.Toggle(after, blockee.Name); if(before != after) { if(!before) blocker.StatesToBlock.Add(i); else blocker.StatesToBlock.Remove(i); EditorUtility.SetDirty(component); } if (e % 2 == 1) { GUILayout.Space(10); GUILayout.EndHorizontal(); } e++; GUI.enabled = true; } if (e % 2 == 1) GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUILayout.BeginHorizontal(); EditorGUILayout.HelpBox("Select states to be disallowed on this " + componentName + " while the '" + blocker.Name + "' state is enabled. A state can not block itself, a state that blocks it or the Default state.", MessageType.Info); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close", GUILayout.MinWidth(100), GUILayout.MaxWidth(50))) { m_ShowBlockListFor = null; EditorUtility.SetDirty(component); } GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.EndHorizontal(); GUILayout.Space(10); }
/// <summary> /// this method applies a preset onto the passed component, /// returning true on success /// </summary> public static bool Apply(vp_Component component, vp_ComponentPreset preset) { if (preset == null) { Error("Tried to apply a preset that was null in '" + vp_Utility.GetErrorLocation() + "'"); return(false); } if (preset.m_ComponentType == null) { Error("Preset ComponentType was null in '" + vp_Utility.GetErrorLocation() + "'"); return(false); } if (component == null) { UnityEngine.Debug.LogWarning("Warning: Component was null when attempting to apply preset in '" + vp_Utility.GetErrorLocation() + "'"); return(false); } if (component.Type != preset.m_ComponentType) { string type = "a '" + preset.m_ComponentType + "' preset"; if (preset.m_ComponentType == null) { type = "an unknown preset type"; } Error("Applied " + type + " to a '" + component.Type.ToString() + "' component in '" + vp_Utility.GetErrorLocation() + "'"); return(false); } // component and preset both seem ok, so set the preset fields // onto the component for (int p = 0; p < preset.m_Fields.Count; p++) { FieldInfo destField = FieldInfo.GetFieldFromHandle(preset.m_Fields[p].FieldHandle); #if ANTICHEAT if ((destField.FieldType == typeof(ObscuredFloat)) && (preset.m_Fields[p].Args.GetType() == typeof(float))) { ObscuredFloat o = (float)preset.m_Fields[p].Args; destField.SetValue(component, o); } else if ((destField.FieldType == typeof(ObscuredVector3)) && (preset.m_Fields[p].Args.GetType() == typeof(Vector3))) { ObscuredVector3 o = (Vector3)preset.m_Fields[p].Args; destField.SetValue(component, o); } else if ((destField.FieldType == typeof(ObscuredVector2)) && (preset.m_Fields[p].Args.GetType() == typeof(Vector2))) { ObscuredVector2 o = (Vector2)preset.m_Fields[p].Args; destField.SetValue(component, o); } else if ((destField.FieldType == typeof(ObscuredInt)) && (preset.m_Fields[p].Args.GetType() == typeof(int))) { ObscuredInt o = (int)preset.m_Fields[p].Args; destField.SetValue(component, o); } else if ((destField.FieldType == typeof(ObscuredBool)) && (preset.m_Fields[p].Args.GetType() == typeof(bool))) { ObscuredBool o = (bool)preset.m_Fields[p].Args; destField.SetValue(component, o); } else if ((destField.FieldType == typeof(ObscuredString)) && (preset.m_Fields[p].Args.GetType() == typeof(string))) { ObscuredString o = (string)preset.m_Fields[p].Args; destField.SetValue(component, o); } else #endif destField.SetValue(component, preset.m_Fields[p].Args); } return(true); }
/// <summary> /// draws a row displaying a preset state name, a path and /// buttons for browsing the path + deleting the state /// </summary> public static void StateField(vp_State state, List<vp_State> stateList, vp_Component component) { GUI.enabled = !Application.isPlaying; // only allow preset field interaction in 'stopped' mode EditorGUILayout.BeginHorizontal(); string orig = state.Name; if (state.Name == "Default") { GUI.enabled = false; EditorGUILayout.TextField(state.Name, GUILayout.MinWidth(90), GUILayout.MaxWidth(90)); GUI.enabled = true; } else { if (m_ShowBlockListFor != null) { if (!component.States.Contains(m_ShowBlockListFor)) m_ShowBlockListFor = null; else { if (m_ShowBlockListFor.StatesToBlock == null) m_ShowBlockListFor.StatesToBlock = new List<int>(); if (m_ShowBlockListFor.StatesToBlock.Contains(component.States.IndexOf(state))) GUI.color = m_ColorGrayYellow; } } state.Name = EditorGUILayout.TextField(state.Name, GUILayout.MinWidth(90), GUILayout.MaxWidth(90)); GUI.color = Color.white; } if (orig != state.Name) { int collisions = -1; foreach (vp_State s in stateList) { if (s.Name == state.Name) collisions++; } if (state.Name == "Default") { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "'Default' is a reserved state name."); state.Name = orig; } else if (state.Name.Length == 0) { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "State name can't be empty."); state.Name = orig; } else if (collisions > 0) { vp_MessageBox.Create(vp_MessageBox.Mode.OK, "Error", "There is already a state named '" + state.Name +"'.\nTIP: If you need a similar state name, begin by adding numbers at the end." ); state.Name = orig; } else EditorUtility.SetDirty(component); } PresetField(state); if (state.Name == "Default") { if (state.TextAsset == null) { GUI.enabled = false; GUILayout.TextField("(Inspector)", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(60)); } else { GUI.enabled = true; if (GUILayout.Button("Unlock", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(30), GUILayout.MinHeight(15))) { state.TextAsset = null; EditorUtility.SetDirty(component); } } } else { if (stateList.IndexOf(state) == 0) GUI.enabled = false; GUI.SetNextControlName("state"); if (GUILayout.Button("^", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(15))) { BackupBlockLists(component); int i = stateList.IndexOf(state); if (i != 0) { stateList.Remove(state); stateList.Insert(i - 1, state); } RestoreBlockLists(component); // focus this button to get rid of possible textfield focus, // or the textfields won't update properly when moving state GUI.FocusControl("state"); EditorUtility.SetDirty(component); } GUI.enabled = true; if (state.StatesToBlock == null) state.StatesToBlock = new List<int>(); if ((state.StatesToBlock.Count > 0) && ((m_ShowBlockListFor == null) || (!component.States.Contains(m_ShowBlockListFor)) || m_ShowBlockListFor == state)) GUI.color = m_ColorGrayYellow; GUI.enabled = (component.States.Count > 2); if (GUILayout.Button("B", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(15))) { if (m_ShowBlockListFor == state) m_ShowBlockListFor = null; else m_ShowBlockListFor = state; EditorUtility.SetDirty(component); } GUI.enabled = true; GUI.color = Color.white; if (GUILayout.Button("X", vp_EditorGUIUtility.SmallButtonStyle, GUILayout.MinWidth(15), GUILayout.MaxWidth(15), GUILayout.MinHeight(15))) { vp_MessageBox.Create(vp_MessageBox.Mode.YesNo, "Confirm", "Are you sure you want to delete the state '" + state.Name + "'?", delegate(vp_MessageBox.Answer answer) { if (answer == vp_MessageBox.Answer.Yes) { BackupBlockLists(component); stateList.Remove(state); RestoreBlockLists(component); EditorUtility.SetDirty(component); } }); EditorUtility.SetDirty(component); } } GUI.enabled = true; EditorGUILayout.EndHorizontal(); }
/////////////////////////////////////////////////////////// // draws a button showing if a state is on or off, allowing // the user to toggle states at runtime. will also show // a text saying if the state is currently disallowed /////////////////////////////////////////////////////////// public static void RunTimeStateField(vp_Component component, vp_StateInfo state, List<vp_StateInfo> stateList) { EditorGUILayout.BeginHorizontal(); GUI.color = m_ColorTransparentWhite; if (!state.Enabled) { GUILayout.Space(20); GUI.enabled = true; GUILayout.Label((stateList.Count - stateList.IndexOf(state) - 1).ToString() + ":", vp_EditorGUIUtility.RightAlignedPathStyle, GUILayout.MinWidth(20), GUILayout.MaxWidth(20)); GUILayout.BeginHorizontal(); if(GUILayout.Button(state.Name, vp_EditorGUIUtility.CenteredBoxStyle, GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { vp_Component[] compos = component.gameObject.GetComponentsInChildren<vp_Component>(); foreach (vp_Component c in compos) { c.StateManager.SetState(state.Name, true); c.Refresh(); } } if (!state.Allowed) GUILayout.Label("(Disallowed)"); GUILayout.EndHorizontal(); GUI.color = m_ColorTransparentWhite; } else { GUILayout.Space(20); GUILayout.Label((stateList.Count - stateList.IndexOf(state) - 1).ToString() + ":", vp_EditorGUIUtility.RightAlignedPathStyle, GUILayout.MinWidth(20), GUILayout.MaxWidth(20)); if (GUILayout.Button(state.Name, vp_EditorGUIUtility.CenteredBoxStyleBold, GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { vp_Component[] compos = component.gameObject.GetComponentsInChildren<vp_Component>(); foreach (vp_Component c in compos) { c.StateManager.SetState(state.Name, false); c.Refresh(); } } } if (state.Name != "Default" && state.TextAsset == null) GUILayout.TextField("<- Warning: No preset!", vp_EditorGUIUtility.NoteStyle, GUILayout.MinWidth(100)); EditorGUILayout.EndHorizontal(); }
/// <summary> /// fills a dictionary with all the states as string keys /// (instead of objects) and their block lists as string-list /// (instead of int-list) values /// </summary> static void BackupBlockLists(vp_Component component) { m_BlockListBackups = new Dictionary<string, List<string>>(); foreach (vp_State blocker in component.States) { List<string> blockees = new List<string>(); if (blocker.StatesToBlock == null) blocker.StatesToBlock = new List<int>(); foreach (int i in blocker.StatesToBlock) { string blockee = GetStateName(component, i); if(blockee != null) blockees.Add(blockee); } if (!m_BlockListBackups.ContainsKey(blocker.Name)) m_BlockListBackups.Add(blocker.Name, blockees); } }
/////////////////////////////////////////////////////////// // draws a field allowing the user to create, reorganize, // name, assign presets to and delete states on a component /////////////////////////////////////////////////////////// public static bool StateFoldout(bool foldout, vp_Component component, List<vp_StateInfo> stateList, vp_ComponentPersister persister = null) { bool before = foldout; foldout = EditorGUILayout.Foldout(foldout, (foldout && !Application.isPlaying) ? "State Preset" : "States" ); if (foldout != before) component.RefreshDefaultState(); if (foldout) { for (int v = 0; v < stateList.Count; v++) { int s = v; if (!Application.isPlaying) { vp_PresetEditorGUIUtility.StateField(stateList[s], stateList); } else { vp_PresetEditorGUIUtility.RunTimeStateField(component, stateList[s], stateList); } } GUILayout.BeginHorizontal(); if (!Application.isPlaying) { if (GUILayout.Button("Add State", GUILayout.MinWidth(90), GUILayout.MaxWidth(90))) { stateList.Add(new vp_StateInfo(component.GetType().Name, "New State", "")); component.RefreshDefaultState(); } } else { GUI.color = Color.clear; GUILayout.Button("", GUILayout.MinWidth(36), GUILayout.MaxWidth(36)); GUI.color = Color.white; } if(!Application.isPlaying) GUILayout.EndHorizontal(); if (persister != null) vp_PresetEditorGUIUtility.PersistToggle(persister); if (Application.isPlaying) GUILayout.EndHorizontal(); vp_EditorGUIUtility.Separator(); } return foldout; }
/// <summary> /// /// </summary> public static int GetStateId(vp_Component component, string state) { for (int v = 0; v < component.States.Count; v++) { if (component.States[v].Name == state) return v; } return -1; }
/// <summary> /// /// </summary> public static void GenerateStatesAndPresetsFromDerivedComponent(Component derivedComponent, Component baseComponent, string path) { //System.Type derivedType = derivedComponent.GetType(); // TEST (see below) System.Type baseType = baseComponent.GetType(); // TEST: disabled to allow converting from vp_FPController to // vp_CapsuleController. evaluate this down the line //if (!vp_EditorUtility.IsSameOrSubclass(baseType, derivedType)) // return; vp_Component vpDerived = derivedComponent as vp_Component; vp_Component vpBase = baseComponent as vp_Component; if (vpDerived == null) { return; } if (vpBase == null) { return; } for (int v = 0; v < vpDerived.States.Count; v++) { // abort if old state has no text asset vp_State oldState = vpDerived.States[v]; if (oldState.TextAsset == null) { continue; } // abort if we fail to load old text asset into a preset vp_ComponentPreset preset = new vp_ComponentPreset(); if (!preset.LoadFromTextAsset(oldState.TextAsset)) { continue; } // try to make the preset compatible with the base component. this // will fail if it has no compatible fields, in which case we abort if (preset.TryMakeCompatibleWithComponent(vpBase) < 1) { continue; } // we have a new preset that is compatible with the base component. // save it at a temporary, auto-generated path string typeName = oldState.TypeName.Replace("vp_FP", ""); typeName = typeName.Replace("vp_", ""); string filePath = path + "/" + typeName + "_" + vpBase.gameObject.name + "_" + oldState.Name + ".txt"; vp_ComponentPreset.Save(preset, filePath); AssetDatabase.Refresh(); // add a corresponding state, into which we load the new preset vp_State newState = new vp_State(baseType.Name, vpDerived.States[v].Name, null, null); vpBase.States.Add(newState); // System.Threading.Thread.Sleep(100); // might come in handy on slow disk (?) newState.TextAsset = AssetDatabase.LoadAssetAtPath(filePath, typeof(TextAsset)) as TextAsset; } }
/// <summary> /// opens a dialog for loading presets /// </summary> static private void ShowLoadDialog(vp_Component component) { string path = Application.dataPath.Replace("\\", "/"); vp_FileDialog.Create(vp_FileDialog.Mode.Open, "Load Preset", path, delegate(string filename) { if (!vp_ComponentPreset.Load(component, filename)) vp_FileDialog.Result = "Failed to load preset '" + vp_FileDialog.ExtractFilenameFromPath(filename) + "'.\n\nIs it the correct component type? (" + component.GetType().ToString() + ")"; else EditorUtility.SetDirty(component); }, ".txt"); }
/// <summary> /// /// </summary> public int TryMakeCompatibleWithComponent(vp_Component component) { m_ComponentType = component.GetType(); List<FieldInfo> availableFields = new List<FieldInfo>(m_ComponentType.GetFields()); for (int v = m_Fields.Count - 1; v > -1; v--) { foreach (FieldInfo field in availableFields) { // TEMP: special case since these values are not relevant in 3rd person if (field.Name.Contains("PositionOffset") || field.Name.Contains("RotationOffset")) goto kill; if (m_Fields[v].FieldHandle == field.FieldHandle) goto keep; } kill: m_Fields.Remove(m_Fields[v]); keep:{ } } return m_Fields.Count; }