diff --git a/Editor/Core/Architecture.meta b/Documentation/Information.meta similarity index 77% rename from Editor/Core/Architecture.meta rename to Documentation/Information.meta index b1a05d71..0b4d1848 100644 --- a/Editor/Core/Architecture.meta +++ b/Documentation/Information.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 600171c84a5cb1e4c9936a94efd94541 +guid: b31819f8abae8d6498ef952fa251bb85 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Documentation/Information/ClassViewer.txt b/Documentation/Information/ClassViewer.txt new file mode 100644 index 00000000..4d82ba38 --- /dev/null +++ b/Documentation/Information/ClassViewer.txt @@ -0,0 +1,70 @@ +Runtime + Core + Architecture + Game -> This is a red word and bold green. Go to TEST https://github.com/AliJimpa/RealMethod/wiki/Assets. + World -> just test text ColortTEst Without link + GameConfig + GameBridge + ManagerContracts + ServiceContracts + WorldSceneConfig + ProjectSettingAsset -> ProjectSettingAsset Should be in Resource>RealMethod>RealMethodSetting.asset and all RealMethod setting handeled by this asset and this name. + Attributes + ButtonAttribute + ColorFieldAttribute + ConditionalHideAttribute + DropdownAttribute + DropdownFromArrayAttribute + DropdownFromDictionaryAttribute + EnumDescriptionAttribute + ExpandableAttribute + HelpBoxAttribute + HideInInspectorByEnumAttribute + InterfaceValidationDrawer + LayerAttribute + ListToPopupAttribute + MinMaxRangeAttribute + ReadOnlyAttribute + SeparatorAttribute + ShowInInspectorByEnumAttribute + ShowOnlyAttribute + ShowTypeAttribute + TagSelectorAttribute + Definitions + Assets + Identifier + Prefab + Tick + ProjectSetting + ProjectSettingAsset + Library + Extension + Interfaces + SharedScripts + Utilities + Vendor + Pattern + Components + DataAssets + DesignPatterns + Managers + Services + ReadySet + Commands + Components + DefaultsClass + Managers + Presets + Services + Toolkit + Ability + Actor + CSVFile + CurveViewer + Interaction + Inventory + PCG + Pickup + RPG + Tutorial + Upgrade diff --git a/Reservoir/ScriptTemplates/ItemAssetTemplate.txt.meta b/Documentation/Information/ClassViewer.txt.meta similarity index 75% rename from Reservoir/ScriptTemplates/ItemAssetTemplate.txt.meta rename to Documentation/Information/ClassViewer.txt.meta index d7efbd4a..9d6bfdd0 100644 --- a/Reservoir/ScriptTemplates/ItemAssetTemplate.txt.meta +++ b/Documentation/Information/ClassViewer.txt.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: bb63fd5394661484babdcdc725c3d48a +guid: 79055230a8dc125418831907cfeb785e TextScriptImporter: externalObjects: {} userData: diff --git a/Editor/Library/Vendor.meta b/Documentation/Resource.meta similarity index 77% rename from Editor/Library/Vendor.meta rename to Documentation/Resource.meta index 95cd04e7..16b30863 100644 --- a/Editor/Library/Vendor.meta +++ b/Documentation/Resource.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b6449ef571a85534abe38c8766ce2b2c +guid: 7b6dff7ffa0c54f4c93b41811af269d5 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Reservoir/Icons/Core/RealMethod.png b/Documentation/Resource/RM_Title.png similarity index 100% rename from Reservoir/Icons/Core/RealMethod.png rename to Documentation/Resource/RM_Title.png diff --git a/Reservoir/Icons/Core/RealMethod.png.meta b/Documentation/Resource/RM_Title.png.meta similarity index 100% rename from Reservoir/Icons/Core/RealMethod.png.meta rename to Documentation/Resource/RM_Title.png.meta diff --git a/Editor/Core/Architecture/GameCompWindow.cs b/Editor/Core/Architecture/GameCompWindow.cs deleted file mode 100644 index 589ee281..00000000 --- a/Editor/Core/Architecture/GameCompWindow.cs +++ /dev/null @@ -1,64 +0,0 @@ -using PlasticGui.WorkspaceWindow; -using UnityEditor; - -namespace RealMethod -{ - [CustomEditor(typeof(Game), true)] - public class GameCompWindow : UnityEditor.Editor - { - private Game BaseComponent; - - private void OnEnable() - { - BaseComponent = (Game)target; - } - public override void OnInspectorGUI() - { - base.OnInspectorGUI(); - EditorGUILayout.Space(); - if (BaseComponent != null) - { - if (Game.World != null) - { - - } - EditorGUILayout.LabelField($"{GetWorld()} | {GetSetvice()} | {GetConfig()}"); - EditorGUILayout.Space(0.5f); - string[] Data = BaseComponent.GetAllServiceNames(); - for (int i = 0; i < Data.Length; i++) - { - EditorGUILayout.LabelField($"{i + 1}. {Data[i]}"); - } - } - } - - - - - - private string GetWorld() - { - return Game.World != null ? Game.World.GetType().Name : "World Not Valid"; - } - private string GetSetvice() - { - return Game.Service != null ? Game.Service.GetType().Name : "GameService Not Valid"; - } - private string GetConfig() - { - return Game.Config != null ? Game.Config.GetType().Name : "GameConfig Not Valid"; - } - - - - - - - - - - } - - - -} \ No newline at end of file diff --git a/Editor/Core/Definitions/ConfigAssetValidator.cs b/Editor/Core/Definitions/ConfigAssetValidator.cs deleted file mode 100644 index bec8bc5d..00000000 --- a/Editor/Core/Definitions/ConfigAssetValidator.cs +++ /dev/null @@ -1,89 +0,0 @@ -#if UNITY_EDITOR -using UnityEditor; -using UnityEngine; -using System; -using System.Reflection; -using System.Linq; - -namespace RealMethod.Editor -{ - [InitializeOnLoad] - public static class ConfigAssetValidator - { - static ConfigAssetValidator() - { - EditorApplication.delayCall += ValidateAllConfigs; - } - - public static void ValidateAllConfigs() - { - var configTypes = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(a => a.GetTypes()) - .Where(t => t.IsSubclassOf(typeof(ConfigAsset))); - - foreach (var type in configTypes) - { - // 🔹 Check fields - var badFields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly) - .Where(f => !f.IsInitOnly && !f.IsLiteral && !f.IsDefined(typeof(SerializeField), false)) - .ToList(); - - foreach (var f in badFields) - { - Debug.LogError($"❌ '{type.Name}' has non-readonly field '{f.Name}' — only readonly fields allowed in Config-derived classes."); - } - - // 🔹 Check methods - var badMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) - .Where(m => !m.IsSpecialName && !m.IsConstructor) - .Where(m => ViolatesPureMethodRules(m)) - .ToList(); - - foreach (var m in badMethods) - { - Debug.LogError($"❌ '{type.Name}' public method '{m.Name}' modifies state — only pure getter/return methods are allowed in Config-derived classes."); - } - } - } - private static bool ViolatesPureMethodRules(MethodInfo method) - { - try - { - var body = method.GetMethodBody(); - if (body == null) - return false; - - var il = body.GetILAsByteArray(); - if (il == null) - return false; - - // Look for IL opcodes that store data or call setters - for (int i = 0; i < il.Length - 1; i++) - { - byte b = il[i]; - byte next = il[i + 1]; - - // Store field (stfld or stsfld) - if (b == 0x7D || b == 0x80) - return true; - - // Callvirt / call that might be setter - if (b == 0x28) - { - var tokens = method.Module.ResolveMethod(BitConverter.ToInt32(il, i + 1)); - if (tokens.Name.StartsWith("set_", StringComparison.Ordinal)) - return true; - } - } - } - catch - { - // Ignore methods that can't be inspected - } - - return false; - } - } -#endif - -} \ No newline at end of file diff --git a/Editor/Core/Definitions/PrefabDrawer.cs b/Editor/Core/Definitions/PrefabDrawer.cs deleted file mode 100644 index 7962de34..00000000 --- a/Editor/Core/Definitions/PrefabDrawer.cs +++ /dev/null @@ -1,117 +0,0 @@ -#if UNITY_EDITOR -using UnityEditor; -using UnityEngine; -using System; - -namespace RealMethod.Editor -{ - [CustomPropertyDrawer(typeof(PrefabCore), true)] - public class PrefabDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - SerializedProperty prefabGOProp = property.FindPropertyRelative("PrefabAsset"); - - if (prefabGOProp == null) - { - EditorGUI.LabelField(position, label.text, "Invalid Prefab Field"); - return; - } - - EditorGUI.BeginProperty(position, label, property); - - UnityEngine.Object newObject = EditorGUI.ObjectField( - position, - label, - prefabGOProp.objectReferenceValue, - typeof(GameObject), - false - ); - - if (newObject != prefabGOProp.objectReferenceValue) - { - if (newObject == null) - { - prefabGOProp.objectReferenceValue = null; - } - else if (PrefabUtility.IsPartOfPrefabAsset(newObject)) - { - GameObject go = newObject as GameObject; - - // Get the actual object instance for this SerializedProperty - PrefabCore targetPrefab = GetTargetObjectOfProperty(property) as PrefabCore; - - if (targetPrefab == null) - { - EditorGUI.LabelField(position, label.text, "Invalid prefab wrapper."); - return; - } - - var targetClass = targetPrefab.GetTargetClass(); - - if (targetClass != null && go.GetComponent(targetClass) != null) - { - prefabGOProp.objectReferenceValue = newObject; - } - else - { - Debug.LogWarning($"Selected prefab does not have required component: {targetClass?.Name}"); - } - } - else - { - Debug.LogWarning("Only prefab assets from the project can be assigned."); - } - } - - EditorGUI.EndProperty(); - } - - // Utility to get the real object from a SerializedProperty - private object GetTargetObjectOfProperty(SerializedProperty prop) - { - if (prop == null) return null; - - string path = prop.propertyPath.Replace(".Array.data[", "["); - object obj = prop.serializedObject.targetObject; - string[] elements = path.Split('.'); - - foreach (string element in elements) - { - if (element.Contains("[")) - { - string elementName = element.Substring(0, element.IndexOf("[")); - int index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", "")); - obj = GetValue(obj, elementName, index); - } - else - { - obj = GetValue(obj, element); - } - } - return obj; - } - - private object GetValue(object source, string name) - { - if (source == null) return null; - var type = source.GetType(); - var f = type.GetField(name, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); - if (f == null) return null; - return f.GetValue(source); - } - - private object GetValue(object source, string name, int index) - { - var enumerable = GetValue(source, name) as System.Collections.IEnumerable; - if (enumerable == null) return null; - var enm = enumerable.GetEnumerator(); - for (int i = 0; i <= index; i++) - { - if (!enm.MoveNext()) return null; - } - return enm.Current; - } - } -} -#endif diff --git a/Editor/Library/Vendor/SerializableDictionary.meta b/Editor/Core/Drawers.meta similarity index 77% rename from Editor/Library/Vendor/SerializableDictionary.meta rename to Editor/Core/Drawers.meta index 52041f27..c71d71ad 100644 --- a/Editor/Library/Vendor/SerializableDictionary.meta +++ b/Editor/Core/Drawers.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8c73a086c2d5b9142b2f8d4d8befecfe +guid: 4b2ca676aa99da945bf729d345f81474 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Runtime/Core/Attributes/ExpandableAttribute.cs b/Editor/Core/Drawers/AssetInlinDrawer.cs similarity index 79% rename from Runtime/Core/Attributes/ExpandableAttribute.cs rename to Editor/Core/Drawers/AssetInlinDrawer.cs index eaf64240..6d602555 100644 --- a/Runtime/Core/Attributes/ExpandableAttribute.cs +++ b/Editor/Core/Drawers/AssetInlinDrawer.cs @@ -1,35 +1,18 @@ using System; +using System.Collections.Generic; +using UnityEditor; using UnityEngine; -namespace RealMethod +namespace RealMethod.Editor { - -#if UNITY_EDITOR - using System.Collections.Generic; - using UnityEditor; -#endif - - /// - /// Use this property on a ScriptableObject type to allow the editors drawing the field to draw an expandable - /// area that allows for changing the values on the object without having to change editor. - /// - public class ExpandableAttribute : PropertyAttribute - { - public ExpandableAttribute() - { - - } - } - -#if UNITY_EDITOR /// /// Draws the property field for any field marked with ExpandableAttribute. /// - [CustomPropertyDrawer(typeof(ExpandableAttribute), true)] - public class ExpandableAttributeDrawer : PropertyDrawer + [CustomPropertyDrawer(typeof(AssetInlinAttribute), true)] + public class AssetInlinDrawer : PropertyDrawer { + // Style Setup // Use the following area to change the style of the expandable ScriptableObject drawers; - #region Style Setup private enum BackgroundStyles { None, @@ -37,42 +20,37 @@ private enum BackgroundStyles Darken, Lighten } - + /// /// Whether the default editor Script field should be shown. /// private static bool SHOW_SCRIPT_FIELD = false; - /// /// The spacing on the inside of the background rect. /// private static float INNER_SPACING = 6.0f; - /// /// The spacing on the outside of the background rect. /// private static float OUTER_SPACING = 4.0f; - /// /// The style the background uses. /// private static BackgroundStyles BACKGROUND_STYLE = BackgroundStyles.HelpBox; - /// /// The colour that is used to darken the background. /// private static Color DARKEN_COLOUR = new Color(0.0f, 0.0f, 0.0f, 0.2f); - /// /// The colour that is used to lighten the background. /// private static Color LIGHTEN_COLOUR = new Color(1.0f, 1.0f, 1.0f, 0.2f); - #endregion + /// /// Cached editor reference. /// - private Editor editor = null; + private UnityEditor.Editor editor = null; public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { @@ -87,7 +65,7 @@ public override float GetPropertyHeight(SerializedProperty property, GUIContent return totalHeight; if (editor == null) - Editor.CreateCachedEditor(property.objectReferenceValue, null, ref editor); + UnityEditor.Editor.CreateCachedEditor(property.objectReferenceValue, null, ref editor); if (editor == null) return totalHeight; @@ -111,7 +89,6 @@ public override float GetPropertyHeight(SerializedProperty property, GUIContent return totalHeight; } - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { Rect fieldRect = new Rect(position); @@ -119,11 +96,11 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten EditorGUI.PropertyField(fieldRect, property, label, true); - if (property.objectReferenceValue == null) - { - Debug.Log("It's secretly null"); - return; - } + // if (property.objectReferenceValue == null) + // { + // Debug.Log("It's secretly null"); + // return; + // } property.isExpanded = EditorGUI.Foldout(fieldRect, property.isExpanded, GUIContent.none, true); @@ -131,7 +108,7 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten return; if (editor == null) - Editor.CreateCachedEditor(property.objectReferenceValue, null, ref editor); + UnityEditor.Editor.CreateCachedEditor(property.objectReferenceValue, null, ref editor); if (editor == null) { @@ -211,6 +188,7 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten #endregion } + /// /// Draws the Background /// @@ -235,21 +213,7 @@ private void DrawBackground(Rect rect) } } - /// - /// Required for the fetching of a default editor on MonoBehaviour objects. - /// - [CanEditMultipleObjects] - [CustomEditor(typeof(MonoBehaviour), true)] - public class MonoBehaviourEditor : Editor { } + - /// - /// Required for the fetching of a default editor on ScriptableObject objects. - /// - [CanEditMultipleObjects] - [CustomEditor(typeof(ScriptableObject), true)] - public class ScriptableObjectEditor : Editor { } -#endif -} -// ----Use -//[Expandable] -//public ScriptableObject TEST; \ No newline at end of file + +} \ No newline at end of file diff --git a/Editor/Core/Drawers/AssetInlinDrawer.cs.meta b/Editor/Core/Drawers/AssetInlinDrawer.cs.meta new file mode 100644 index 00000000..845d3428 --- /dev/null +++ b/Editor/Core/Drawers/AssetInlinDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4d330d952dca5b1429429089ed414c8a \ No newline at end of file diff --git a/Editor/Core/Drawers/AssetsDrawer.cs b/Editor/Core/Drawers/AssetsDrawer.cs new file mode 100644 index 00000000..c772820d --- /dev/null +++ b/Editor/Core/Drawers/AssetsDrawer.cs @@ -0,0 +1,17 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(PrimitiveAsset), true)] + public class Asset_Drawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + Color prevColor = GUI.color; + GUI.color = new Color(1f, 0.8f, 0.8f); + EditorGUI.PropertyField(position, property, label, true); + GUI.color = prevColor; + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/AssetsDrawer.cs.meta b/Editor/Core/Drawers/AssetsDrawer.cs.meta new file mode 100644 index 00000000..5f2cec98 --- /dev/null +++ b/Editor/Core/Drawers/AssetsDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a177970772cd9c04184171cfabfc6ae9 \ No newline at end of file diff --git a/Editor/Core/Drawers/ColorFieldDrawet.cs b/Editor/Core/Drawers/ColorFieldDrawet.cs new file mode 100644 index 00000000..0fa3b795 --- /dev/null +++ b/Editor/Core/Drawers/ColorFieldDrawet.cs @@ -0,0 +1,19 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(ColorFieldAttribute))] + public class RequiredFieldDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + ColorFieldAttribute field = attribute as ColorFieldAttribute; + + GUI.color = field.color; //Set the color of the GUI + EditorGUI.PropertyField(position, property, label); //Draw the GUI + GUI.color = Color.white; //Reset the color of the GUI to white + + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/ColorFieldDrawet.cs.meta b/Editor/Core/Drawers/ColorFieldDrawet.cs.meta new file mode 100644 index 00000000..658df024 --- /dev/null +++ b/Editor/Core/Drawers/ColorFieldDrawet.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: eeddf87aa2f38034791a447abc095062 \ No newline at end of file diff --git a/Editor/Core/Drawers/ConditionalHideByEnumDrawer.cs b/Editor/Core/Drawers/ConditionalHideByEnumDrawer.cs new file mode 100644 index 00000000..7d9be6a9 --- /dev/null +++ b/Editor/Core/Drawers/ConditionalHideByEnumDrawer.cs @@ -0,0 +1,54 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(ConditionalHideByEnumAttribute))] + public class ConditionalHideByEnumDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var attr = (ConditionalHideByEnumAttribute)attribute; + + // Build sibling path: replace "UseAsset" with "Mode", etc. + string enumPath = property.propertyPath.Replace(property.name, attr.EnumFieldName); + SerializedProperty enumField = property.serializedObject.FindProperty(enumPath); + + if (enumField != null && !ShouldHide(enumField, attr.HideValues)) + { + EditorGUI.PropertyField(position, property, label, true); + } + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + var attr = (ConditionalHideByEnumAttribute)attribute; + + // Must use the SAME path logic as in OnGUI + string enumPath = property.propertyPath.Replace(property.name, attr.EnumFieldName); + SerializedProperty enumField = property.serializedObject.FindProperty(enumPath); + + if (enumField != null && !ShouldHide(enumField, attr.HideValues)) + { + return EditorGUI.GetPropertyHeight(property, label, true); + } + + // fully hide line + return -EditorGUIUtility.standardVerticalSpacing; + } + + private bool ShouldHide(SerializedProperty enumField, object[] hideValues) + { + if (enumField.propertyType == SerializedPropertyType.Enum) + { + foreach (var value in hideValues) + { + if (enumField.enumValueIndex == (int)value) + return true; // hide when enum matches any of these + } + } + + return false; + } + } +} diff --git a/Editor/Core/Drawers/ConditionalHideByEnumDrawer.cs.meta b/Editor/Core/Drawers/ConditionalHideByEnumDrawer.cs.meta new file mode 100644 index 00000000..f4b02353 --- /dev/null +++ b/Editor/Core/Drawers/ConditionalHideByEnumDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 07df77986e5a9f64eb6288db1009335b \ No newline at end of file diff --git a/Editor/Core/Drawers/ConditionalHideDrawer.cs b/Editor/Core/Drawers/ConditionalHideDrawer.cs new file mode 100644 index 00000000..7d6df370 --- /dev/null +++ b/Editor/Core/Drawers/ConditionalHideDrawer.cs @@ -0,0 +1,69 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(ConditionalHideAttribute))] + public class ConditionalHidePropertyDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + ConditionalHideAttribute condHAtt = (ConditionalHideAttribute)attribute; + bool enabled = GetConditionalHideAttributeResult(condHAtt, property); + + if (!condHAtt.HideInInspector || enabled) + { + return EditorGUI.GetPropertyHeight(property, label); + } + else + { + return -EditorGUIUtility.standardVerticalSpacing; + } + } + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + ConditionalHideAttribute condHAtt = (ConditionalHideAttribute)attribute; + bool enabled = GetConditionalHideAttributeResult(condHAtt, property); + + bool wasEnabled = GUI.enabled; + GUI.enabled = enabled; + + if (!condHAtt.HideInInspector || enabled) + { + EditorGUI.PropertyField(position, property, label, true); + } + + GUI.enabled = wasEnabled; + } + + + + private bool GetConditionalHideAttributeResult(ConditionalHideAttribute condHAtt, SerializedProperty property) + { + bool enabled = true; + + string propertyPath = property.propertyPath; // returns the property path of the property we want to apply the attribute to + string conditionPath = propertyPath.Replace(property.name, condHAtt.ConditionalSourceField); // changes the path to the conditionalsource property path + SerializedProperty sourcePropertyValue = property.serializedObject.FindProperty(conditionPath); + + if (sourcePropertyValue != null) + { + if (!condHAtt.ReverceCondition) + { + enabled = sourcePropertyValue.boolValue; + } + else + { + enabled = !sourcePropertyValue.boolValue; + } + + } + else + { + Debug.LogWarning("Attempting to use a ConditionalHideAttribute but no matching SourcePropertyValue found in object: " + condHAtt.ConditionalSourceField); + } + + return enabled; + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/ConditionalHideDrawer.cs.meta b/Editor/Core/Drawers/ConditionalHideDrawer.cs.meta new file mode 100644 index 00000000..6c85b642 --- /dev/null +++ b/Editor/Core/Drawers/ConditionalHideDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 47ed489e327ef2e41b5047aaa4bc4d7d \ No newline at end of file diff --git a/Editor/Core/Drawers/ConditionalShowByEnumDrawer.cs b/Editor/Core/Drawers/ConditionalShowByEnumDrawer.cs new file mode 100644 index 00000000..0d41b4ed --- /dev/null +++ b/Editor/Core/Drawers/ConditionalShowByEnumDrawer.cs @@ -0,0 +1,53 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(ConditionalShowByEnumAttribute))] + public class ConditionalShowByEnumDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var attr = (ConditionalShowByEnumAttribute)attribute; + + // Build sibling path: replace "UseAsset" with "Mode", etc. + string enumPath = property.propertyPath.Replace(property.name, attr.EnumFieldName); + SerializedProperty enumField = property.serializedObject.FindProperty(enumPath); + + if (enumField != null && IsVisible(enumField, attr.ShowValues)) + { + EditorGUI.PropertyField(position, property, label); + } + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + var attr = (ConditionalShowByEnumAttribute)attribute; + + // Must use the SAME path logic as in OnGUI + string enumPath = property.propertyPath.Replace(property.name, attr.EnumFieldName); + SerializedProperty enumField = property.serializedObject.FindProperty(enumPath); + + if (enumField != null && IsVisible(enumField, attr.ShowValues)) + { + return EditorGUI.GetPropertyHeight(property, label, true); + } + + // fully hide line + return -EditorGUIUtility.standardVerticalSpacing; + } + + private bool IsVisible(SerializedProperty enumField, object[] showValues) + { + foreach (var value in showValues) + { + if (enumField.propertyType == SerializedPropertyType.Enum && enumField.enumValueIndex == (int)value) + { + return true; + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/ConditionalShowByEnumDrawer.cs.meta b/Editor/Core/Drawers/ConditionalShowByEnumDrawer.cs.meta new file mode 100644 index 00000000..054c05a8 --- /dev/null +++ b/Editor/Core/Drawers/ConditionalShowByEnumDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: efb65d24cd2c9e04c867b0cae6a7d5ef \ No newline at end of file diff --git a/Runtime/Core/Attributes/EnumDescriptionAttribute.cs b/Editor/Core/Drawers/DescriptionEnumDrawer.cs similarity index 66% rename from Runtime/Core/Attributes/EnumDescriptionAttribute.cs rename to Editor/Core/Drawers/DescriptionEnumDrawer.cs index 713b9da5..5f802a4c 100644 --- a/Runtime/Core/Attributes/EnumDescriptionAttribute.cs +++ b/Editor/Core/Drawers/DescriptionEnumDrawer.cs @@ -1,28 +1,11 @@ using System; -using UnityEngine; -#if UNITY_EDITOR using UnityEditor; -#endif +using UnityEngine; -namespace RealMethod +namespace RealMethod.Editor { - [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] - public class EnumDescriptionAttribute : PropertyAttribute - { - public string Description { get; } - - public EnumDescriptionAttribute(string description) - { - Description = description; - } - } - - -#if UNITY_EDITOR - - - [CustomPropertyDrawer(typeof(EnumDescriptionAttribute))] - public class EnumWithDescriptionsDrawer : PropertyDrawer + [CustomPropertyDrawer(typeof(DescriptionEnumAttribute))] + public class DescriptionEnumDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { @@ -60,26 +43,11 @@ private string[] GetEnumDescriptions(Type enumType) for (int i = 0; i < names.Length; i++) { var field = enumType.GetField(names[i]); - var descriptionAttribute = Attribute.GetCustomAttribute(field, typeof(EnumDescriptionAttribute)) as EnumDescriptionAttribute; + var descriptionAttribute = Attribute.GetCustomAttribute(field, typeof(DescriptionEnumAttribute)) as DescriptionEnumAttribute; descriptions[i] = descriptionAttribute != null ? descriptionAttribute.Description : names[i]; } return descriptions; } } -#endif -} - - -//////Use -// public enum MyEnumWithDescriptions -// { -// [EnumDescription("This is the first option.")] -// Option1, - -// [EnumDescription("This is the second option.")] -// Option2, - -// [EnumDescription("This is the third option.")] -// Option3 -// } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/DescriptionEnumDrawer.cs.meta b/Editor/Core/Drawers/DescriptionEnumDrawer.cs.meta new file mode 100644 index 00000000..05ee81f3 --- /dev/null +++ b/Editor/Core/Drawers/DescriptionEnumDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 16a6b6f8280e964489d2e6b7629652a9 \ No newline at end of file diff --git a/Editor/Core/Drawers/DropdownDrawer.cs b/Editor/Core/Drawers/DropdownDrawer.cs new file mode 100644 index 00000000..0bc2d7f8 --- /dev/null +++ b/Editor/Core/Drawers/DropdownDrawer.cs @@ -0,0 +1,31 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(DropdownAttribute))] + public class DropdownDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + DropdownAttribute dropdownAttribute = (DropdownAttribute)attribute; + + if (property.propertyType == SerializedPropertyType.String) + { + int index = Mathf.Max(0, System.Array.IndexOf(dropdownAttribute.options, property.stringValue)); + index = EditorGUI.Popup(position, label.text, index, dropdownAttribute.options); + property.stringValue = dropdownAttribute.options[index]; + } + else if (property.propertyType == SerializedPropertyType.Integer) + { + int index = Mathf.Clamp(property.intValue, 0, dropdownAttribute.options.Length - 1); + index = EditorGUI.Popup(position, label.text, index, dropdownAttribute.options); + property.intValue = index; + } + else + { + EditorGUI.LabelField(position, label.text, "Use Dropdown with string or int."); + } + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/DropdownDrawer.cs.meta b/Editor/Core/Drawers/DropdownDrawer.cs.meta new file mode 100644 index 00000000..8003b34b --- /dev/null +++ b/Editor/Core/Drawers/DropdownDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 93150ce5c26a6bd44b4f1552fc8553b3 \ No newline at end of file diff --git a/Editor/Core/Drawers/DropdownFromArrayDrawer.cs b/Editor/Core/Drawers/DropdownFromArrayDrawer.cs new file mode 100644 index 00000000..19c58842 --- /dev/null +++ b/Editor/Core/Drawers/DropdownFromArrayDrawer.cs @@ -0,0 +1,53 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(DropdownFromArrayAttribute))] + public class DropdownFromArrayDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + DropdownFromArrayAttribute dropdownAttribute = (DropdownFromArrayAttribute)attribute; + string[] options = GetOptions(property, dropdownAttribute.TargetArray); + + if (options != null && options.Length > 0) + { + if (property.propertyType == SerializedPropertyType.String) + { + int index = Mathf.Max(0, System.Array.IndexOf(options, property.stringValue)); + index = EditorGUI.Popup(position, label.text, index, options); + property.stringValue = options[index]; + } + else + { + EditorGUI.LabelField(position, label.text, "Use DropdownFromArray with string."); + } + } + else + { + EditorGUI.LabelField(position, label.text, "Array not found or empty."); + } + } + + private string[] GetOptions(SerializedProperty property, string targetArry) + { + string[] options = null; + Object targetObject = property.serializedObject.targetObject; + System.Type targetType = targetObject.GetType(); + System.Reflection.FieldInfo fieldInfo = targetType.GetField(targetArry); + + if (fieldInfo != null) + { + options = fieldInfo.GetValue(targetObject) as string[]; + } + + return options; + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUI.GetPropertyHeight(property, label, true); + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/DropdownFromArrayDrawer.cs.meta b/Editor/Core/Drawers/DropdownFromArrayDrawer.cs.meta new file mode 100644 index 00000000..d5209d00 --- /dev/null +++ b/Editor/Core/Drawers/DropdownFromArrayDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ad31a5019cd88d54c94626d1bbb037aa \ No newline at end of file diff --git a/Editor/Core/Drawers/DropdownFromDictionaryDrawer.cs b/Editor/Core/Drawers/DropdownFromDictionaryDrawer.cs new file mode 100644 index 00000000..17fec49d --- /dev/null +++ b/Editor/Core/Drawers/DropdownFromDictionaryDrawer.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(DropdownFromDictionaryAttribute))] + public class DropdownFromDictionaryDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + DropdownFromDictionaryAttribute dropdownAttribute = (DropdownFromDictionaryAttribute)attribute; + string[] options = GetOptions(property, dropdownAttribute.dictionaryFieldName); + + if (options != null && options.Length > 0) + { + if (property.propertyType == SerializedPropertyType.String) + { + int index = Mathf.Max(0, System.Array.IndexOf(options, property.stringValue)); + index = EditorGUI.Popup(position, label.text, index, options); + property.stringValue = options[index]; + } + else + { + EditorGUI.LabelField(position, label.text, "Use DropdownFromDictionary with string."); + } + } + else + { + EditorGUI.LabelField(position, label.text, "Dictionary not found or empty."); + } + } + + private string[] GetOptions(SerializedProperty property, string dictionaryFieldName) + { + string[] options = null; + Object targetObject = property.serializedObject.targetObject; + System.Type targetType = targetObject.GetType(); + System.Reflection.FieldInfo fieldInfo = targetType.GetField(dictionaryFieldName); + + if (fieldInfo != null) + { + var dictionary = fieldInfo.GetValue(targetObject) as Dictionary; + if (dictionary != null) + { + options = new string[dictionary.Count]; + dictionary.Keys.CopyTo(options, 0); + } + } + + return options; + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUI.GetPropertyHeight(property, label, true); + } + } + +} \ No newline at end of file diff --git a/Editor/Core/Drawers/DropdownFromDictionaryDrawer.cs.meta b/Editor/Core/Drawers/DropdownFromDictionaryDrawer.cs.meta new file mode 100644 index 00000000..b982d39e --- /dev/null +++ b/Editor/Core/Drawers/DropdownFromDictionaryDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: dd4e08a9c9afbc649ba64dc8a002168c \ No newline at end of file diff --git a/Editor/Core/Drawers/GlobalEnumDrawer.cs b/Editor/Core/Drawers/GlobalEnumDrawer.cs new file mode 100644 index 00000000..9c21d5b7 --- /dev/null +++ b/Editor/Core/Drawers/GlobalEnumDrawer.cs @@ -0,0 +1,40 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(GlobalEnum))] + public class GlobalEnumDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty valueProp = property.FindPropertyRelative("Value"); + int index = valueProp.intValue; + + if (RM_Editor.TryGetSettingAsset(out ProjectSettingAsset setting)) + { + string[] names = setting.Status.ToArray(); + + if (index >= 0 && index < names.Length) + { + int newIndex = EditorGUI.Popup(position, label.text, index, names); + valueProp.intValue = newIndex; + } + else + { + Color prev = GUI.color; + GUI.color = Color.red; + EditorGUI.LabelField(position, $"{label.text} [{index}]: Not Defined!"); + GUI.color = prev; + } + } + else + { + Color prev = GUI.color; + GUI.color = Color.yellow; + EditorGUI.LabelField(position, $"{label.text} [{index}]: Can't load ProjectSettingAsset."); + GUI.color = prev; + } + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/GlobalEnumDrawer.cs.meta b/Editor/Core/Drawers/GlobalEnumDrawer.cs.meta new file mode 100644 index 00000000..2ea542e7 --- /dev/null +++ b/Editor/Core/Drawers/GlobalEnumDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b498f42342792244b9f4ab755fd39a70 \ No newline at end of file diff --git a/Editor/Core/Drawers/HelpBoxDrawer.cs b/Editor/Core/Drawers/HelpBoxDrawer.cs new file mode 100644 index 00000000..17c6f60e --- /dev/null +++ b/Editor/Core/Drawers/HelpBoxDrawer.cs @@ -0,0 +1,30 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(HelpBoxAttribute))] + public class HelpBoxDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + HelpBoxAttribute helpBoxAttribute = (HelpBoxAttribute)attribute; + EditorGUI.BeginProperty(position, label, property); + // Calculate the height of the help box + var helpBoxHeight = EditorGUIUtility.singleLineHeight * helpBoxAttribute.height; + var helpBoxRect = new Rect(position.x, position.y, position.width, helpBoxHeight); + EditorGUI.HelpBox(helpBoxRect, helpBoxAttribute.text, (MessageType)helpBoxAttribute.messageType); + // Calculate the position of the property field + var propertyRect = new Rect(position.x, position.y + helpBoxHeight + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); + EditorGUI.PropertyField(propertyRect, property, label); + EditorGUI.EndProperty(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + HelpBoxAttribute helpBoxAttribute = (HelpBoxAttribute)attribute; + var helpBoxHeight = EditorGUIUtility.singleLineHeight * 2; + return helpBoxHeight + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/HelpBoxDrawer.cs.meta b/Editor/Core/Drawers/HelpBoxDrawer.cs.meta new file mode 100644 index 00000000..f9d948e8 --- /dev/null +++ b/Editor/Core/Drawers/HelpBoxDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7dc2a9809fb29c84f99cf655165efe0f \ No newline at end of file diff --git a/Editor/Core/Drawers/LayerDrawer.cs b/Editor/Core/Drawers/LayerDrawer.cs new file mode 100644 index 00000000..c65b375f --- /dev/null +++ b/Editor/Core/Drawers/LayerDrawer.cs @@ -0,0 +1,21 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(LayerAttribute))] + public class LayerDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (property.propertyType == SerializedPropertyType.Integer) + { + property.intValue = EditorGUI.LayerField(position, label, property.intValue); + } + else + { + EditorGUI.LabelField(position, label.text, "Use [Layer] with int."); + } + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/LayerDrawer.cs.meta b/Editor/Core/Drawers/LayerDrawer.cs.meta new file mode 100644 index 00000000..626a7fe8 --- /dev/null +++ b/Editor/Core/Drawers/LayerDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: af5212a855fb5084d898aba471657705 \ No newline at end of file diff --git a/Editor/Core/Drawers/LineDrawer.cs b/Editor/Core/Drawers/LineDrawer.cs new file mode 100644 index 00000000..b13c274d --- /dev/null +++ b/Editor/Core/Drawers/LineDrawer.cs @@ -0,0 +1,39 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(LineAttribute))] + public class LineDrawer : DecoratorDrawer + { + public override void OnGUI(Rect position) + { + // get a reference to the attribute + LineAttribute separatorAttribute + = attribute as LineAttribute; + // define the line to draw + Rect separatorRect = new Rect(position.xMin, + position.yMin + separatorAttribute.Spacing, + position.width, + separatorAttribute.Height); + // draw it + Color lineColor = EditorGUIUtility.isProSkin + ? new Color(0.2f, 0.2f, 0.2f, 1) + : new Color(0.7f, 0.7f, 0.7f, 1); + + EditorGUI.DrawRect(separatorRect, lineColor); + } + + public override float GetHeight() + { + LineAttribute separatorAttribute + = attribute as LineAttribute; + + float totalSpacing = separatorAttribute.Spacing + + separatorAttribute.Height + + separatorAttribute.Spacing; + + return totalSpacing; + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/LineDrawer.cs.meta b/Editor/Core/Drawers/LineDrawer.cs.meta new file mode 100644 index 00000000..62243d73 --- /dev/null +++ b/Editor/Core/Drawers/LineDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e2604c09d5b614044a87657f1f3c6b54 \ No newline at end of file diff --git a/Editor/Core/Drawers/MinMaxRangeDrawer.cs b/Editor/Core/Drawers/MinMaxRangeDrawer.cs new file mode 100644 index 00000000..a1ab2628 --- /dev/null +++ b/Editor/Core/Drawers/MinMaxRangeDrawer.cs @@ -0,0 +1,51 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(MinMaxRangeAttribute))] + public class MinMaxRangeDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (property.propertyType == SerializedPropertyType.Vector2) + { + MinMaxRangeAttribute range = (MinMaxRangeAttribute)attribute; + + Vector2 value = property.vector2Value; + + EditorGUI.BeginProperty(position, label, property); + + // Draw label + position = EditorGUI.PrefixLabel(position, label); + + // Draw min-max slider + float min = value.x; + float max = value.y; + + float sliderWidth = position.width * 0.6f; + float fieldWidth = (position.width - sliderWidth) / 2f; + + Rect minFieldRect = new Rect(position.x, position.y, fieldWidth - 2, position.height); + Rect sliderRect = new Rect(position.x + fieldWidth, position.y, sliderWidth, position.height); + Rect maxFieldRect = new Rect(position.x + fieldWidth + sliderWidth + 2, position.y, fieldWidth - 2, position.height); + + min = EditorGUI.FloatField(minFieldRect, min); + EditorGUI.MinMaxSlider(sliderRect, ref min, ref max, range.minLimit, range.maxLimit); + max = EditorGUI.FloatField(maxFieldRect, max); + + // Clamp values + min = Mathf.Clamp(min, range.minLimit, max); + max = Mathf.Clamp(max, min, range.maxLimit); + + property.vector2Value = new Vector2(min, max); + + EditorGUI.EndProperty(); + } + else + { + EditorGUI.LabelField(position, label.text, "Use MinMaxRange with Vector2"); + } + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/MinMaxRangeDrawer.cs.meta b/Editor/Core/Drawers/MinMaxRangeDrawer.cs.meta new file mode 100644 index 00000000..b0639726 --- /dev/null +++ b/Editor/Core/Drawers/MinMaxRangeDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 06fcdbe99bffac94b949f0b3d29aabe7 \ No newline at end of file diff --git a/Editor/Core/Drawers/Name16Drawer.cs b/Editor/Core/Drawers/Name16Drawer.cs new file mode 100644 index 00000000..aeb20013 --- /dev/null +++ b/Editor/Core/Drawers/Name16Drawer.cs @@ -0,0 +1,49 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(Name16))] + public class Name16Drawer : PropertyDrawer + { + const int MaxLength = 16; + static readonly Color Tint = new Color(1f, 0.82f, 0.9f); // very light pink + + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var aProp = property.FindPropertyRelative("Name_A"); + var bProp = property.FindPropertyRelative("Name_B"); + + Name16 value = new Name16(); + value.Name_A = (ulong)aProp.longValue; + value.Name_B = (ulong)bProp.longValue; + + string text = value.ToString(); + + EditorGUI.BeginProperty(position, label, property); + + Color oldColor = GUI.color; + GUI.color = Tint; // apply pink tint + + EditorGUI.BeginChangeCheck(); + string newText = EditorGUI.TextField(position, label, text); + + GUI.color = oldColor; // restore color + + if (EditorGUI.EndChangeCheck()) + { + if (newText.Length > MaxLength) + newText = newText.Substring(0, MaxLength); + + Name16 newValue = new Name16(newText); + + aProp.longValue = (long)newValue.Name_A; + bProp.longValue = (long)newValue.Name_B; + } + + EditorGUI.EndProperty(); + } + } + +} \ No newline at end of file diff --git a/Editor/Core/Drawers/Name16Drawer.cs.meta b/Editor/Core/Drawers/Name16Drawer.cs.meta new file mode 100644 index 00000000..efbed6d5 --- /dev/null +++ b/Editor/Core/Drawers/Name16Drawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2ddcecdd6b6816a40926f6a6d2ac2a9a \ No newline at end of file diff --git a/Runtime/Core/Attributes/ListToPopupAttribute.cs b/Editor/Core/Drawers/PopupListDrawer.cs similarity index 64% rename from Runtime/Core/Attributes/ListToPopupAttribute.cs rename to Editor/Core/Drawers/PopupListDrawer.cs index 86c823d9..b0a93d10 100644 --- a/Runtime/Core/Attributes/ListToPopupAttribute.cs +++ b/Editor/Core/Drawers/PopupListDrawer.cs @@ -1,33 +1,16 @@ -using System; using System.Collections.Generic; using System.Reflection; -#if UNITY_EDITOR using UnityEditor; -#endif using UnityEngine; -namespace RealMethod +namespace RealMethod.Editor { - public class ListToPopupAttribute : PropertyAttribute - { - public Type myType; - public string propertyName; - - public ListToPopupAttribute(Type _myType, string _propertyName) - { - myType = _myType; - propertyName = _propertyName; - } - } - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(ListToPopupAttribute))] - public class ListToPopupDrawer : PropertyDrawer + [CustomPropertyDrawer(typeof(PopupListAttribute))] + public class PopupListDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - ListToPopupAttribute atb = attribute as ListToPopupAttribute; + PopupListAttribute atb = attribute as PopupListAttribute; List stringList = null; // Get the field using reflection @@ -57,10 +40,4 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten } } } - -#endif -} -// ------------Use -// [ListToPopup(typeof(ExampleClass), "options")] -// public string selectedOption; -// public static List options = new List { "Option1", "Option2", "Option3" }; +} \ No newline at end of file diff --git a/Editor/Core/Drawers/PopupListDrawer.cs.meta b/Editor/Core/Drawers/PopupListDrawer.cs.meta new file mode 100644 index 00000000..6c9a03b0 --- /dev/null +++ b/Editor/Core/Drawers/PopupListDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a289ef88415dda149980554c00cc8cfe \ No newline at end of file diff --git a/Editor/Core/Drawers/PrefabCoreDrawer.cs b/Editor/Core/Drawers/PrefabCoreDrawer.cs new file mode 100644 index 00000000..16ad77ff --- /dev/null +++ b/Editor/Core/Drawers/PrefabCoreDrawer.cs @@ -0,0 +1,78 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(PrefabCore), true)] + public class PrefabCore_Drawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prefabGOProp = property.FindPropertyRelative("PrefabAsset"); + + if (prefabGOProp == null) + { + EditorGUI.LabelField(position, label.text, "Cannot serialize generic prefab"); + return; + } + + EditorGUI.BeginProperty(position, label, property); + + // Determine label text + // string displayLabel = prefabGOProp.objectReferenceValue != null ? label.text: $"{label.text} (Select a prefab...)"; + + // Draw the ObjectField for GameObject + UnityEngine.Object newObject = EditorGUI.ObjectField( + position, + label, + prefabGOProp.objectReferenceValue, + typeof(GameObject), + false + ); + + // Only update if changed + if (newObject != prefabGOProp.objectReferenceValue) + { + if (newObject == null) + { + prefabGOProp.objectReferenceValue = null; + } + else if (PrefabUtility.IsPartOfPrefabAsset(newObject)) + { + // Get the concrete PrefabCore instance + PrefabCore targetPrefab = fieldInfo.GetValue(property.serializedObject.targetObject) as PrefabCore; + + if (targetPrefab == null) + { + Debug.LogWarning("Invalid prefab wrapper."); + return; + } + + var targetClass = targetPrefab.GetMainType(); + GameObject go = newObject as GameObject; + + // Type-check: the prefab must have the required component + if (targetClass != null && go.GetComponent(targetClass) != null) + { + prefabGOProp.objectReferenceValue = newObject; + } + else + { + Debug.LogWarning($"Selected prefab does not have required component: {targetClass?.Name}"); + } + } + else + { + Debug.LogWarning("Only prefab assets from the project can be assigned."); + } + } + + // --- Set GUI color to blue to indicate change --- + Color prevColor = GUI.color; + GUI.color = Color.cyan; // light blue + EditorGUI.ObjectField(position, label, prefabGOProp.objectReferenceValue, typeof(GameObject), false); + GUI.color = prevColor; + EditorGUI.EndProperty(); + } + } +} diff --git a/Editor/Core/Definitions/PrefabDrawer.cs.meta b/Editor/Core/Drawers/PrefabCoreDrawer.cs.meta similarity index 100% rename from Editor/Core/Definitions/PrefabDrawer.cs.meta rename to Editor/Core/Drawers/PrefabCoreDrawer.cs.meta diff --git a/Editor/Core/Drawers/ReadOnlyDrawer.cs b/Editor/Core/Drawers/ReadOnlyDrawer.cs new file mode 100644 index 00000000..3d0b1ad8 --- /dev/null +++ b/Editor/Core/Drawers/ReadOnlyDrawer.cs @@ -0,0 +1,21 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] + public class ReadOnlyDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + GUI.enabled = false; // Disable the GUI + EditorGUI.PropertyField(position, property, label, true); + GUI.enabled = true; // Enable the GUI + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUI.GetPropertyHeight(property, label, true); + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/ReadOnlyDrawer.cs.meta b/Editor/Core/Drawers/ReadOnlyDrawer.cs.meta new file mode 100644 index 00000000..521007c0 --- /dev/null +++ b/Editor/Core/Drawers/ReadOnlyDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d44334cf564e8644e8c743b8e93b2507 \ No newline at end of file diff --git a/Editor/Core/Drawers/SceneAssetDrawer.cs b/Editor/Core/Drawers/SceneAssetDrawer.cs new file mode 100644 index 00000000..9df5964f --- /dev/null +++ b/Editor/Core/Drawers/SceneAssetDrawer.cs @@ -0,0 +1,68 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(SceneAsset), true)] + public class SceneAssetDrawer : PropertyDrawer + { + private Texture2D checkIcon; + private Texture2D warningIcon; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + // Load icons once + if (checkIcon == null) checkIcon = EditorGUIUtility.IconContent("TestPassed").image as Texture2D; + if (warningIcon == null) warningIcon = EditorGUIUtility.IconContent("console.warnicon").image as Texture2D; + + SerializedProperty sceneAssetProp = property.FindPropertyRelative("Asset"); + SerializedProperty scenePathProp = property.FindPropertyRelative("ScenePath"); + + EditorGUI.BeginProperty(position, label, property); + + // Restrict to SceneAsset type + Rect objectFieldRect = new Rect(position.x, position.y, position.width - 20, position.height); + EditorGUI.PropertyField(objectFieldRect, sceneAssetProp, label); + + if (sceneAssetProp.objectReferenceValue != null) + { + string path = AssetDatabase.GetAssetPath(sceneAssetProp.objectReferenceValue); + scenePathProp.stringValue = path; + + bool isInBuild = IsSceneInBuild(path); + + // Icon display + Rect iconRect = new Rect(position.x + position.width - 16, position.y + 2, 16, 16); + GUI.DrawTexture(iconRect, isInBuild ? checkIcon : warningIcon); + + // Tooltip if not included + if (!isInBuild) + { + GUIContent warningContent = new GUIContent("", "Scene is NOT in the active Build Profile.\nAdd it via File > Build Profiles."); + EditorGUI.LabelField(iconRect, warningContent); + } + } + else + { + scenePathProp.stringValue = string.Empty; + } + + EditorGUI.EndProperty(); + } + + private bool IsSceneInBuild(string scenePath) + { + for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++) + { + string listedScenePath = SceneUtility.GetScenePathByBuildIndex(i); + if (listedScenePath == scenePath) + return true; + } + return false; + } + } +} + + + diff --git a/Editor/Core/Drawers/SceneAssetDrawer.cs.meta b/Editor/Core/Drawers/SceneAssetDrawer.cs.meta new file mode 100644 index 00000000..77fc6bd0 --- /dev/null +++ b/Editor/Core/Drawers/SceneAssetDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 17b36a74fca686a45a451a08879dfe1c \ No newline at end of file diff --git a/Editor/Core/Drawers/ShowOnlyDrawer.cs b/Editor/Core/Drawers/ShowOnlyDrawer.cs new file mode 100644 index 00000000..58c3bd84 --- /dev/null +++ b/Editor/Core/Drawers/ShowOnlyDrawer.cs @@ -0,0 +1,35 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(ShowOnlyAttribute))] + public class ShowOnlyDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + string valueStr; + + switch (prop.propertyType) + { + case SerializedPropertyType.Integer: + valueStr = prop.intValue.ToString(); + break; + case SerializedPropertyType.Boolean: + valueStr = prop.boolValue.ToString(); + break; + case SerializedPropertyType.Float: + valueStr = prop.floatValue.ToString("0.00000"); + break; + case SerializedPropertyType.String: + valueStr = prop.stringValue; + break; + default: + valueStr = "(not supported)"; + break; + } + + EditorGUI.LabelField(position, label.text, valueStr); + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/ShowOnlyDrawer.cs.meta b/Editor/Core/Drawers/ShowOnlyDrawer.cs.meta new file mode 100644 index 00000000..17459bec --- /dev/null +++ b/Editor/Core/Drawers/ShowOnlyDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 24cc41ec6d04b4344b61e6551c7320ef \ No newline at end of file diff --git a/Editor/Core/Drawers/SlugDrawer.cs b/Editor/Core/Drawers/SlugDrawer.cs new file mode 100644 index 00000000..fe09839f --- /dev/null +++ b/Editor/Core/Drawers/SlugDrawer.cs @@ -0,0 +1,22 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +[CustomPropertyDrawer(typeof(SlugAttribute))] +public class SlugDrawer : PropertyDrawer +{ + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SlugAttribute attr = (SlugAttribute)attribute; + + // Draw label normally + position = EditorGUI.PrefixLabel(position, label); + + // Shrink width + position.width *= attr.WidthScale; + + // Draw the text field + EditorGUI.PropertyField(position, property, GUIContent.none); + } +} +#endif diff --git a/Editor/Core/Drawers/SlugDrawer.cs.meta b/Editor/Core/Drawers/SlugDrawer.cs.meta new file mode 100644 index 00000000..fd2254ac --- /dev/null +++ b/Editor/Core/Drawers/SlugDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 943d7c0715f903d4fa0b76804a8f7110 \ No newline at end of file diff --git a/Editor/Core/Drawers/SoftTypeDrawer.cs b/Editor/Core/Drawers/SoftTypeDrawer.cs new file mode 100644 index 00000000..6108b67b --- /dev/null +++ b/Editor/Core/Drawers/SoftTypeDrawer.cs @@ -0,0 +1,59 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(SoftType), true)] + public class SoftTypeDrawer : PropertyDrawer + { + private string[] displayNames; + private string[] typeNames; + private int currentIndex; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var typeProp = property.FindPropertyRelative("typeName"); + + if (displayNames == null) + { + Initialize(typeProp); + if (displayNames.Length > 0) + typeProp.stringValue = typeNames[currentIndex]; + } + + if (displayNames.Length == 0) + { + EditorGUI.LabelField(position, label.text, "No class found"); + return; + } + + int newIndex = EditorGUI.Popup(position, label.text, currentIndex, displayNames); + + if (newIndex != currentIndex) + { + currentIndex = newIndex; + typeProp.stringValue = typeNames[newIndex]; + } + } + + private void Initialize(SerializedProperty property) + { + var baseType = fieldInfo.FieldType.GetGenericArguments()[0]; + + var types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(a => a.GetTypes()) + .Where(t => baseType.IsAssignableFrom(t) && !t.IsAbstract) + .OrderBy(t => t.Name) + .ToArray(); + + displayNames = types.Select(t => t.Name).ToArray(); + typeNames = types.Select(t => t.AssemblyQualifiedName).ToArray(); + + currentIndex = Array.IndexOf(typeNames, property.stringValue); + if (currentIndex < 0) currentIndex = 0; + } + } + +} \ No newline at end of file diff --git a/Editor/Core/Drawers/SoftTypeDrawer.cs.meta b/Editor/Core/Drawers/SoftTypeDrawer.cs.meta new file mode 100644 index 00000000..cc5f48ba --- /dev/null +++ b/Editor/Core/Drawers/SoftTypeDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7d22a982c67c68d4aa07c4bc76bb7282 \ No newline at end of file diff --git a/Editor/Core/Drawers/TagSelectorDrawer.cs b/Editor/Core/Drawers/TagSelectorDrawer.cs new file mode 100644 index 00000000..f45531da --- /dev/null +++ b/Editor/Core/Drawers/TagSelectorDrawer.cs @@ -0,0 +1,31 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(TagSelectorAttribute))] + public class TagSelectorDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + TagSelectorAttribute tagSelector = (TagSelectorAttribute)attribute; + + if (tagSelector.UseDefaultTagFieldDrawer) + { + EditorGUI.PropertyField(position, property, label); + } + else + { + if (property.propertyType == SerializedPropertyType.String) + { + property.stringValue = EditorGUI.TagField(position, label, property.stringValue); + } + else + { + EditorGUI.PropertyField(position, property, label); + EditorGUI.HelpBox(position, "TagSelector can only be used with strings.", MessageType.Error); + } + } + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/TagSelectorDrawer.cs.meta b/Editor/Core/Drawers/TagSelectorDrawer.cs.meta new file mode 100644 index 00000000..b81f84f2 --- /dev/null +++ b/Editor/Core/Drawers/TagSelectorDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c3a11f74a60467949a0aea20cd3c704c \ No newline at end of file diff --git a/Editor/Core/Drawers/TypeSelectorDrawer.cs b/Editor/Core/Drawers/TypeSelectorDrawer.cs new file mode 100644 index 00000000..fdcfa46d --- /dev/null +++ b/Editor/Core/Drawers/TypeSelectorDrawer.cs @@ -0,0 +1,51 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(TypeSelectorAttribute))] + public class TypeSelectorDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + TypeSelectorAttribute typeSelector = (TypeSelectorAttribute)attribute; + + + if (property.propertyType == SerializedPropertyType.String) + { + // Get all types derived from the specified base type + Type[] types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(assembly => assembly.GetTypes()) + .Where(t => typeSelector.BaseType.IsAssignableFrom(t) && !t.IsAbstract) + .ToArray(); + + // Get the current type + string ClassName = property.stringValue; + Type currentType = !string.IsNullOrEmpty(ClassName) ? Type.GetType(ClassName) : null; + + // Get type names for the dropdown + string[] typeNames = types.Select(t => t.FullName).ToArray(); + int currentIndex = Array.IndexOf(typeNames, currentType?.FullName); + + // Show the dropdown in the Inspector + int selectedIndex = EditorGUI.Popup(position, label.text, currentIndex, typeNames); + + // Update the selected type + if (selectedIndex >= 0 && selectedIndex < types.Length) + { + property.stringValue = types[selectedIndex].AssemblyQualifiedName; + } + else + { + property.stringValue = string.Empty; + } + } + else + { + EditorGUI.LabelField(position, label.text, "Use TypeSelector with string."); + } + } + } +} \ No newline at end of file diff --git a/Editor/Core/Drawers/TypeSelectorDrawer.cs.meta b/Editor/Core/Drawers/TypeSelectorDrawer.cs.meta new file mode 100644 index 00000000..7ee35387 --- /dev/null +++ b/Editor/Core/Drawers/TypeSelectorDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bbe6e5799205f324690a4af7e1a541d0 \ No newline at end of file diff --git a/Editor/Core/Definitions.meta b/Editor/Core/InitializeOnLoad.meta similarity index 77% rename from Editor/Core/Definitions.meta rename to Editor/Core/InitializeOnLoad.meta index ff7fd276..6c8fe827 100644 --- a/Editor/Core/Definitions.meta +++ b/Editor/Core/InitializeOnLoad.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 04563dc2f2c64684c987eb7ddde21c3d +guid: efad1f04ce1244c449edfa22bfb8686f folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Editor/Core/InitializeOnLoad/CompileGuard.cs b/Editor/Core/InitializeOnLoad/CompileGuard.cs new file mode 100644 index 00000000..3a0cd574 --- /dev/null +++ b/Editor/Core/InitializeOnLoad/CompileGuard.cs @@ -0,0 +1,249 @@ +using UnityEditor; +using UnityEditor.Compilation; +using System; +using UnityEngine; + + +namespace RealMethod.Editor +{ + /// + /// Base class for creating custom compile-time or editor-time validation rules. + /// Rules are instantiated by CompileGuard and triggered automatically depending + /// on the selected . + /// + public abstract class CompileRule + { + /// + /// Defines when a should be executed by . + /// This controls which editor event triggers the rule validation. + /// + public enum RuleExecutionMode + { + /// + /// Rule runs after Unity finishes compiling scripts. + /// Triggered by . + /// Useful for validating code structure or assets after compilation. + /// + AfterCompilation = 0, + /// + /// Rule runs on the editor update loop after the editor loads. + /// Triggered using . + /// Useful for checks that should occur once the editor is ready. + /// + EditorStartup = 1, + /// + /// Rule runs after the editor has fully returned to Edit Mode. + /// The editor is back to its normal editing state. + /// + EnteredEditMode = 2, + /// + /// Rule runs when the editor is about to leave Edit Mode and start entering Play Mode. + /// This happens before Play Mode is fully active. + /// + ExitingEditMode = 3, + /// + /// Rule runs after the editor has fully entered Play Mode. + /// Game logic is now running. + /// + EnteredPlayMode = 4, + /// + /// Rule runs when the editor is about to stop Play Mode and return to Edit Mode. + /// Game execution is shutting down. + /// + ExitingPlayMode = 5, + } + + + public CompileRule() + { + Initilized(); + } + + + /// + /// Called automatically right after the rule is constructed. + /// Use this to initialize internal data, cache values, or set up + /// anything needed before the rule is used by CompileGuard. + /// + protected abstract void Initilized(); + /// + /// Performs rule initialization for the specified execution mode. + /// This method is called once per mode before any type scanning or rule checks begin. + /// Use it to reset internal state, prepare data, or configure the rule + /// + /// The execution mode for the current validation pass. + public abstract void OnStartCheck(RuleExecutionMode mode); + /// + /// Determines whether this rule can perform a check using the specified + /// execution mode and target type. Override this method in derived classes + /// to define which modes and types the rule supports. + /// + /// The rule execution mode being requested. + /// The target data type to evaluate. + /// + /// True if the rule can check the given mode and type; otherwise, false. + /// + public abstract bool CanCheck(RuleExecutionMode mode, Type type); + /// + /// Called when CompileGuard finds a type that inherits from the rule's base type. + /// Implement validation logic here. This method is invoked automatically for each + /// matching type during the selected rule mode. + /// + /// + /// The discovered type that matches . + /// + public abstract void OnCheck(Type type); + } + + + [InitializeOnLoad] + /// + /// Central system that discovers and executes all CompileRule instances. + /// It triggers rules during compilation or editor updates depending on their mode, + /// and passes every project type that matches the rule's base type. + /// + public static class CompileGuard + { + private static ProjectSettingAsset ProjectSetting_Cache; + private static ProjectSettingAsset ProjectSetting + { + get + { + if (ProjectSetting_Cache == null) + { + if (!RM_Editor.TryGetSettingAsset(out ProjectSetting_Cache)) + { + return null; + } + } + return ProjectSetting_Cache; + } + } + private static System.Reflection.Assembly[] Assemblies; + private static CompileRule[] Rules; + private static bool initialized; + + public static readonly Type[] DefaultRuls = new Type[4] { + // Array of ruls to that should be run always for RealMethod + typeof(ConfigAssetsRule), + typeof(ServiceRule), + typeof(PrimitveAssetsRule), + typeof(PureRule), + }; + + + static CompileGuard() + { + if (!ProjectSetting.CanCompile()) + { + return; + } + + if (initialized) return; + initialized = true; + + CompilationPipeline.compilationFinished += OnCompilationFinished; + EditorApplication.delayCall += OnEditorUpdated; + EditorApplication.playModeStateChanged += OnPlayModeChanged; + } + + private static void OnCompilationFinished(object obj) + { + CheckRuls(CompileRule.RuleExecutionMode.AfterCompilation); + } + private static void OnEditorUpdated() + { + CheckRuls(CompileRule.RuleExecutionMode.EditorStartup); + } + private static void OnPlayModeChanged(PlayModeStateChange state) + { + int index = (int)state + 2; + CheckRuls((CompileRule.RuleExecutionMode)index); + } + + + // Checking process + private static void CheckRuls(CompileRule.RuleExecutionMode mode) + { + if (ProjectSetting == null) + return; + + + if (Rules == null) + { + Type[] RulsClass = ProjectSetting.GetCompileRules(); + if (RulsClass == null) + { + Debug.LogError($"ProjectSetting didn't have Compilerule but compileguard is enable"); + return; + } + + Rules = new CompileRule[RulsClass.Length]; + for (int i = 0; i < RulsClass.Length; i++) + { + if (RulsClass[i] == null) + continue; + + if (typeof(CompileRule).IsAssignableFrom(RulsClass[i])) + { + try + { + Rules[i] = (CompileRule)Activator.CreateInstance(RulsClass[i]); + } + catch (Exception ex) + { + Debug.LogError($"Failed to instantiate {RulsClass[i]}: {ex.Message}."); + return; + } + } + else + { + Debug.LogError($"Type {RulsClass[i]} is not assignable to CompileRule."); + return; + } + } + } + + + if (Assemblies == null) + { + Assemblies = AppDomain.CurrentDomain.GetAssemblies(); + } + + // StartMode + foreach (var rule in Rules) + { + rule.OnStartCheck(mode); + } + + // Checking + Type[] types; + foreach (var assembly in Assemblies) + { + try + { + types = assembly.GetTypes(); + } + catch + { + continue; + } + + foreach (var type in types) + { + foreach (var rule in Rules) + { + if (rule == null) + continue; + if (rule.CanCheck(mode, type) == false) + continue; + + rule.OnCheck(type); + } + } + } + } + } + + +} diff --git a/Editor/Core/InitializeOnLoad/CompileGuard.cs.meta b/Editor/Core/InitializeOnLoad/CompileGuard.cs.meta new file mode 100644 index 00000000..169716b0 --- /dev/null +++ b/Editor/Core/InitializeOnLoad/CompileGuard.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7177b9c29b1bfdf4998168fa58642b35 \ No newline at end of file diff --git a/Editor/Core/InitializeOnLoad/Rules.meta b/Editor/Core/InitializeOnLoad/Rules.meta new file mode 100644 index 00000000..553a751e --- /dev/null +++ b/Editor/Core/InitializeOnLoad/Rules.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 24f3441ca9697e34f926a8ca3105ac53 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Core/InitializeOnLoad/Rules/ConfigAssetsRule.cs b/Editor/Core/InitializeOnLoad/Rules/ConfigAssetsRule.cs new file mode 100644 index 00000000..0b0fc2c5 --- /dev/null +++ b/Editor/Core/InitializeOnLoad/Rules/ConfigAssetsRule.cs @@ -0,0 +1,95 @@ +using System; +using System.Linq; +using System.Reflection; +using UnityEngine; + +namespace RealMethod.Editor +{ + + public class ConfigAssetsRule : CompileRule + { + // CompileRule Methods + protected override void Initilized() + { + } + public override void OnStartCheck(RuleExecutionMode mode) + { + } + public override bool CanCheck(RuleExecutionMode mode, Type type) + { + if (mode == RuleExecutionMode.EditorStartup) + { + return type.IsSubclassOf(typeof(ConfigAsset)); + } + else + { + return false; + } + } + public override void OnCheck(Type type) + { + // 🔹 Check fields + var badFields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly) + .Where(f => !f.IsInitOnly && !f.IsLiteral && !f.IsDefined(typeof(SerializeField), false)) + .ToList(); + + foreach (var f in badFields) + { + Debug.LogError($"❌ '{type.Name}' has non-readonly field '{f.Name}' — only readonly fields allowed in Config-derived classes."); + } + + // 🔹 Check methods + var badMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) + .Where(m => !m.IsSpecialName && !m.IsConstructor) + .Where(m => ViolatesPureMethodRules(m)) + .ToList(); + + foreach (var m in badMethods) + { + Debug.LogError($"❌ '{type.Name}' public method '{m.Name}' modifies state — only pure getter/return methods are allowed in Config-derived classes."); + } + } + + + // Functions + private bool ViolatesPureMethodRules(MethodInfo method) + { + try + { + var body = method.GetMethodBody(); + if (body == null) + return false; + + var il = body.GetILAsByteArray(); + if (il == null) + return false; + + // Look for IL opcodes that store data or call setters + for (int i = 0; i < il.Length - 1; i++) + { + byte b = il[i]; + byte next = il[i + 1]; + + // Store field (stfld or stsfld) + if (b == 0x7D || b == 0x80) + return true; + + // Callvirt / call that might be setter + if (b == 0x28) + { + var tokens = method.Module.ResolveMethod(BitConverter.ToInt32(il, i + 1)); + if (tokens.Name.StartsWith("set_", StringComparison.Ordinal)) + return true; + } + } + } + catch + { + // Ignore methods that can't be inspected + } + + return false; + } + + } +} \ No newline at end of file diff --git a/Editor/Core/Definitions/ConfigAssetValidator.cs.meta b/Editor/Core/InitializeOnLoad/Rules/ConfigAssetsRule.cs.meta similarity index 100% rename from Editor/Core/Definitions/ConfigAssetValidator.cs.meta rename to Editor/Core/InitializeOnLoad/Rules/ConfigAssetsRule.cs.meta diff --git a/Editor/Core/InitializeOnLoad/Rules/GameModuleRule.cs b/Editor/Core/InitializeOnLoad/Rules/GameModuleRule.cs new file mode 100644 index 00000000..49953099 --- /dev/null +++ b/Editor/Core/InitializeOnLoad/Rules/GameModuleRule.cs @@ -0,0 +1,54 @@ +using System; +using System.Reflection; +using UnityEngine; + +namespace RealMethod.Editor +{ + public class ServiceRule : CompileRule + { + // CompileRule Methods + protected override void Initilized() + { + + } + public override void OnStartCheck(RuleExecutionMode mode) + { + } + public override bool CanCheck(RuleExecutionMode mode, Type type) + { + if (mode == RuleExecutionMode.AfterCompilation) + { + return type.IsSubclassOf(typeof(GameModule)); + } + else + { + return false; + } + } + public override void OnCheck(Type type) + { + // Check if class is static + if (type.IsAbstract && type.IsSealed) + { + Debug.LogError($"{typeof(GameModule).Name} class '{type.FullName}' cannot be static."); + return; + } + + // Check for static methods + var methods = type.GetMethods( + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Static | + BindingFlags.DeclaredOnly + ); + + foreach (var method in methods) + { + if (method.IsStatic) + { + Debug.LogError($"Module '{type.FullName}' contains static method '{method.Name}'. Static methods are not allowed in module classes."); + } + } + } + } +} \ No newline at end of file diff --git a/Editor/Core/InitializeOnLoad/Rules/GameModuleRule.cs.meta b/Editor/Core/InitializeOnLoad/Rules/GameModuleRule.cs.meta new file mode 100644 index 00000000..db007c21 --- /dev/null +++ b/Editor/Core/InitializeOnLoad/Rules/GameModuleRule.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d5ced9cc83a3eaa4bbf313a3a3c0d44c \ No newline at end of file diff --git a/Editor/Core/InitializeOnLoad/Rules/PrimitveAssetsRule.cs b/Editor/Core/InitializeOnLoad/Rules/PrimitveAssetsRule.cs new file mode 100644 index 00000000..8bdace9d --- /dev/null +++ b/Editor/Core/InitializeOnLoad/Rules/PrimitveAssetsRule.cs @@ -0,0 +1,55 @@ +using System; +using UnityEngine; +using UnityEditor; + +namespace RealMethod.Editor +{ + public class PrimitveAssetsRule : CompileRule + { + private PrimitiveAsset[] assets = null; + + protected override void Initilized() + { + assets = Resources.FindObjectsOfTypeAll(); + } + public override void OnStartCheck(RuleExecutionMode mode) + { + if ((int)mode < 2) + return; + + PlayModeStateChange CurrentMode = (PlayModeStateChange)((int)mode - 2); + foreach (var asset in assets) + { + if (mode == RuleExecutionMode.EnteredPlayMode) + { + if (asset is not DataAsset) + asset.SendMessage(FunctionNames.AssetPermission, SendMessageOptions.RequireReceiver); + + // if (AssetDatabase.Contains(asset)) + // { + // if (asset is FileAsset) + // { + // Debug.LogWarning($"InstanceAsset '{asset.name}' is used directly in Play Mode. " + + // $"A runtime instanceAsset should be used instead.Create() at runtime", + // asset); + // } + // } + } + + if (asset.AutoReset(CurrentMode)) + { + asset.SendMessage(FunctionNames.Reset, SendMessageOptions.RequireReceiver); + } + } + } + public override bool CanCheck(RuleExecutionMode mode, Type type) + { + return false; + } + public override void OnCheck(Type type) + { + + } + + } +} \ No newline at end of file diff --git a/Editor/Core/InitializeOnLoad/Rules/PrimitveAssetsRule.cs.meta b/Editor/Core/InitializeOnLoad/Rules/PrimitveAssetsRule.cs.meta new file mode 100644 index 00000000..c7a5b4ed --- /dev/null +++ b/Editor/Core/InitializeOnLoad/Rules/PrimitveAssetsRule.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 83de4f43792a7cd4bb82451acfff8360 \ No newline at end of file diff --git a/Editor/Core/InitializeOnLoad/Rules/PureRule.cs b/Editor/Core/InitializeOnLoad/Rules/PureRule.cs new file mode 100644 index 00000000..57bda237 --- /dev/null +++ b/Editor/Core/InitializeOnLoad/Rules/PureRule.cs @@ -0,0 +1,145 @@ +using System; +using System.Reflection; +using UnityEngine; + +namespace RealMethod.Editor +{ + public class PureRule : CompileRule + { + // CompileRule MEthods + protected override void Initilized() + { + throw new NotImplementedException(); + } + public override void OnStartCheck(RuleExecutionMode mode) + { + } + public override bool CanCheck(RuleExecutionMode mode, Type type) + { + if (mode == RuleExecutionMode.AfterCompilation) + { + return true; + } + else + { + return false; + } + } + public override void OnCheck(Type type) + { + foreach (var method in type.GetMethods( + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.Static | + BindingFlags.DeclaredOnly)) + { + // Ignore methods without PureAttribute + if (!method.IsDefined(typeof(PureAttribute), false)) + continue; + + // Check the calls inside the method + if (!IsMethodPure(method)) + { + Debug.LogError( + $"PURE METHOD VIOLATION in {type.FullName}.{method.Name}():\n" + + $"→ This method is marked [Pure] but calls an impure method!" + ); + } + } + } + + + private bool IsMethodPure(MethodInfo method) + { + var body = method.GetMethodBody(); + if (body == null) + return true; + + var il = body.GetILAsByteArray(); + int pos = 0; + + while (pos < il.Length) + { + byte op = il[pos]; + + // CALL or CALLVIRT opcodes + if (op == 0x28 || op == 0x6F) + { + int metadataToken = BitConverter.ToInt32(il, pos + 1); + var called = method.Module.ResolveMethod(metadataToken) as MethodInfo; + + if (called != null) + { + // If called method is not marked [Pure] → error + if (!called.IsDefined(typeof(PureAttribute), false)) + return false; + } + } + + pos++; + } + + return true; + } + private bool IsPure(MethodInfo method) + { + // 1. Explicitly marked as pure + if (method.GetCustomAttribute() != null) + return true; + + // 2. Implicit analysis + return IsMethodImplicitlyPure(method); + } + private bool IsMethodImplicitlyPure(MethodInfo method) + { + // Any setter = NOT pure + if (method.IsSpecialName && method.Name.StartsWith("set_")) + return false; + + // Inspect instructions (Cecil would be ideal, but unavailable at runtime) + // Simple heuristic: if method writes to fields, it's impure + var body = method.GetMethodBody(); + if (body == null) + return true; // e.g., extern methods are assumed pure + + var il = body.GetILAsByteArray(); + + // Look for IL opcodes that indicate mutation + // stfld = write to field + // stsfld = write to static field + // call/set = property setter + // callvirt = method call (we check purity recursively) + + for (int i = 0; i < il.Length; i++) + { + byte code = il[i]; + + // stfld or stsfld (field writes) + if (code == 0x7D || code == 0x80) + return false; + + // call / callvirt: check called method purity + if (code == 0x28 || code == 0x6F) + { + // Read metadata token + int token = BitConverter.ToInt32(il, i + 1); + var calledMethod = method.Module.ResolveMethod(token) as MethodInfo; + + if (calledMethod == null) + continue; + + // If called method is not pure => this method is impure + if (!IsPure(calledMethod)) + return false; + } + } + + return true; + } + + + + + } +} \ No newline at end of file diff --git a/Editor/Core/InitializeOnLoad/Rules/PureRule.cs.meta b/Editor/Core/InitializeOnLoad/Rules/PureRule.cs.meta new file mode 100644 index 00000000..108444b9 --- /dev/null +++ b/Editor/Core/InitializeOnLoad/Rules/PureRule.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 14a6add6319d3c04e824d67efc811507 \ No newline at end of file diff --git a/Editor/Core/Inspectors.meta b/Editor/Core/Inspectors.meta new file mode 100644 index 00000000..cea3ae1e --- /dev/null +++ b/Editor/Core/Inspectors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b4a83e7828d63e4e893cb8244c6a31f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Core/Inspectors/ButtonEditor.cs b/Editor/Core/Inspectors/ButtonEditor.cs new file mode 100644 index 00000000..a3c8599d --- /dev/null +++ b/Editor/Core/Inspectors/ButtonEditor.cs @@ -0,0 +1,30 @@ +using UnityEditor; +using UnityEngine; +using System.Linq; +using System.Reflection; + + +namespace RealMethod.Editor +{ + [CustomEditor(typeof(MonoBehaviour), true)] + public class ButtonDrawer : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + var targetType = target.GetType(); + var methods = targetType + .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .Where(m => m.GetCustomAttribute() != null && m.GetParameters().Length == 0); + + foreach (var method in methods) + { + if (GUILayout.Button(method.Name)) + { + method.Invoke(target, null); + } + } + } + } +} \ No newline at end of file diff --git a/Editor/Core/Inspectors/ButtonEditor.cs.meta b/Editor/Core/Inspectors/ButtonEditor.cs.meta new file mode 100644 index 00000000..25039171 --- /dev/null +++ b/Editor/Core/Inspectors/ButtonEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b9640b8b2e43dc0419208f4283f8aa82 \ No newline at end of file diff --git a/Editor/Core/Inspectors/GameEditor.cs b/Editor/Core/Inspectors/GameEditor.cs new file mode 100644 index 00000000..d34379a5 --- /dev/null +++ b/Editor/Core/Inspectors/GameEditor.cs @@ -0,0 +1,57 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomEditor(typeof(Game), true)] + public class GameEditor : UnityEditor.Editor + { + private Game Comp; + private string WorldName => Game.World != null ? Game.World.GetType().Name : "World Not Valid"; + private string BridgeName => Game.Bridge != null ? Game.Bridge.GetType().Name : "GameBridge Not Valid"; + private string ConfigName => Game.Config != null ? Game.Config.GetType().Name : "GameConfig Not Valid"; + private IInspectorInfo[] InfoList; + private bool[] FoldoutList; + + private void OnEnable() + { + Comp = (Game)target; + InfoList = Comp.GetAllInfo(); + FoldoutList = new bool[InfoList.Length]; + } + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.Space(); + if (Comp != null) + { + EditorGUILayout.LabelField($"{WorldName} | {BridgeName} | {ConfigName}"); + EditorGUILayout.LabelField($"GameStat: {Game.State}"); + EditorGUILayout.LabelField($"----------------------------------------({InfoList.Length})----------------------------------------"); + if (InfoList != null) + { + for (int i = 0; i < InfoList.Length; i++) + { + IInspectorInfo info = InfoList[i]; + if (info == null) + continue; + + FoldoutList[i] = EditorGUILayout.Foldout(FoldoutList[i], $"{i + 1}. {info.GetTitleInfo()}", true, EditorStyles.foldoutHeader); + if (FoldoutList[i]) + { + GUIStyle style = new GUIStyle(EditorStyles.label); + style.wordWrap = true; + EditorGUILayout.LabelField(info.GetInfo(), style); + } + } + } + + } + } + + + } + + + +} \ No newline at end of file diff --git a/Editor/Core/Architecture/GameCompWindow.cs.meta b/Editor/Core/Inspectors/GameEditor.cs.meta similarity index 100% rename from Editor/Core/Architecture/GameCompWindow.cs.meta rename to Editor/Core/Inspectors/GameEditor.cs.meta diff --git a/Editor/Core/Inspectors/MonoBehaviourEditor.cs b/Editor/Core/Inspectors/MonoBehaviourEditor.cs new file mode 100644 index 00000000..228d054d --- /dev/null +++ b/Editor/Core/Inspectors/MonoBehaviourEditor.cs @@ -0,0 +1,15 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + /// + /// Required for the fetching of a default editor on MonoBehaviour objects. + /// + [CanEditMultipleObjects] + [CustomEditor(typeof(MonoBehaviour), true)] + public class MonoBehaviourEditor : UnityEditor.Editor + { + + } +} \ No newline at end of file diff --git a/Editor/Core/Inspectors/MonoBehaviourEditor.cs.meta b/Editor/Core/Inspectors/MonoBehaviourEditor.cs.meta new file mode 100644 index 00000000..36acbb49 --- /dev/null +++ b/Editor/Core/Inspectors/MonoBehaviourEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5d107c809858e504f9c8f63b13101d7c \ No newline at end of file diff --git a/Editor/Core/Inspectors/PrimitiveAssetEditor.cs b/Editor/Core/Inspectors/PrimitiveAssetEditor.cs new file mode 100644 index 00000000..fe8ec347 --- /dev/null +++ b/Editor/Core/Inspectors/PrimitiveAssetEditor.cs @@ -0,0 +1,11 @@ +using UnityEditor; + +namespace RealMethod.Editor +{ + /// + /// Required for the fetching of a default editor on ScriptableObject objects. + /// + [CanEditMultipleObjects] + [CustomEditor(typeof(PrimitiveAsset), true)] + public class PrimitiveAssetEditor : UnityEditor.Editor { } +} \ No newline at end of file diff --git a/Editor/Core/Inspectors/PrimitiveAssetEditor.cs.meta b/Editor/Core/Inspectors/PrimitiveAssetEditor.cs.meta new file mode 100644 index 00000000..78ce2527 --- /dev/null +++ b/Editor/Core/Inspectors/PrimitiveAssetEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9da63613ae73be84aac196a150fc3fa2 \ No newline at end of file diff --git a/Editor/Core/Definitions/DataAssetEditor.cs b/Editor/Core/Inspectors/ScriptableObjectEditor.cs similarity index 92% rename from Editor/Core/Definitions/DataAssetEditor.cs rename to Editor/Core/Inspectors/ScriptableObjectEditor.cs index 2ee63d0b..c28f3177 100644 --- a/Editor/Core/Definitions/DataAssetEditor.cs +++ b/Editor/Core/Inspectors/ScriptableObjectEditor.cs @@ -1,10 +1,9 @@ -#if UNITY_EDITOR using UnityEditor; using UnityEngine; namespace RealMethod.Editor { - public class DataAssetEditor : UnityEditor.Editor + public class ScriptableObjectEditor : UnityEditor.Editor { public static void DrawCompleteScriptableObjectEditor(string name, ref T settings, ref bool foldout, ref UnityEditor.Editor editor) where T : ScriptableObject { @@ -23,5 +22,4 @@ public static void DrawSubEditor (Object settings, ref bool foldout, ref UnityEd } } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/Editor/Core/Definitions/DataAssetEditor.cs.meta b/Editor/Core/Inspectors/ScriptableObjectEditor.cs.meta similarity index 100% rename from Editor/Core/Definitions/DataAssetEditor.cs.meta rename to Editor/Core/Inspectors/ScriptableObjectEditor.cs.meta diff --git a/Editor/Core/MenuItem.meta b/Editor/Core/MenuItem.meta new file mode 100644 index 00000000..0bb4c4dc --- /dev/null +++ b/Editor/Core/MenuItem.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ffc42bc08d097ab468267973c58637fd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Core/MenuItem/CoreMenu.cs b/Editor/Core/MenuItem/CoreMenu.cs new file mode 100644 index 00000000..3019d2c7 --- /dev/null +++ b/Editor/Core/MenuItem/CoreMenu.cs @@ -0,0 +1,115 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + class CoreMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Core; + + + ///////////// GameObject \\\\\\\\\\\\ + [MenuItem(RM_Editor.GameObjectMenuItemPath + "PlayerStarter", false, 1)] + static void CreatePlayerStarter(MenuCommand menuCommand) + { + // Create a new GameObject + GameObject go = new GameObject("PlayerStarter"); + + // Optional: add components + go.AddComponent(); + + // Place it in the scene, parented if needed + GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject); + + // Register the creation in Undo system (so Ctrl+Z works) + Undo.RegisterCreatedObjectUndo(go, "Create " + go.name); + + // Select the new GameObject + Selection.activeObject = go; + } + [MenuItem(RM_Editor.GameObjectMenuItemPath + "World", false, 1)] + static void CreateWorld(MenuCommand menuCommand) + { + // Create a new GameObject + GameObject go = new GameObject("World"); + + // Optional: add components + go.AddComponent(); + + // Place it in the scene, parented if needed + GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject); + + // Register the creation in Undo system (so Ctrl+Z works) + Undo.RegisterCreatedObjectUndo(go, "Create " + go.name); + + // Select the new GameObject + Selection.activeObject = go; + } + + + ////////////// Scripts \\\\\\\\\\\\ + // Essentials + [MenuItem(RM_Editor.ScriptMenuItemPath + "Essential/Game", false, RM_Editor.MenuOrder.Essential_Head)] + public static void CreateGameClass() + { + RM_Editor.CreateScriptTemplate("Game", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Essential/World", false, RM_Editor.MenuOrder.Essential_Body)] + public static void CreateWorld() + { + RM_Editor.CreateScriptTemplate("World", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Essential/GameBridge", false, RM_Editor.MenuOrder.Essential_Body)] + public static void CreateGameBridgeClass() + { + RM_Editor.CreateScriptTemplate("GameBridge", MenuLayer); + } + // Managers + [MenuItem(RM_Editor.ScriptMenuItemPath + "Manager/EmptyManager", false, RM_Editor.MenuOrder.Manager_Head)] + public static void CreateManager() + { + RM_Editor.CreateScriptTemplate("Manager", MenuLayer); + } + // Services + [MenuItem(RM_Editor.ScriptMenuItemPath + "Service/EmptyService", false, RM_Editor.MenuOrder.Service_Head)] + public static void CreateService() + { + RM_Editor.CreateScriptTemplate("Service", MenuLayer); + } + // Assets + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Data/EmptyDataAsset", false, RM_Editor.MenuOrder.DataAsset_Head)] + public static void CreateDataAsset() + { + RM_Editor.CreateScriptTemplate("DataAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Clone/EmptyCloneAsset", false, RM_Editor.MenuOrder.CloneAsset_Head)] + public static void CreateCloneAsset() + { + RM_Editor.CreateScriptTemplate("CloneAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Unique/EmptyUniqueAsset", false, RM_Editor.MenuOrder.UniqueAsset_Head)] + public static void CreateUniqueAsset() + { + RM_Editor.CreateScriptTemplate("UniqueAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Config/EmptyConfigAsset", false, RM_Editor.MenuOrder.ConfigAsset_Head)] + public static void CreateConfigAsset() + { + RM_Editor.CreateScriptTemplate("ConfigAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Config/Game", false, RM_Editor.MenuOrder.ConfigAsset_Body)] + public static void CreateGameConfig() + { + RM_Editor.CreateScriptTemplate("GameConfig", MenuLayer); + } + // Editor + [MenuItem(RM_Editor.ScriptMenuItemPath + "Editor/CompileRule", false, RM_Editor.MenuOrder.Editor)] + public static void CreateCompileRule() + { + RM_Editor.CreateScriptTemplate("CompileRule", MenuLayer); + } + + + + } +} \ No newline at end of file diff --git a/Editor/Core/MenuItem/CoreMenu.cs.meta b/Editor/Core/MenuItem/CoreMenu.cs.meta new file mode 100644 index 00000000..1c9ed7a0 --- /dev/null +++ b/Editor/Core/MenuItem/CoreMenu.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ca9b255b431903b41a6cad7b4423abe6 \ No newline at end of file diff --git a/Editor/Core/Architecture/AutoWorldExecutionOrder.cs b/Editor/Core/MenuItem/FixupExecutionMenu.cs similarity index 91% rename from Editor/Core/Architecture/AutoWorldExecutionOrder.cs rename to Editor/Core/MenuItem/FixupExecutionMenu.cs index ab0e17c4..bc530f1b 100644 --- a/Editor/Core/Architecture/AutoWorldExecutionOrder.cs +++ b/Editor/Core/MenuItem/FixupExecutionMenu.cs @@ -6,10 +6,9 @@ namespace RealMethod.Editor { - //[InitializeOnLoad] - public static class AutoWorldExecutionOrder + public static class FixupExecutionMenu { - [MenuItem("Tools/RealMethod/Core/ExecutionOrder" , priority = -1001)] + [MenuItem("Tools/RealMethod/Core/FixupExecutionOrder" , priority = -1001)] static void ApplyExecutionOrder() { SetExecutionOrderForDerivedTypes(typeof(World), -18); // ← change base class and order here diff --git a/Editor/Core/Architecture/AutoWorldExecutionOrder.cs.meta b/Editor/Core/MenuItem/FixupExecutionMenu.cs.meta similarity index 100% rename from Editor/Core/Architecture/AutoWorldExecutionOrder.cs.meta rename to Editor/Core/MenuItem/FixupExecutionMenu.cs.meta diff --git a/Editor/Core/ProjectSetting.meta b/Editor/Core/ProjectSetting.meta index 9368b91a..3e26e471 100644 --- a/Editor/Core/ProjectSetting.meta +++ b/Editor/Core/ProjectSetting.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9b58be0a7cb56d449a05466c8d147894 +guid: 46009ab07d5815948a8a9bfd68b24f8b folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Editor/Core/ProjectSetting/ProjectSettingProvider.cs b/Editor/Core/ProjectSetting/ProjectSettingProvider.cs new file mode 100644 index 00000000..373c6d97 --- /dev/null +++ b/Editor/Core/ProjectSetting/ProjectSettingProvider.cs @@ -0,0 +1,356 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + // Interface for call base method in ProjectSettingSection by RealMethodSetting + interface ISectionSetting + { + void FirstSelected(ProjectSettingAsset storage); + void Draw(); + bool IsRuntime(); + } + // Abstract base class for a settings section + public abstract class ProjectSettingSection : ISectionSetting + { + protected enum SectionType + { + Runtime, + Editor, + } + protected class TypeSelector + { + private SerializedProperty myProperty; + private string fieldName; + private List typeList; + private string[] displayNames; + private string[] assemblyNames; + private int selectedIndex = 0; + private int newIndex; + + + public TypeSelector(SerializedProperty TargetStringProperty, string displayName) + { + if (TargetStringProperty != null && displayName != string.Empty) + { + myProperty = TargetStringProperty; + fieldName = displayName; + } + else + { + Debug.LogWarning("TypeSelector Can't Create"); + return; + } + + + typeList = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(a => a.GetTypes()) + .Where(t => typeof(T).IsAssignableFrom(t) && !t.IsAbstract) + .ToList(); + + displayNames = typeList.Select(t => $"{t.Namespace}.{t.Name}").ToArray(); // shown in UI + assemblyNames = typeList.Select(t => t.AssemblyQualifiedName).ToArray(); // stored + } + + public void Draw() + { + selectedIndex = Array.IndexOf(assemblyNames, myProperty.stringValue); + + newIndex = EditorGUILayout.Popup(fieldName, selectedIndex, displayNames); + + if (newIndex >= 0 && newIndex < assemblyNames.Length) + { + myProperty.stringValue = assemblyNames[newIndex]; + } + } + } + protected class ArrayTypeSelector + { + protected SerializedProperty myProperty; + private string fieldName; + private List typeList; + private string[] displayNames; + private string[] assemblyNames; + private int selectedIndex = 0; + private int newIndex; + private readonly int EnforceDisable = -1; + + + public ArrayTypeSelector(SerializedProperty TargetStringProperty, string displayName) + { + if (TargetStringProperty != null && displayName != string.Empty) + { + myProperty = TargetStringProperty; + fieldName = displayName; + } + else + { + Debug.LogWarning("TypeSelector Can't Create"); + return; + } + + typeList = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(a => a.GetTypes()) + .Where(t => typeof(T).IsAssignableFrom(t) && !t.IsAbstract) + .ToList(); + + displayNames = typeList.Select(t => $"{t.Namespace}.{t.Name}").ToArray(); // shown in UI + assemblyNames = typeList.Select(t => t.AssemblyQualifiedName).ToArray(); // stored + + EnforceDisable = GetEnforceDisableIndex(); + } + public void Draw() + { + if (!myProperty.isArray) + return; + + if(myProperty.arraySize < EnforceDisable) + { + myProperty.ClearArray(); + } + + if(myProperty.arraySize == 0) + { + DefaultInitiation(); + } + + for (int i = 0; i < myProperty.arraySize; i++) + { + EditorGUILayout.BeginHorizontal(); + + SerializedProperty element = myProperty.GetArrayElementAtIndex(i); + selectedIndex = Array.IndexOf(assemblyNames, element.stringValue); + + if (i < EnforceDisable) + GUI.enabled = false; + + newIndex = EditorGUILayout.Popup(fieldName, selectedIndex, displayNames); + if (newIndex >= 0 && newIndex < assemblyNames.Length) + { + element.stringValue = assemblyNames[newIndex]; + } + + GUI.enabled = true; + + // Prevent removing first two elements + if (i >= EnforceDisable) + { + if (GUILayout.Button("Remove", GUILayout.Width(70))) + { + myProperty.DeleteArrayElementAtIndex(i); + } + } + else + { + GUI.enabled = false; + GUILayout.Button("Locked", GUILayout.Width(70)); + GUI.enabled = true; + } + + EditorGUILayout.EndHorizontal(); + + } + + GUILayout.Space(10); + + if (GUILayout.Button("Add New")) + { + myProperty.InsertArrayElementAtIndex(myProperty.arraySize); + } + + } + + + protected virtual int GetEnforceDisableIndex() + { + return -1; + } + protected virtual void DefaultInitiation() + { + + } + } + + private bool isReady = true;// Indicates whether the section is ready to render + private string message = string.Empty;// Error message to display if the section is not ready + private int errorid = 0;// Error ID to identify the type of error + + public ProjectSettingSection() + { + Initialized(); + } + + // Implement ISectionSetting Interface + void ISectionSetting.FirstSelected(ProjectSettingAsset storage) + { + BeginRender(storage); + } + void ISectionSetting.Draw() + { + EditorGUILayout.Space(); + EditorGUILayout.LabelField($"{GetTitle()} ({GetSectionType()})", EditorStyles.boldLabel); // Section Title + + if (isReady) + { + // Render the section's content + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + UpdateRender(); + EditorGUILayout.EndVertical(); + } + else + { + // Display an error message if the section is not ready + EditorGUILayout.HelpBox(message, MessageType.Error); + + // Provide a "Fix" button to resolve the error + if (GUILayout.Button("Fix")) + { + Fix(errorid); + } + } + } + bool ISectionSetting.IsRuntime() + { + return GetSectionType() == SectionType.Runtime; + } + + // Abstract Method + protected abstract void Initialized(); + protected abstract void BeginRender(ProjectSettingAsset Storage); + protected abstract void UpdateRender(); + protected abstract string GetTitle(); + protected abstract SectionType GetSectionType(); + protected abstract void Fix(int Id); + + // Protected Function + protected void Error(string Message, int Id = 0) + { + if (isReady) + { + isReady = false; + } + message = Message; + errorid = Id; + } + protected void ClearError() + { + message = string.Empty; + errorid = 0; + if (!isReady) + { + isReady = true; + } + UpdateRender(); + } + + } + + + + // Project Setting + public static class ProjectSettingProvider + { + private static bool candraw = true;// Flag to determine if the UI can be drawn + private static ProjectSettingSection[] sections = new ProjectSettingSection[4] { + // Array of sections to be rendered in the settings UI + new InitializerSettingSection(), + new FolderStructureSection(), + new GameStatusSection(), + new CompileRuleSection(), + }; + + + [SettingsProvider] + // Create a SettingsProvider for Unity's Project Settings + public static SettingsProvider CreateSettingsProvider() + { + var provider = new SettingsProvider("Project/RealMethod", SettingsScope.Project) + { + label = "RealMethod", + + // Called when the settings tab is first selected + activateHandler = (searchContext, rootElement) => + { + ProjectSettingAsset TargetStorage = null; + + // Attempt to load the settings asset + if (!RM_Editor.TryGetSettingAsset(out TargetStorage)) + { + if (Directory.Exists(Path.GetDirectoryName(RM_Editor.SetttingAssetPath))) + { + TargetStorage = CreateSettingStorage(); + } + else + { + candraw = false; + } + } + + // Initialize each section with the loaded settings + foreach (var item in sections) + { + ISectionSetting ptovider = item; + if (TargetStorage != null) + ptovider.FirstSelected(TargetStorage); + } + }, + + + // Called to draw the UI elements + guiHandler = (searchContext) => + { + if (candraw) + { + // Render each section + foreach (var item in sections) + { + ISectionSetting ptovider = item; + ptovider.Draw(); + // Add a separator line + GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); + } + } + else + { + EditorGUILayout.HelpBox($"The Address is not valid {Path.GetDirectoryName(RM_Editor.SetttingAssetPath)}", MessageType.Error); + if (GUILayout.Button("Fix")) + { + if (!Directory.Exists("Assets/Resources")) + AssetDatabase.CreateFolder("Assets", "Resources"); + + if (!Directory.Exists("Assets/Resources/RealMethod")) + AssetDatabase.CreateFolder("Assets/Resources", "RealMethod"); + + + ProjectSettingAsset TargetStorage = CreateSettingStorage(); + foreach (var item in sections) + { + ISectionSetting ptovider = item; + if (TargetStorage != null) + ptovider.FirstSelected(TargetStorage); + } + + candraw = true; + } + } + } + }; + + return provider; + } + + + private static ProjectSettingAsset CreateSettingStorage() + { + // Create a new settings asset at the specified path + ProjectSettingAsset settings = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(settings, RM_Editor.SetttingAssetPath); + AssetDatabase.SaveAssets(); + return settings; + } + } +} \ No newline at end of file diff --git a/Editor/Core/ProjectSetting/ProjectSettingWindow.cs.meta b/Editor/Core/ProjectSetting/ProjectSettingProvider.cs.meta similarity index 100% rename from Editor/Core/ProjectSetting/ProjectSettingWindow.cs.meta rename to Editor/Core/ProjectSetting/ProjectSettingProvider.cs.meta diff --git a/Editor/Core/ProjectSetting/ProjectSettingWindow.cs b/Editor/Core/ProjectSetting/ProjectSettingWindow.cs deleted file mode 100644 index 6f1ebfef..00000000 --- a/Editor/Core/ProjectSetting/ProjectSettingWindow.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor; -using UnityEngine; - -namespace RealMethod.Editor -{ - public static class ProjectSettingWindow - { - private const string settingsPath = "Assets/Resources/RealMethod/RealMethodSetting.asset"; - private static bool candraw = true;// Flag to determine if the UI can be drawn - private static ProjectSettingSection[] sections = new ProjectSettingSection[2] { - // Array of sections to be rendered in the settings UI - new InitializerSection(), - new FolderSettingSection() - }; - - - [SettingsProvider]// Create a SettingsProvider for Unity's Project Settings - public static SettingsProvider CreateSettingsProvider() - { - var provider = new SettingsProvider("Project/Real Method", SettingsScope.Project) - { - label = "Real Method", - - // Called when the settings tab is first selected - activateHandler = (searchContext, rootElement) => - { - ProjectSettingAsset TargetStorage = null; - - // Attempt to load the settings asset - if (!GetSettingStorage(out TargetStorage)) - { - if (Directory.Exists(Path.GetDirectoryName(settingsPath))) - { - TargetStorage = CreateSettingStorage(); - } - else - { - candraw = false; - } - } - - // Initialize each section with the loaded settings - foreach (var item in sections) - { - if (TargetStorage != null) - item.BeginRender(TargetStorage); - } - }, - - // Called to draw the UI elements - guiHandler = (searchContext) => - { - if (candraw) - { - // Render each section - foreach (var item in sections) - { - item.UpdateRender(); - // Add a separator line - GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); - } - } - else - { - EditorGUILayout.HelpBox($"The Address is not valid {Path.GetDirectoryName(settingsPath)}", MessageType.Error); - if (GUILayout.Button("Fix")) - { - if (!Directory.Exists("Assets/Resources")) - AssetDatabase.CreateFolder("Assets", "Resources"); - - if (!Directory.Exists("Assets/Resources/RealMethod")) - AssetDatabase.CreateFolder("Assets/Resources", "RealMethod"); - - - ProjectSettingAsset TargetStorage = CreateSettingStorage(); - foreach (var item in sections) - { - if (TargetStorage != null) - item.BeginRender(TargetStorage); - } - - candraw = true; - } - } - } - }; - - return provider; - } - - - public static bool GetSettingStorage(out ProjectSettingAsset settings) - { - // Attempt to load the settings asset from the specified path - settings = AssetDatabase.LoadAssetAtPath(settingsPath); - return settings != null; - } - private static ProjectSettingAsset CreateSettingStorage() - { - // Create a new settings asset at the specified path - ProjectSettingAsset settings = ScriptableObject.CreateInstance(); - AssetDatabase.CreateAsset(settings, settingsPath); - AssetDatabase.SaveAssets(); - return settings; - } - } - - - // Abstract base class for a settings section - public abstract class ProjectSettingSection - { - protected class ClassType - { - private List TypeList; - private string[] TypeName; - private int selctedIndex = 0; - private int newIndex; - - public ClassType() - { - // Get all available T types **only once** - TypeList = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(assembly => assembly.GetTypes()) - .Where(type => typeof(T).IsAssignableFrom(type) && !type.IsAbstract) - .ToList(); - - TypeName = TypeList.Select(t => t.FullName).ToArray(); - } - - public void Draw(SerializedObject projectSettings, string PropertyName, string DisplayName) - { - selctedIndex = System.Array.IndexOf(TypeName, projectSettings.FindProperty(PropertyName).stringValue); - newIndex = EditorGUILayout.Popup(DisplayName, selctedIndex, TypeName); - if (newIndex >= 0 && newIndex < TypeName.Length) - { - projectSettings.FindProperty(PropertyName).stringValue = TypeName[newIndex]; - } - } - } - private bool isReady = true;// Indicates whether the section is ready to render - private string message = string.Empty;// Error message to display if the section is not ready - private int errorid = 0;// Error ID to identify the type of error - - - public ProjectSettingSection() - { - Initialized(); - } - - public void BeginRender(ProjectSettingAsset storage) - { - FirstSelected(storage); - } - public void UpdateRender() - { - EditorGUILayout.Space(); - EditorGUILayout.LabelField(GetTitle(), EditorStyles.boldLabel); // Section Title - - if (isReady) - { - // Render the section's content - Draw(); - } - else - { - // Display an error message if the section is not ready - EditorGUILayout.HelpBox(message, MessageType.Error); - - // Provide a "Fix" button to resolve the error - if (GUILayout.Button("Fix")) - { - Fix(errorid); - } - } - } - - - protected abstract void Initialized(); - protected abstract void FirstSelected(ProjectSettingAsset Storage); - protected abstract void Draw(); - protected abstract string GetTitle(); - protected abstract void Fix(int Id); - - - protected void Error(string Message, int Id = 0) - { - if (isReady) - { - isReady = false; - } - message = Message; - errorid = Id; - } - protected void ClearError() - { - message = string.Empty; - errorid = 0; - if (!isReady) - { - isReady = true; - } - UpdateRender(); - } - - } -} \ No newline at end of file diff --git a/Editor/Core/ProjectSetting/Sections/CompileRuleSection.cs b/Editor/Core/ProjectSetting/Sections/CompileRuleSection.cs new file mode 100644 index 00000000..99959225 --- /dev/null +++ b/Editor/Core/ProjectSetting/Sections/CompileRuleSection.cs @@ -0,0 +1,85 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + public class CompileRuleSection : ProjectSettingSection + { + private class RuleSelector : ArrayTypeSelector + { + + public RuleSelector(SerializedProperty TargetStringProperty, string displayName) : base(TargetStringProperty, displayName) + { + } + + protected override int GetEnforceDisableIndex() + { + return CompileGuard.DefaultRuls.Length; + } + protected override void DefaultInitiation() + { + foreach (var ruletype in CompileGuard.DefaultRuls) + { + int Index = myProperty.arraySize; + myProperty.InsertArrayElementAtIndex(Index); + SerializedProperty element = myProperty.GetArrayElementAtIndex(Index); + element.stringValue = ruletype.AssemblyQualifiedName; + Debug.LogWarning($"====> {ruletype}"); + } + } + } + + private SerializedProperty CompilingSerialized; + private ProjectSettingAsset SettingAsset; + private SerializedObject projectSettings; + private RuleSelector Rules; + + + // Implement ProjectSettingSection Methods + protected override void Initialized() + { + } + protected override string GetTitle() + { + return "CompileGuard"; + } + protected override SectionType GetSectionType() + { + return SectionType.Editor; + } + protected override void BeginRender(ProjectSettingAsset Storage) + { + SettingAsset = Storage; + projectSettings = new SerializedObject(Storage); + CompilingSerialized = projectSettings.FindProperty("Compiling"); + Rules = new RuleSelector(projectSettings.FindProperty("Rules"), "Rules"); + } + protected override void UpdateRender() + { + if (projectSettings == null) return; + + projectSettings.Update(); + CompilingSerialized.boolValue = EditorGUILayout.Toggle("Enable", CompilingSerialized.boolValue, GUILayout.Width(100)); + + Rules.Draw(); + + if (GUI.changed) + { + projectSettings.ApplyModifiedProperties(); + EditorUtility.SetDirty(SettingAsset); // Mark ScriptableObject dirty + AssetDatabase.SaveAssets(); // Optional: saves to disk immediately + AssetDatabase.Refresh(); + } + + projectSettings.ApplyModifiedProperties(); + + } + + + protected override void Fix(int Id) + { + + } + + } +} \ No newline at end of file diff --git a/Editor/Core/ProjectSetting/Sections/CompileRuleSection.cs.meta b/Editor/Core/ProjectSetting/Sections/CompileRuleSection.cs.meta new file mode 100644 index 00000000..d771a57b --- /dev/null +++ b/Editor/Core/ProjectSetting/Sections/CompileRuleSection.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: de6204fe01936154fbd368730fc129c5 \ No newline at end of file diff --git a/Editor/Core/ProjectSetting/Sections/FolderSettingSection.cs b/Editor/Core/ProjectSetting/Sections/FolderStructureSection.cs similarity index 72% rename from Editor/Core/ProjectSetting/Sections/FolderSettingSection.cs rename to Editor/Core/ProjectSetting/Sections/FolderStructureSection.cs index 5396d8c6..9771a35f 100644 --- a/Editor/Core/ProjectSetting/Sections/FolderSettingSection.cs +++ b/Editor/Core/ProjectSetting/Sections/FolderStructureSection.cs @@ -3,37 +3,40 @@ namespace RealMethod.Editor { - public class FolderSettingSection : ProjectSettingSection + public class FolderStructureSection : ProjectSettingSection { private ProjectSettingAsset MyStorage; private bool isPanelMaximize = false; // Add a toggle for minimizing the panel - // Implement Abstraction Methods + // Implement ProjectSettingSection Methods protected override void Initialized() { } - - protected override void FirstSelected(ProjectSettingAsset Storage) + protected override void BeginRender(ProjectSettingAsset Storage) { MyStorage = Storage; } - - protected override void Draw() + protected override void UpdateRender() { + if (!AssetDatabase.IsValidFolder("Assets/" + Application.productName)) + { + AssetDatabase.CreateFolder("Assets", Application.productName); + } + // Add a toggle button for minimizing or expanding the panel EditorGUILayout.BeginHorizontal(); isPanelMaximize = EditorGUILayout.Foldout(isPanelMaximize, "Folder List", true, EditorStyles.foldoutHeader); if (GUILayout.Button("Create All", GUILayout.Width(80))) { - foreach (var address in MyStorage.ProjectStructure) + foreach (var address in MyStorage.FolderStructure) { - if (AssetDatabase.IsValidFolder(address.Path)) + if (AssetDatabase.IsValidFolder(address.AssetPath)) { Debug.Log($"Folder exists: {address}"); } else { - string folderpath = address.Path; + string folderpath = address.GetFolderPath(MyStorage); string FolderAddress = string.Join("/", folderpath.Split('/')[..^1]); // Remove the last segment of the path string folderName = System.IO.Path.GetFileName(folderpath); // Get the last segment of the path CreateFolder(FolderAddress, folderName); // Create the folder @@ -49,26 +52,26 @@ protected override void Draw() } // Render the folder list - for (int i = 0; i < MyStorage.ProjectStructure.Length; i++) + for (int i = 0; i < MyStorage.FolderStructure.Count; i++) { EditorGUILayout.BeginHorizontal(); // Start horizontal layout // Display the folder path as a text field - MyStorage.ProjectStructure[i].Path = EditorGUILayout.TextField($"{i + 1}.{MyStorage.ProjectStructure[i].Identity}", MyStorage.ProjectStructure[i].Path); + MyStorage.SetFolderAddressPath(i, EditorGUILayout.TextField($"{i + 1}.{MyStorage.FolderStructure[i].AssetType}", MyStorage.FolderStructure[i].AssetPath)); - string ButtonName = AssetDatabase.IsValidFolder(MyStorage.ProjectStructure[i].Path) ? "Check" : "Create"; + string ButtonName = AssetDatabase.IsValidFolder(MyStorage.FolderStructure[i].AssetPath) ? "Check" : "Create"; // Add a button next to the text field if (GUILayout.Button(ButtonName, GUILayout.Width(60))) { // Check if the folder exists - if (AssetDatabase.IsValidFolder(MyStorage.ProjectStructure[i].Path)) + if (AssetDatabase.IsValidFolder(MyStorage.FolderStructure[i].AssetPath)) { - Debug.Log($"Folder exists: {MyStorage.ProjectStructure[i]}"); + Debug.Log($"Folder exists: {MyStorage.FolderStructure[i]}"); } else { - string folderpath = MyStorage.ProjectStructure[i].Path; + string folderpath = MyStorage.FolderStructure[i].GetFolderPath(MyStorage); string FolderAddress = string.Join("/", folderpath.Split('/')[..^1]); // Remove the last segment of the path string folderName = System.IO.Path.GetFileName(folderpath); // Get the last segment of the path CreateFolder(FolderAddress, folderName); // Create the folder @@ -78,16 +81,19 @@ protected override void Draw() EditorGUILayout.EndHorizontal(); // End horizontal layout } } - protected override string GetTitle() { return "FolderStructure"; } - + protected override SectionType GetSectionType() + { + return SectionType.Editor; + } protected override void Fix(int Id) { } + private void CreateFolder(string parentFolder, string newFolderName) { string folderPath = System.IO.Path.Combine(parentFolder, newFolderName).Replace("\\", "/"); diff --git a/Editor/Core/ProjectSetting/Sections/FolderSettingSection.cs.meta b/Editor/Core/ProjectSetting/Sections/FolderStructureSection.cs.meta similarity index 100% rename from Editor/Core/ProjectSetting/Sections/FolderSettingSection.cs.meta rename to Editor/Core/ProjectSetting/Sections/FolderStructureSection.cs.meta diff --git a/Editor/Core/ProjectSetting/Sections/GameStatusSection.cs b/Editor/Core/ProjectSetting/Sections/GameStatusSection.cs new file mode 100644 index 00000000..87b7dd32 --- /dev/null +++ b/Editor/Core/ProjectSetting/Sections/GameStatusSection.cs @@ -0,0 +1,103 @@ + +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + public class GameStatusSection : ProjectSettingSection + { + private ProjectSettingAsset SettingAsset; + private SerializedObject projectSettings; + private List MyList + { + get + { + if (SettingAsset == null) + { + //Error("SettingAsset Can't find"); + return new List(0); + } + return SettingAsset.Status; + } + + set + { + if (SettingAsset != null) + { + SettingAsset.Status = value; + } + else + { + //Error("SettingAsset Can't find"); + } + } + } + + + protected override string GetTitle() + { + return "GameStatus"; + } + protected override SectionType GetSectionType() + { + return SectionType.Editor; + } + protected override void Initialized() + { + + } + protected override void BeginRender(ProjectSettingAsset Storage) + { + SettingAsset = Storage; + projectSettings = new SerializedObject(Storage); + } + protected override void UpdateRender() + { + EditorGUI.BeginChangeCheck(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.Space(5); + int newSize = Mathf.Max(0, EditorGUILayout.IntField("Size", MyList.Count)); + EditorGUILayout.EndHorizontal(); + + while (MyList.Count < newSize) + MyList.Add(""); + + while (MyList.Count > newSize) + MyList.RemoveAt(MyList.Count - 1); + + for (int i = 0; i < MyList.Count; i++) + { + MyList[i] = EditorGUILayout.TextField($"Element {i}", MyList[i]); + } + + if (EditorGUI.EndChangeCheck()) + { + if (projectSettings != null) + { + Undo.RecordObject(SettingAsset, "Modify Game Status Names"); + EditorUtility.SetDirty(SettingAsset); + } + } + + if (GUI.changed) + { + projectSettings.ApplyModifiedProperties(); + EditorUtility.SetDirty(SettingAsset); // Mark ScriptableObject dirty + AssetDatabase.SaveAssets(); // Optional: saves to disk immediately + AssetDatabase.Refresh(); + } + + projectSettings.ApplyModifiedProperties(); + + } + + protected override void Fix(int Id) + { + ClearError(); + } + + + } +} \ No newline at end of file diff --git a/Editor/Core/ProjectSetting/Sections/GameStatusSection.cs.meta b/Editor/Core/ProjectSetting/Sections/GameStatusSection.cs.meta new file mode 100644 index 00000000..0a82f4c1 --- /dev/null +++ b/Editor/Core/ProjectSetting/Sections/GameStatusSection.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a6ecf6e981d7ae74ea5bfab2e27f9523 \ No newline at end of file diff --git a/Editor/Core/ProjectSetting/Sections/InitializerSection.cs b/Editor/Core/ProjectSetting/Sections/InitializerSettingSection.cs similarity index 62% rename from Editor/Core/ProjectSetting/Sections/InitializerSection.cs rename to Editor/Core/ProjectSetting/Sections/InitializerSettingSection.cs index 477e7f76..5bcdfdae 100644 --- a/Editor/Core/ProjectSetting/Sections/InitializerSection.cs +++ b/Editor/Core/ProjectSetting/Sections/InitializerSettingSection.cs @@ -3,42 +3,48 @@ namespace RealMethod.Editor { - public class InitializerSection : ProjectSettingSection + public class InitializerSettingSection : ProjectSettingSection { - private ClassType gameClass; - private ClassType gameService; + private TypeSelector gameClass; + private TypeSelector gameBridge; private SerializedObject projectSettings; private ProjectSettingAsset SettingAsset; + protected override string GetTitle() + { + return "Initializer"; + } + protected override SectionType GetSectionType() + { + return SectionType.Runtime; + } protected override void Initialized() { - gameClass = new ClassType(); - gameService = new ClassType(); + } - protected override void FirstSelected(ProjectSettingAsset Storage) + protected override void BeginRender(ProjectSettingAsset Storage) { SettingAsset = Storage; projectSettings = new SerializedObject(Storage); + gameClass = new TypeSelector(projectSettings.FindProperty("GameClass"), "Game Class"); + gameBridge = new TypeSelector(projectSettings.FindProperty("GameBridge"), "Game Bridge"); } - protected override void Draw() + protected override void UpdateRender() { if (projectSettings == null) return; projectSettings.Update(); // GameInstanceClass - gameClass.Draw(projectSettings, "GameClass", "Game Class"); - - // GameServiceClass - gameService.Draw(projectSettings, "GameService", "Game Service"); - + gameClass.Draw(); + // GameBridgeClass + gameBridge.Draw(); // GameSettingAsset EditorGUILayout.PropertyField(projectSettings.FindProperty("GameConfig"), new GUIContent("Game Config")); - //GameInitialPrefabs - EditorGUILayout.PropertyField(projectSettings.FindProperty("GamePrefab_1"), new GUIContent("Game Prefab (1)")); - EditorGUILayout.PropertyField(projectSettings.FindProperty("GamePrefab_2"), new GUIContent("Game Prefab (2)")); - EditorGUILayout.PropertyField(projectSettings.FindProperty("GamePrefab_3"), new GUIContent("Game Prefab (3)")); + EditorGUILayout.PropertyField(projectSettings.FindProperty("GamePrefab_1"), new GUIContent("GameScope (Runtime)")); + EditorGUILayout.PropertyField(projectSettings.FindProperty("GamePrefab_2"), new GUIContent("GameScope (Editor)")); + EditorGUILayout.PropertyField(projectSettings.FindProperty("GamePrefab_3"), new GUIContent("Dedicated Server")); if (GUI.changed) { @@ -50,17 +56,11 @@ protected override void Draw() projectSettings.ApplyModifiedProperties(); } - protected override string GetTitle() - { - return "Initializer"; - } protected override void Fix(int Id) { throw new System.NotImplementedException(); } - - } } \ No newline at end of file diff --git a/Editor/Core/ProjectSetting/Sections/InitializerSection.cs.meta b/Editor/Core/ProjectSetting/Sections/InitializerSettingSection.cs.meta similarity index 100% rename from Editor/Core/ProjectSetting/Sections/InitializerSection.cs.meta rename to Editor/Core/ProjectSetting/Sections/InitializerSettingSection.cs.meta diff --git a/Editor/Core/ProjectSetting/UnityAsset_Postprocessor.cs b/Editor/Core/ProjectSetting/UnityAsset_Postprocessor.cs deleted file mode 100644 index 95642d87..00000000 --- a/Editor/Core/ProjectSetting/UnityAsset_Postprocessor.cs +++ /dev/null @@ -1,123 +0,0 @@ -using UnityEditor; -using UnityEngine; - -namespace RealMethod.Editor -{ - public class UnityAsset_Postprocessor : AssetPostprocessor - { - static AssetHandeler[] AssetList = new AssetHandeler[5] { - new WorldScene_UnityAsset(), - new Table_UnityAsset(), - new PCGResource_UnityAsset(), - new PCGGeneration_UnityAsset(), - new PCGCash_UnityAsset() }; - - // private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) - // { - // if (AssetList == null) - // { - // return; - // } - - // foreach (var asset in AssetList) - // { - // foreach (string assetPath in importedAssets) - // { - // asset.OnAssetImported(assetPath); - // } - // foreach (string assetPath in deletedAssets) - // { - // asset.OnAssetDeleted(assetPath); - // } - // for (int i = 0; i < movedAssets.Length; i++) - // { - // asset.OnAssetMoved(movedAssets[i], movedFromAssetPaths[i]); - // } - // } - // } - - [InitializeOnLoadMethod] - private static void OnDoubleClickScriptableObject() - { - EditorApplication.projectWindowItemOnGUI += (guid, rect) => - { - Event e = Event.current; - if (e.type == EventType.MouseDown && e.clickCount == 2) - { - string assetPath = AssetDatabase.GUIDToAssetPath(guid); - foreach (var asset in AssetList) - { - asset.OnAssetClick(assetPath, e); - } - } - }; - } - } - - - - public abstract class AssetHandeler - { - public AssetHandeler() - { - Initialized(); - } - - protected abstract void Initialized(); - public abstract void OnAssetImported(string AssetPath); - public abstract void OnAssetDeleted(string AssetPath); - public abstract void OnAssetMoved(string AssetPath, string FromPath); - public abstract void OnAssetClick(string AssetPath, Event e); - protected abstract string GetIconPath(); - } - - public abstract class AssetHandeler : AssetHandeler where T : Object - { - protected abstract void DoubleClick(T asset); - - public override void OnAssetImported(string AssetPath) - { - T loadedAsset; - if (TryLoadAsset(AssetPath, out loadedAsset)) - { - if (loadedAsset.GetType() == typeof(J)) - { - // Load your icon from Resources (adjust the path as needed) - Texture2D icon = Resources.Load(GetIconPath()); - if (icon != null) - { - EditorGUIUtility.SetIconForObject(loadedAsset, icon); - } - else - { - Debug.LogWarning("Custom icon not found. Please ensure the path and file are correct."); - } - } - } - else - { - Debug.LogWarning("Cant Load "); - } - } - public override void OnAssetClick(string AssetPath, Event e) - { - var asset = AssetDatabase.LoadAssetAtPath(AssetPath); - - if (asset != null) - { - DoubleClick(asset); - e.Use(); // Consume the event - } - } - - protected bool TryLoadAsset(string assetPath, out K asset) where K : Object - { - asset = AssetDatabase.LoadAssetAtPath(assetPath); - return asset != null; - } - } - - - - -} \ No newline at end of file diff --git a/Editor/Core/Utilities.meta b/Editor/Core/Utilities.meta new file mode 100644 index 00000000..c92a9ecd --- /dev/null +++ b/Editor/Core/Utilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0bdf41dbd1061b64299b20780a85c8c7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Core/Utilities/Editor_Library.cs b/Editor/Core/Utilities/Editor_Library.cs new file mode 100644 index 00000000..d5802a7f --- /dev/null +++ b/Editor/Core/Utilities/Editor_Library.cs @@ -0,0 +1,197 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + public enum RealMethodLayer + { + Core, + Library, + Pattern, + ReadySet, + Toolkit + } + + public static class RM_Editor + { + public static class MenuOrder + { + private const int starter = 80; + private const int space = 1; + private const int priorityjumps = 11; + + + + public const int Essential_Head = starter; + public const int Essential_Body = Essential_Head; + public const int Manager_Head = Essential_Head + space; + public const int Manager_Body = Manager_Head + priorityjumps; + public const int Service_Head = Manager_Head + space; + public const int Service_Body = Service_Head + priorityjumps; + public const int DataAsset_Head = Service_Head + space; + public const int DataAsset_Body = DataAsset_Head + priorityjumps; + public const int CloneAsset_Head = DataAsset_Head + space; + public const int CloneAsset_Body = CloneAsset_Head + priorityjumps; + public const int UniqueAsset_Head = CloneAsset_Head + space; + public const int UniqueAsset_Body = UniqueAsset_Head + priorityjumps; + public const int ConfigAsset_Head = UniqueAsset_Head + space; + public const int ConfigAsset_Body = ConfigAsset_Head + priorityjumps; + public const int Method = ConfigAsset_Body + space; + public const int Toolkit = Method + space; + public const int Editor = Toolkit + space + priorityjumps; + } + public static string SetttingAssetPath = ProjectSettingAsset.Path; + public static string ScriptTemplatesPath => GetPackagePath("com.mustard.realmethod") + "/Reservoir/ScriptTemplates"; + public static string PrefabTemplatePath => GetPackagePath("com.mustard.realmethod") + "/Reservoir/Prefabs"; + public const string GameObjectMenuItemPath = "GameObject/RealMethod/"; + public const string ScriptMenuItemPath = "Assets/Create/Scripting/RealMethod/"; + public static string Documentation => GetPackagePath("com.mustard.realmethod") + "/Documentation/Information"; + public static bool IsPlayMode + { + get + { + return EditorApplication.isPlaying && EditorApplication.isPlayingOrWillChangePlaymode == false; + } + } + + + + + // Functions + public static bool TryGetSettingAsset(out ProjectSettingAsset settings) + { + // Attempt to load the settings asset from the specified path + settings = AssetDatabase.LoadAssetAtPath(SetttingAssetPath); + return settings != null; + } + private static string GetPackagePath(string packageName) + { + string[] guids = AssetDatabase.FindAssets("package", new[] { "Packages/" + packageName }); + foreach (string guid in guids) + { + string path = AssetDatabase.GUIDToAssetPath(guid); + if (path.Contains(packageName)) + { + string packagePath = Path.GetDirectoryName(path); + while (!string.IsNullOrEmpty(packagePath)) + { + if (File.Exists(Path.Combine(packagePath, "package.json"))) + return packagePath; + + packagePath = Path.GetDirectoryName(packagePath); + } + } + } + + Debug.LogError($"Could not find package path for: {packageName}"); + return null; + } + public static void CreateScriptTemplate(string TemplateName, RealMethodLayer layer) + { + string NewFileName = $"My{TemplateName}.cs"; + string TemplateFileName = $"{layer}\\{TemplateName}Template.txt"; + string NewFilePath = CreateScriptTemplate(TemplateFileName, NewFileName); + } + public static GameObject CreatePrefabTemplate(string prefabName, bool UseProject = false) + { + + string prefabPath = string.Empty; + if (UseProject) + { + ProjectSettingAsset ProjectSetting = AssetDatabase.LoadAssetAtPath(SetttingAssetPath); + prefabPath = Path.Combine(ProjectSetting.GetFolderPathByType(ProjectSettingAsset.AssetFormat.Prefab), prefabName); + } + else + { + prefabPath = Path.Combine(PrefabTemplatePath, prefabName); + } + + // Load the prefab from the specified path + GameObject prefab = AssetDatabase.LoadAssetAtPath(prefabPath); + + if (prefab != null) + { + // Create an instance of the prefab in the scene + GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab); + + // Register the creation in the undo system + Undo.RegisterCreatedObjectUndo(instance, "Create " + instance.name); + + // Select the newly created instance + Selection.activeObject = instance; + return instance; + } + else + { + Debug.LogError("Prefab not found at path: " + prefabPath); + return null; + } + } + public static string GetScenePathByName(string name) + { + foreach (var scene in EditorBuildSettings.scenes) + { + if (scene.path.Contains(name)) + return scene.path; + } + return null; + } + + + + + // Methods + private static string CreateScriptTemplate(string templateFileName, string defaultName) + { + string templatePath = string.Empty; + if (Directory.Exists("Assets/RealDev/_General")) + { + Debug.LogWarning("When This Message show RealMetod using hardcode addres becuase find [Assets/RealDev/_General]"); + templatePath = Path.Combine("Assets\\RealMethod\\Reservoir\\ScriptTemplates\\", templateFileName); + } + else + { + templatePath = Path.Combine(ScriptTemplatesPath, templateFileName); + } + + + if (!File.Exists(templatePath)) + { + Debug.LogError($"Template file not found: {templatePath}"); + return string.Empty; + } + + string selectedPath = RM_Asset.GetSelectedAssetDirectory(); + string newScriptPath = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(selectedPath, defaultName)); + + // Prompt user for script name before creating the file + string inputName = EditorUtility.SaveFilePanel( + "Create Script", + selectedPath, + Path.GetFileNameWithoutExtension(defaultName), + "cs" + ); + + if (string.IsNullOrEmpty(inputName)) + return string.Empty; + + // Ensure the path is relative to the Assets folder + if (inputName.StartsWith(Application.dataPath)) + newScriptPath = "Assets" + inputName.Substring(Application.dataPath.Length); + else + newScriptPath = inputName; + + string template = File.ReadAllText(templatePath); + template = template.Replace("#SCRIPTNAME#", Path.GetFileNameWithoutExtension(newScriptPath)); + string projectName = Application.productName; + template = template.Replace("#PROJECTNAME#", projectName); + + File.WriteAllText(newScriptPath, template); + AssetDatabase.Refresh(); + Selection.activeObject = AssetDatabase.LoadAssetAtPath(newScriptPath); + return newScriptPath; + } + + } +} \ No newline at end of file diff --git a/Editor/Library/Utilities/Core.cs.meta b/Editor/Core/Utilities/Editor_Library.cs.meta similarity index 100% rename from Editor/Library/Utilities/Core.cs.meta rename to Editor/Core/Utilities/Editor_Library.cs.meta diff --git a/Editor/Library/Drawers.meta b/Editor/Library/Drawers.meta new file mode 100644 index 00000000..bfda2d7a --- /dev/null +++ b/Editor/Library/Drawers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 09f6f3abd6dcd6748b7743fe122234a1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Library/Vendor/SerializableDictionary/SerializableDictionaryPropertyDrawer.cs b/Editor/Library/Drawers/MapDrawer.cs similarity index 96% rename from Editor/Library/Vendor/SerializableDictionary/SerializableDictionaryPropertyDrawer.cs rename to Editor/Library/Drawers/MapDrawer.cs index 8e97de0f..4266dfd9 100644 --- a/Editor/Library/Vendor/SerializableDictionary/SerializableDictionaryPropertyDrawer.cs +++ b/Editor/Library/Drawers/MapDrawer.cs @@ -7,24 +7,12 @@ namespace RealMethod.Editor { - [CustomPropertyDrawer(typeof(SerializableDictionaryBase), true)] + [CustomPropertyDrawer(typeof(MapCore), true)] #if NET_4_6 || NET_STANDARD_2_0 [CustomPropertyDrawer(typeof(SerializableHashSetBase), true)] #endif - public class SerializableDictionaryPropertyDrawer : PropertyDrawer + public class MapDrawer : PropertyDrawer { - const string KeysFieldName = "m_keys"; - const string ValuesFieldName = "m_values"; - protected const float IndentWidth = 15f; - - static GUIContent s_iconPlus = IconContent("Toolbar Plus", "Add entry"); - static GUIContent s_iconMinus = IconContent("Toolbar Minus", "Remove entry"); - static GUIContent s_warningIconConflict = IconContent("console.warnicon.sml", "Conflicting key, this entry will be lost"); - static GUIContent s_warningIconOther = IconContent("console.infoicon.sml", "Conflicting key"); - static GUIContent s_warningIconNull = IconContent("console.warnicon.sml", "Null key, this entry will be lost"); - static GUIStyle s_buttonStyle = GUIStyle.none; - static GUIContent s_tempContent = new GUIContent(); - class ConflictState { @@ -36,7 +24,6 @@ class ConflictState public bool conflictValuePropertyExpanded = false; public float conflictLineHeight = 0f; } - struct PropertyIdentity { public PropertyIdentity(SerializedProperty property) @@ -48,9 +35,19 @@ public PropertyIdentity(SerializedProperty property) public UnityEngine.Object instance; public string propertyPath; } + struct EnumerationEntry + { + public SerializedProperty keyProperty; + public SerializedProperty valueProperty; + public int index; - static Dictionary s_conflictStateDict = new Dictionary(); - + public EnumerationEntry(SerializedProperty keyProperty, SerializedProperty valueProperty, int index) + { + this.keyProperty = keyProperty; + this.valueProperty = valueProperty; + this.index = index; + } + } enum Action { None, @@ -58,166 +55,52 @@ enum Action Remove } - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - label = EditorGUI.BeginProperty(position, label, property); - - Action buttonAction = Action.None; - int buttonActionIndex = 0; - - var keyArrayProperty = property.FindPropertyRelative(KeysFieldName); - var valueArrayProperty = property.FindPropertyRelative(ValuesFieldName); - - ConflictState conflictState = GetConflictState(property); - - if (conflictState.conflictIndex != -1) - { - keyArrayProperty.InsertArrayElementAtIndex(conflictState.conflictIndex); - var keyProperty = keyArrayProperty.GetArrayElementAtIndex(conflictState.conflictIndex); - SetPropertyValue(keyProperty, conflictState.conflictKey); - keyProperty.isExpanded = conflictState.conflictKeyPropertyExpanded; - - if (valueArrayProperty != null) - { - valueArrayProperty.InsertArrayElementAtIndex(conflictState.conflictIndex); - var valueProperty = valueArrayProperty.GetArrayElementAtIndex(conflictState.conflictIndex); - SetPropertyValue(valueProperty, conflictState.conflictValue); - valueProperty.isExpanded = conflictState.conflictValuePropertyExpanded; - } - } - - var buttonWidth = s_buttonStyle.CalcSize(s_iconPlus).x; - - var labelPosition = position; - labelPosition.height = EditorGUIUtility.singleLineHeight; - if (property.isExpanded) - labelPosition.xMax -= s_buttonStyle.CalcSize(s_iconPlus).x; - - EditorGUI.PropertyField(labelPosition, property, label, false); - // property.isExpanded = EditorGUI.Foldout(labelPosition, property.isExpanded, label); - if (property.isExpanded) - { - var buttonPosition = position; - buttonPosition.xMin = buttonPosition.xMax - buttonWidth; - buttonPosition.height = EditorGUIUtility.singleLineHeight; - EditorGUI.BeginDisabledGroup(conflictState.conflictIndex != -1); - if (GUI.Button(buttonPosition, s_iconPlus, s_buttonStyle)) - { - buttonAction = Action.Add; - buttonActionIndex = keyArrayProperty.arraySize; - } - EditorGUI.EndDisabledGroup(); - - EditorGUI.indentLevel++; - var linePosition = position; - linePosition.y += EditorGUIUtility.singleLineHeight; - linePosition.xMax -= buttonWidth; - - foreach (var entry in EnumerateEntries(keyArrayProperty, valueArrayProperty)) - { - var keyProperty = entry.keyProperty; - var valueProperty = entry.valueProperty; - int i = entry.index; - - float lineHeight = DrawKeyValueLine(keyProperty, valueProperty, linePosition, i); - - buttonPosition = linePosition; - buttonPosition.x = linePosition.xMax; - buttonPosition.height = EditorGUIUtility.singleLineHeight; - if (GUI.Button(buttonPosition, s_iconMinus, s_buttonStyle)) - { - buttonAction = Action.Remove; - buttonActionIndex = i; - } - - if (i == conflictState.conflictIndex && conflictState.conflictOtherIndex == -1) - { - var iconPosition = linePosition; - iconPosition.size = s_buttonStyle.CalcSize(s_warningIconNull); - GUI.Label(iconPosition, s_warningIconNull); - } - else if (i == conflictState.conflictIndex) - { - var iconPosition = linePosition; - iconPosition.size = s_buttonStyle.CalcSize(s_warningIconConflict); - GUI.Label(iconPosition, s_warningIconConflict); - } - else if (i == conflictState.conflictOtherIndex) - { - var iconPosition = linePosition; - iconPosition.size = s_buttonStyle.CalcSize(s_warningIconOther); - GUI.Label(iconPosition, s_warningIconOther); - } - - - linePosition.y += lineHeight; - } + const string KeysFieldName = "m_keys"; + const string ValuesFieldName = "m_values"; + protected const float IndentWidth = 15f; - EditorGUI.indentLevel--; - } - if (buttonAction == Action.Add) - { - keyArrayProperty.InsertArrayElementAtIndex(buttonActionIndex); - if (valueArrayProperty != null) - valueArrayProperty.InsertArrayElementAtIndex(buttonActionIndex); - } - else if (buttonAction == Action.Remove) - { - DeleteArrayElementAtIndex(keyArrayProperty, buttonActionIndex); - if (valueArrayProperty != null) - DeleteArrayElementAtIndex(valueArrayProperty, buttonActionIndex); - } + static MapDrawer() + { + Dictionary serializedPropertyValueAccessorsNameDict = new Dictionary() { + { SerializedPropertyType.Integer, "intValue" }, + { SerializedPropertyType.Boolean, "boolValue" }, + { SerializedPropertyType.Float, "floatValue" }, + { SerializedPropertyType.String, "stringValue" }, + { SerializedPropertyType.Color, "colorValue" }, + { SerializedPropertyType.ObjectReference, "objectReferenceValue" }, + { SerializedPropertyType.LayerMask, "intValue" }, + { SerializedPropertyType.Enum, "intValue" }, + { SerializedPropertyType.Vector2, "vector2Value" }, + { SerializedPropertyType.Vector3, "vector3Value" }, + { SerializedPropertyType.Vector4, "vector4Value" }, + { SerializedPropertyType.Rect, "rectValue" }, + { SerializedPropertyType.ArraySize, "intValue" }, + { SerializedPropertyType.Character, "intValue" }, + { SerializedPropertyType.AnimationCurve, "animationCurveValue" }, + { SerializedPropertyType.Bounds, "boundsValue" }, + { SerializedPropertyType.Quaternion, "quaternionValue" }, + }; + Type serializedPropertyType = typeof(SerializedProperty); - conflictState.conflictKey = null; - conflictState.conflictValue = null; - conflictState.conflictIndex = -1; - conflictState.conflictOtherIndex = -1; - conflictState.conflictLineHeight = 0f; - conflictState.conflictKeyPropertyExpanded = false; - conflictState.conflictValuePropertyExpanded = false; + s_serializedPropertyValueAccessorsDict = new Dictionary(); + BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; - foreach (var entry1 in EnumerateEntries(keyArrayProperty, valueArrayProperty)) + foreach (var kvp in serializedPropertyValueAccessorsNameDict) { - var keyProperty1 = entry1.keyProperty; - int i = entry1.index; - object keyProperty1Value = GetPropertyValue(keyProperty1); - - if (keyProperty1Value == null) - { - var valueProperty1 = entry1.valueProperty; - SaveProperty(keyProperty1, valueProperty1, i, -1, conflictState); - DeleteArrayElementAtIndex(keyArrayProperty, i); - if (valueArrayProperty != null) - DeleteArrayElementAtIndex(valueArrayProperty, i); - - break; - } - - - foreach (var entry2 in EnumerateEntries(keyArrayProperty, valueArrayProperty, i + 1)) - { - var keyProperty2 = entry2.keyProperty; - int j = entry2.index; - object keyProperty2Value = GetPropertyValue(keyProperty2); - - if (ComparePropertyValues(keyProperty1Value, keyProperty2Value)) - { - var valueProperty2 = entry2.valueProperty; - SaveProperty(keyProperty2, valueProperty2, j, i, conflictState); - DeleteArrayElementAtIndex(keyArrayProperty, j); - if (valueArrayProperty != null) - DeleteArrayElementAtIndex(valueArrayProperty, j); - - goto breakLoops; - } - } + PropertyInfo propertyInfo = serializedPropertyType.GetProperty(kvp.Value, flags); + s_serializedPropertyValueAccessorsDict.Add(kvp.Key, propertyInfo); } - breakLoops: - - EditorGUI.EndProperty(); } - + static GUIContent s_iconPlus = IconContent("Toolbar Plus", "Add entry"); + static GUIContent s_iconMinus = IconContent("Toolbar Minus", "Remove entry"); + static GUIContent s_warningIconConflict = IconContent("console.warnicon.sml", "Conflicting key, this entry will be lost"); + static GUIContent s_warningIconOther = IconContent("console.infoicon.sml", "Conflicting key"); + static GUIContent s_warningIconNull = IconContent("console.warnicon.sml", "Null key, this entry will be lost"); + static GUIStyle s_buttonStyle = GUIStyle.none; + static GUIContent s_tempContent = new GUIContent(); + static Dictionary s_conflictStateDict = new Dictionary(); + static Dictionary s_serializedPropertyValueAccessorsDict; static float DrawKeyValueLine(SerializedProperty keyProperty, SerializedProperty valueProperty, Rect linePosition, int index) { bool keyCanBeExpanded = CanPropertyBeExpanded(keyProperty); @@ -250,7 +133,6 @@ static float DrawKeyValueLine(SerializedProperty keyProperty, SerializedProperty } } } - static float DrawKeyValueLineSimple(SerializedProperty keyProperty, SerializedProperty valueProperty, string keyLabel, string valueLabel, Rect linePosition) { float labelWidth = EditorGUIUtility.labelWidth; @@ -276,7 +158,6 @@ static float DrawKeyValueLineSimple(SerializedProperty keyProperty, SerializedPr return Mathf.Max(keyPropertyHeight, valuePropertyHeight); } - static float DrawKeyValueLineExpand(SerializedProperty keyProperty, SerializedProperty valueProperty, Rect linePosition) { float labelWidth = EditorGUIUtility.labelWidth; @@ -296,7 +177,6 @@ static float DrawKeyValueLineExpand(SerializedProperty keyProperty, SerializedPr return Mathf.Max(keyPropertyHeight, valuePropertyHeight); } - static float DrawKeyLine(SerializedProperty keyProperty, Rect linePosition, string keyLabel) { float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); @@ -309,7 +189,6 @@ static float DrawKeyLine(SerializedProperty keyProperty, Rect linePosition, stri return keyPropertyHeight; } - static bool CanPropertyBeExpanded(SerializedProperty property) { switch (property.propertyType) @@ -322,7 +201,6 @@ static bool CanPropertyBeExpanded(SerializedProperty property) return false; } } - static void SaveProperty(SerializedProperty keyProperty, SerializedProperty valueProperty, int index, int otherIndex, ConflictState conflictState) { conflictState.conflictKey = GetPropertyValue(keyProperty); @@ -336,37 +214,6 @@ static void SaveProperty(SerializedProperty keyProperty, SerializedProperty valu conflictState.conflictKeyPropertyExpanded = keyProperty.isExpanded; conflictState.conflictValuePropertyExpanded = valueProperty != null ? valueProperty.isExpanded : false; } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - float propertyHeight = EditorGUIUtility.singleLineHeight; - - if (property.isExpanded) - { - var keysProperty = property.FindPropertyRelative(KeysFieldName); - var valuesProperty = property.FindPropertyRelative(ValuesFieldName); - - foreach (var entry in EnumerateEntries(keysProperty, valuesProperty)) - { - var keyProperty = entry.keyProperty; - var valueProperty = entry.valueProperty; - float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); - float valuePropertyHeight = valueProperty != null ? EditorGUI.GetPropertyHeight(valueProperty) : 0f; - float lineHeight = Mathf.Max(keyPropertyHeight, valuePropertyHeight); - propertyHeight += lineHeight; - } - - ConflictState conflictState = GetConflictState(property); - - if (conflictState.conflictIndex != -1) - { - propertyHeight += conflictState.conflictLineHeight; - } - } - - return propertyHeight; - } - static ConflictState GetConflictState(SerializedProperty property) { ConflictState conflictState; @@ -378,54 +225,16 @@ static ConflictState GetConflictState(SerializedProperty property) } return conflictState; } - - static Dictionary s_serializedPropertyValueAccessorsDict; - - static SerializableDictionaryPropertyDrawer() - { - Dictionary serializedPropertyValueAccessorsNameDict = new Dictionary() { - { SerializedPropertyType.Integer, "intValue" }, - { SerializedPropertyType.Boolean, "boolValue" }, - { SerializedPropertyType.Float, "floatValue" }, - { SerializedPropertyType.String, "stringValue" }, - { SerializedPropertyType.Color, "colorValue" }, - { SerializedPropertyType.ObjectReference, "objectReferenceValue" }, - { SerializedPropertyType.LayerMask, "intValue" }, - { SerializedPropertyType.Enum, "intValue" }, - { SerializedPropertyType.Vector2, "vector2Value" }, - { SerializedPropertyType.Vector3, "vector3Value" }, - { SerializedPropertyType.Vector4, "vector4Value" }, - { SerializedPropertyType.Rect, "rectValue" }, - { SerializedPropertyType.ArraySize, "intValue" }, - { SerializedPropertyType.Character, "intValue" }, - { SerializedPropertyType.AnimationCurve, "animationCurveValue" }, - { SerializedPropertyType.Bounds, "boundsValue" }, - { SerializedPropertyType.Quaternion, "quaternionValue" }, - }; - Type serializedPropertyType = typeof(SerializedProperty); - - s_serializedPropertyValueAccessorsDict = new Dictionary(); - BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; - - foreach (var kvp in serializedPropertyValueAccessorsNameDict) - { - PropertyInfo propertyInfo = serializedPropertyType.GetProperty(kvp.Value, flags); - s_serializedPropertyValueAccessorsDict.Add(kvp.Key, propertyInfo); - } - } - static GUIContent IconContent(string name, string tooltip) { var builtinIcon = EditorGUIUtility.IconContent(name); return new GUIContent(builtinIcon.image, tooltip); } - static GUIContent TempContent(string text) { s_tempContent.text = text; return s_tempContent; } - static void DeleteArrayElementAtIndex(SerializedProperty arrayProperty, int index) { var property = arrayProperty.GetArrayElementAtIndex(index); @@ -437,7 +246,6 @@ static void DeleteArrayElementAtIndex(SerializedProperty arrayProperty, int inde arrayProperty.DeleteArrayElementAtIndex(index); } - public static object GetPropertyValue(SerializedProperty p) { PropertyInfo propertyInfo; @@ -453,7 +261,6 @@ public static object GetPropertyValue(SerializedProperty p) return GetPropertyValueGeneric(p); } } - static void SetPropertyValue(SerializedProperty p, object v) { PropertyInfo propertyInfo; @@ -469,7 +276,6 @@ static void SetPropertyValue(SerializedProperty p, object v) SetPropertyValueGeneric(p, v); } } - static object GetPropertyValueArray(SerializedProperty property) { object[] array = new object[property.arraySize]; @@ -480,7 +286,6 @@ static object GetPropertyValueArray(SerializedProperty property) } return array; } - static object GetPropertyValueGeneric(SerializedProperty property) { Dictionary dict = new Dictionary(); @@ -497,7 +302,6 @@ static object GetPropertyValueGeneric(SerializedProperty property) } return dict; } - static void SetPropertyValueArray(SerializedProperty property, object v) { object[] array = (object[])v; @@ -508,7 +312,6 @@ static void SetPropertyValueArray(SerializedProperty property, object v) SetPropertyValue(item, array[i]); } } - static void SetPropertyValueGeneric(SerializedProperty property, object v) { Dictionary dict = (Dictionary)v; @@ -523,7 +326,6 @@ static void SetPropertyValueGeneric(SerializedProperty property, object v) } while (iterator.Next(false) && iterator.propertyPath != end.propertyPath); } } - static bool ComparePropertyValues(object value1, object value2) { if (value1 is Dictionary && value2 is Dictionary) @@ -537,7 +339,6 @@ static bool ComparePropertyValues(object value1, object value2) return object.Equals(value1, value2); } } - static bool CompareDictionaries(Dictionary dict1, Dictionary dict2) { if (dict1.Count != dict2.Count) @@ -558,21 +359,6 @@ static bool CompareDictionaries(Dictionary dict1, Dictionary EnumerateEntries(SerializedProperty keyArrayProperty, SerializedProperty valueArrayProperty, int startIndex = 0) { if (keyArrayProperty.arraySize > startIndex) @@ -591,21 +377,200 @@ static IEnumerable EnumerateEntries(SerializedProperty keyArra && !SerializedProperty.EqualContents(keyProperty, endProperty)); } } - } - [CustomPropertyDrawer(typeof(SerializableDictionaryBase.Storage), true)] - public class SerializableDictionaryStoragePropertyDrawer : PropertyDrawer - { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - property.Next(true); - EditorGUI.PropertyField(position, property, label, true); - } + label = EditorGUI.BeginProperty(position, label, property); + + Action buttonAction = Action.None; + int buttonActionIndex = 0; + + var keyArrayProperty = property.FindPropertyRelative(KeysFieldName); + var valueArrayProperty = property.FindPropertyRelative(ValuesFieldName); + + ConflictState conflictState = GetConflictState(property); + + if (conflictState.conflictIndex != -1) + { + keyArrayProperty.InsertArrayElementAtIndex(conflictState.conflictIndex); + var keyProperty = keyArrayProperty.GetArrayElementAtIndex(conflictState.conflictIndex); + SetPropertyValue(keyProperty, conflictState.conflictKey); + keyProperty.isExpanded = conflictState.conflictKeyPropertyExpanded; + + if (valueArrayProperty != null) + { + valueArrayProperty.InsertArrayElementAtIndex(conflictState.conflictIndex); + var valueProperty = valueArrayProperty.GetArrayElementAtIndex(conflictState.conflictIndex); + SetPropertyValue(valueProperty, conflictState.conflictValue); + valueProperty.isExpanded = conflictState.conflictValuePropertyExpanded; + } + } + + var buttonWidth = s_buttonStyle.CalcSize(s_iconPlus).x; + + var labelPosition = position; + labelPosition.height = EditorGUIUtility.singleLineHeight; + if (property.isExpanded) + labelPosition.xMax -= s_buttonStyle.CalcSize(s_iconPlus).x; + + // Modify label to include count + var newLabel = new GUIContent($"{label.text} ({keyArrayProperty.arraySize})"); + + EditorGUI.PropertyField(labelPosition, property, newLabel, false); + // property.isExpanded = EditorGUI.Foldout(labelPosition, property.isExpanded, label); + if (property.isExpanded) + { + var buttonPosition = position; + buttonPosition.xMin = buttonPosition.xMax - buttonWidth; + buttonPosition.height = EditorGUIUtility.singleLineHeight; + EditorGUI.BeginDisabledGroup(conflictState.conflictIndex != -1); + if (GUI.Button(buttonPosition, s_iconPlus, s_buttonStyle)) + { + buttonAction = Action.Add; + buttonActionIndex = keyArrayProperty.arraySize; + } + EditorGUI.EndDisabledGroup(); + + EditorGUI.indentLevel++; + var linePosition = position; + linePosition.y += EditorGUIUtility.singleLineHeight; + linePosition.xMax -= buttonWidth; + + foreach (var entry in EnumerateEntries(keyArrayProperty, valueArrayProperty)) + { + var keyProperty = entry.keyProperty; + var valueProperty = entry.valueProperty; + int i = entry.index; + + float lineHeight = DrawKeyValueLine(keyProperty, valueProperty, linePosition, i); + + buttonPosition = linePosition; + buttonPosition.x = linePosition.xMax; + buttonPosition.height = EditorGUIUtility.singleLineHeight; + if (GUI.Button(buttonPosition, s_iconMinus, s_buttonStyle)) + { + buttonAction = Action.Remove; + buttonActionIndex = i; + } + + if (i == conflictState.conflictIndex && conflictState.conflictOtherIndex == -1) + { + var iconPosition = linePosition; + iconPosition.size = s_buttonStyle.CalcSize(s_warningIconNull); + GUI.Label(iconPosition, s_warningIconNull); + } + else if (i == conflictState.conflictIndex) + { + var iconPosition = linePosition; + iconPosition.size = s_buttonStyle.CalcSize(s_warningIconConflict); + GUI.Label(iconPosition, s_warningIconConflict); + } + else if (i == conflictState.conflictOtherIndex) + { + var iconPosition = linePosition; + iconPosition.size = s_buttonStyle.CalcSize(s_warningIconOther); + GUI.Label(iconPosition, s_warningIconOther); + } + + + linePosition.y += lineHeight; + } + + EditorGUI.indentLevel--; + } + + if (buttonAction == Action.Add) + { + keyArrayProperty.InsertArrayElementAtIndex(buttonActionIndex); + if (valueArrayProperty != null) + valueArrayProperty.InsertArrayElementAtIndex(buttonActionIndex); + } + else if (buttonAction == Action.Remove) + { + DeleteArrayElementAtIndex(keyArrayProperty, buttonActionIndex); + if (valueArrayProperty != null) + DeleteArrayElementAtIndex(valueArrayProperty, buttonActionIndex); + } + + conflictState.conflictKey = null; + conflictState.conflictValue = null; + conflictState.conflictIndex = -1; + conflictState.conflictOtherIndex = -1; + conflictState.conflictLineHeight = 0f; + conflictState.conflictKeyPropertyExpanded = false; + conflictState.conflictValuePropertyExpanded = false; + + foreach (var entry1 in EnumerateEntries(keyArrayProperty, valueArrayProperty)) + { + var keyProperty1 = entry1.keyProperty; + int i = entry1.index; + object keyProperty1Value = GetPropertyValue(keyProperty1); + if (keyProperty1Value == null) + { + var valueProperty1 = entry1.valueProperty; + SaveProperty(keyProperty1, valueProperty1, i, -1, conflictState); + DeleteArrayElementAtIndex(keyArrayProperty, i); + if (valueArrayProperty != null) + DeleteArrayElementAtIndex(valueArrayProperty, i); + + break; + } + + + foreach (var entry2 in EnumerateEntries(keyArrayProperty, valueArrayProperty, i + 1)) + { + var keyProperty2 = entry2.keyProperty; + int j = entry2.index; + object keyProperty2Value = GetPropertyValue(keyProperty2); + + if (ComparePropertyValues(keyProperty1Value, keyProperty2Value)) + { + var valueProperty2 = entry2.valueProperty; + SaveProperty(keyProperty2, valueProperty2, j, i, conflictState); + DeleteArrayElementAtIndex(keyArrayProperty, j); + if (valueArrayProperty != null) + DeleteArrayElementAtIndex(valueArrayProperty, j); + + goto breakLoops; + } + } + } + breakLoops: + + EditorGUI.EndProperty(); + } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - property.Next(true); - return EditorGUI.GetPropertyHeight(property); + float propertyHeight = EditorGUIUtility.singleLineHeight; + + if (property.isExpanded) + { + var keysProperty = property.FindPropertyRelative(KeysFieldName); + var valuesProperty = property.FindPropertyRelative(ValuesFieldName); + + foreach (var entry in EnumerateEntries(keysProperty, valuesProperty)) + { + var keyProperty = entry.keyProperty; + var valueProperty = entry.valueProperty; + float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); + float valuePropertyHeight = valueProperty != null ? EditorGUI.GetPropertyHeight(valueProperty) : 0f; + float lineHeight = Mathf.Max(keyPropertyHeight, valuePropertyHeight); + propertyHeight += lineHeight; + } + + ConflictState conflictState = GetConflictState(property); + + if (conflictState.conflictIndex != -1) + { + propertyHeight += conflictState.conflictLineHeight; + } + } + + return propertyHeight; } } + + } \ No newline at end of file diff --git a/Editor/Library/Vendor/SerializableDictionary/SerializableDictionaryPropertyDrawer.cs.meta b/Editor/Library/Drawers/MapDrawer.cs.meta similarity index 100% rename from Editor/Library/Vendor/SerializableDictionary/SerializableDictionaryPropertyDrawer.cs.meta rename to Editor/Library/Drawers/MapDrawer.cs.meta diff --git a/Editor/Library/Drawers/MapStorageDrawer.cs b/Editor/Library/Drawers/MapStorageDrawer.cs new file mode 100644 index 00000000..e40d60e3 --- /dev/null +++ b/Editor/Library/Drawers/MapStorageDrawer.cs @@ -0,0 +1,21 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomPropertyDrawer(typeof(MapCore.Storage), true)] + public class MapStorageDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + property.Next(true); + EditorGUI.PropertyField(position, property, label, true); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + property.Next(true); + return EditorGUI.GetPropertyHeight(property); + } + } +} \ No newline at end of file diff --git a/Editor/Library/Drawers/MapStorageDrawer.cs.meta b/Editor/Library/Drawers/MapStorageDrawer.cs.meta new file mode 100644 index 00000000..95b23ff6 --- /dev/null +++ b/Editor/Library/Drawers/MapStorageDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 22efdf0df2df5bf44a89841c2078e044 \ No newline at end of file diff --git a/Editor/Library/MenuItem.meta b/Editor/Library/MenuItem.meta new file mode 100644 index 00000000..528bfd28 --- /dev/null +++ b/Editor/Library/MenuItem.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c42de7ea7ccb8124c81a1cca94b15c47 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Library/Vendor/UnityEditorIcons/EditorIcons.cs b/Editor/Library/MenuItem/EditorIconsMenu.cs similarity index 99% rename from Editor/Library/Vendor/UnityEditorIcons/EditorIcons.cs rename to Editor/Library/MenuItem/EditorIconsMenu.cs index 8c72e7e4..bd071a80 100644 --- a/Editor/Library/Vendor/UnityEditorIcons/EditorIcons.cs +++ b/Editor/Library/MenuItem/EditorIconsMenu.cs @@ -10,7 +10,7 @@ namespace RealMethod.Editor { #if UNITY_EDITOR - public class EditorIcons : EditorWindow + public class EditorIconsMenu : EditorWindow { [MenuItem("Tools/RealMethod/Vendor/EditorIcons")] public static void EditorIconsOpen() @@ -18,7 +18,7 @@ public static void EditorIconsOpen() #if UNITY_2018 var w = GetWindow("Editor Icons"); #else - var w = CreateWindow("Editor Icons"); + var w = CreateWindow("Editor Icons"); #endif w.ShowUtility(); w.minSize = new Vector2(320, 450); diff --git a/Editor/Library/Vendor/UnityEditorIcons/EditorIcons.cs.meta b/Editor/Library/MenuItem/EditorIconsMenu.cs.meta similarity index 100% rename from Editor/Library/Vendor/UnityEditorIcons/EditorIcons.cs.meta rename to Editor/Library/MenuItem/EditorIconsMenu.cs.meta diff --git a/Editor/Library/SharedScripts/Classes/EditorProperty.cs b/Editor/Library/SharedScripts/Classes/EditorProperty.cs index 22cba318..2228ac59 100644 --- a/Editor/Library/SharedScripts/Classes/EditorProperty.cs +++ b/Editor/Library/SharedScripts/Classes/EditorProperty.cs @@ -3,16 +3,39 @@ using System.Collections.Generic; using System.Reflection; + namespace RealMethod.Editor { - // Base EditorProperty Class - // This class is used to create custom editor properties that can be rendered in the Unity Editor. + /// + /// Base class responsible for rendering a property in the Unity Editor + /// and handling potential validation errors with optional fix actions. + /// public abstract class EditorProperty { - protected Object Owner; + /// + /// Holds the current error state for this property. + /// If not null, the property will render an error instead of its normal UI. + /// + private ErrorAction PropertyError; + + + /// + /// The Unity object that owns this property. + /// Usually a MonoBehaviour, ScriptableObject, or other UnityEngine.Object. + /// + public Object Owner { get; private set; } + /// + /// Name of the property being rendered. + /// Used for identification and debugging. + /// public string PropertyName { get; private set; } - private ErrorAction PropertyError = null; + + /// + /// Creates a new editor property renderer. + /// + /// Name of the property. + /// Object that owns the property. public EditorProperty(string _Name, Object _Owner) { PropertyName = _Name; @@ -24,9 +47,17 @@ public EditorProperty(string _Name, Object _Owner) } } + + /// + /// Renders the property in the inspector. + /// If the property has an error, the error UI is rendered instead. + /// + /// + /// A byte result defined by the implementation (usually used for change flags or state). + /// public byte Render() { - if (PropertyError == null) + if (!PropertyError.IsValid) { return UpdateRender(); } @@ -36,38 +67,144 @@ public byte Render() return 0; } } - + /// + /// Registers an error for this property and provides a fix callback. + /// When an error exists, normal rendering is replaced with an error UI. + /// + /// Error message shown in the inspector. + /// Identifier used to determine which fix action to apply. protected void Error(string message, int id) { - PropertyError = new ErrorAction(message, id, FixError); + PropertyError.Create(message, id, FixError); } + + /// + /// Implemented by derived classes to render the property UI. + /// Called only when no error is active. + /// protected abstract byte UpdateRender(); + /// + /// Called when the user activates the fix action from an error message. + /// + /// Identifier of the error that should be fixed. protected abstract void FixError(int Id); } + /// + /// Generic editor property wrapper that stores and manages a value of type . + /// + /// This class extends and adds value storage, + /// comparison operators, and implicit conversion for easier usage in editor code. + /// + /// It is typically used by custom inspector systems to track a property's + /// current value and optionally compare against a cached value to detect changes. + /// + /// Type of the property value. public abstract class EditorProperty : EditorProperty { + /// + /// Returns true if the current value is valid (not null). + /// Mainly useful for reference types. + /// public bool isvalid => CurrentValue != null; + /// + /// Current value of the property. + /// This is the active value used by the editor UI. + /// protected T CurrentValue; + /// + /// Cached value used for change tracking or restoring previous state. + /// (Likely intended as "CacheValue".) + /// protected T CashValue; + /// + /// Creates a new property without assigning a default value. + /// + /// Name of the property. + /// Owner Unity object. public EditorProperty(string Name, Object other) : base(Name, other) { } + /// + /// Creates a new property with a default value. + /// The default is applied to both the current and cached values. + /// + /// Name of the property. + /// Owner Unity object. + /// Initial value assigned to the property. public EditorProperty(string Name, Object other, T DefaultValue) : base(Name, other) { CurrentValue = DefaultValue; CashValue = DefaultValue; } + /// + /// Returns the current value of the property. + /// public T GetValue() { return CurrentValue; } + /// + /// Updates the current value of the property. + /// + /// New value to assign. public void SetValue(T NewValue) { CurrentValue = NewValue; } + // Operators + public static implicit operator T(EditorProperty property) + { + return property != null ? property.CurrentValue : default; + } + public static bool operator ==(EditorProperty a, EditorProperty b) + { + if (ReferenceEquals(a, b)) + return true; + + if (a is null || b is null) + return false; + + return EqualityComparer.Default.Equals(a.CurrentValue, b.CurrentValue); + } + public static bool operator !=(EditorProperty a, EditorProperty b) + { + return !(a == b); + } + public static bool operator ==(EditorProperty a, T b) + { + if (a is null) + return false; + + return EqualityComparer.Default.Equals(a.CurrentValue, b); + } + public static bool operator !=(EditorProperty a, T b) + { + return !(a == b); + } + + // Overrides + /// + /// Determines equality between this property and another object. + /// Supports comparison with both EditorProperty<T> and raw values of type T. + /// + public override bool Equals(object obj) + { + if (obj is EditorProperty other) + return EqualityComparer.Default.Equals(CurrentValue, other.CurrentValue); + + if (obj is T value) + return EqualityComparer.Default.Equals(CurrentValue, value); + + return false; + } + public override int GetHashCode() + { + return CurrentValue?.GetHashCode() ?? 0; + } + } public abstract class EditorPropertyList : EditorProperty { @@ -317,7 +454,7 @@ public EP_Dropdown(string Name, string[] options, Object other) : base(Name, oth protected override byte UpdateRender() { - CashValue = EditorGUILayout.Popup("Ability Effect", CurrentValue, Options); + CashValue = EditorGUILayout.Popup($"{PropertyName}:", CurrentValue, Options); if (CashValue == CurrentValue) { return 0; // No change @@ -333,9 +470,9 @@ protected override void FixError(int Id) throw new System.NotImplementedException(); } } - public class EP_ScriptableObject : EditorProperty where T : ScriptableObject + public class EP_Asset : EditorProperty where T : PrimitiveAsset { - public EP_ScriptableObject(string Name, Object other) : base(Name, other) + public EP_Asset(string Name, Object other) : base(Name, other) { CurrentValue = null; CashValue = null; @@ -359,9 +496,9 @@ protected override void FixError(int Id) } } - public class EP_Class : EditorProperty where T : class + public class EP_Variable : EditorProperty where T : class { - public EP_Class(string Name, Object other) : base(Name, other) + public EP_Variable(string Name, Object other) : base(Name, other) { } @@ -524,7 +661,6 @@ protected override void FixError(int Id) } - // Storeable // EditorProperty that can be stored in the MetaData public abstract class EP_Storeable : EditorProperty @@ -616,9 +752,9 @@ public List GetList() } /// Sample EP_Storeable - public class EPS_ScriptableObjectList : EP_StoreableList where T : ScriptableObject + public class EPS_AssetList : EP_StoreableList where T : PrimitiveAsset { - public EPS_ScriptableObjectList(UnityEditor.Editor other, string Name) : base(other, Name) + public EPS_AssetList(UnityEditor.Editor other, string Name) : base(other, Name) { } @@ -715,9 +851,6 @@ private string GetTargetPath(T Target) return AssetDatabase.GetAssetPath(Target); } - - - } public class EPS_Enum : EP_Storeable where T : System.Enum { @@ -770,9 +903,9 @@ protected override void FixError(int Id) { } } - public class EPS_ScriptableObject : EP_Storeable where T : ScriptableObject + public class EPS_Asset : EP_Storeable where T : PrimitiveAsset { - public EPS_ScriptableObject(UnityEditor.Editor other, string Name) : base(other, Name) + public EPS_Asset(UnityEditor.Editor other, string Name) : base(other, Name) { } diff --git a/Editor/Library/SharedScripts/Structs.meta b/Editor/Library/SharedScripts/Structs.meta new file mode 100644 index 00000000..cf19f97d --- /dev/null +++ b/Editor/Library/SharedScripts/Structs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f6e53f4684bb6f42bf96ae27ac86bb8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Library/SharedScripts/Classes/ErrorAction.cs b/Editor/Library/SharedScripts/Structs/ErrorAction.cs similarity index 70% rename from Editor/Library/SharedScripts/Classes/ErrorAction.cs rename to Editor/Library/SharedScripts/Structs/ErrorAction.cs index d42bf7f2..316550af 100644 --- a/Editor/Library/SharedScripts/Classes/ErrorAction.cs +++ b/Editor/Library/SharedScripts/Structs/ErrorAction.cs @@ -4,13 +4,15 @@ namespace RealMethod.Editor { - public class ErrorAction + public struct ErrorAction { + public bool IsValid => string.IsNullOrEmpty(ErrorMessage); public string ErrorMessage { get; private set; } private Action OnFixed; - private int ID = 0; + private int ID; - public ErrorAction(string message, int id, Action callback) + + public void Create(string message, int id, Action callback) { ErrorMessage = message; ID = id; @@ -23,6 +25,7 @@ public void RenderError() if (GUILayout.Button("Fix Issue")) { + ErrorMessage = string.Empty; OnFixed?.Invoke(ID); } } diff --git a/Editor/Library/SharedScripts/Classes/ErrorAction.cs.meta b/Editor/Library/SharedScripts/Structs/ErrorAction.cs.meta similarity index 100% rename from Editor/Library/SharedScripts/Classes/ErrorAction.cs.meta rename to Editor/Library/SharedScripts/Structs/ErrorAction.cs.meta diff --git a/Editor/Library/Utilities/Assets.cs b/Editor/Library/Utilities/AssetsLibrary.cs similarity index 85% rename from Editor/Library/Utilities/Assets.cs rename to Editor/Library/Utilities/AssetsLibrary.cs index 4ac66790..77674045 100644 --- a/Editor/Library/Utilities/Assets.cs +++ b/Editor/Library/Utilities/AssetsLibrary.cs @@ -4,9 +4,9 @@ namespace RealMethod.Editor { - public class RM_Assets + public static class RM_Asset { - public static string GetSelectedAssetPath() + public static string GetSelectedAssetDirectory() { string path = AssetDatabase.GetAssetPath(Selection.activeObject); if (string.IsNullOrEmpty(path)) return "Assets"; diff --git a/Editor/Library/Utilities/Assets.cs.meta b/Editor/Library/Utilities/AssetsLibrary.cs.meta similarity index 100% rename from Editor/Library/Utilities/Assets.cs.meta rename to Editor/Library/Utilities/AssetsLibrary.cs.meta diff --git a/Editor/Library/Utilities/CSV.cs b/Editor/Library/Utilities/CSVLibrary.cs similarity index 99% rename from Editor/Library/Utilities/CSV.cs rename to Editor/Library/Utilities/CSVLibrary.cs index 834e05a2..63988eb6 100644 --- a/Editor/Library/Utilities/CSV.cs +++ b/Editor/Library/Utilities/CSVLibrary.cs @@ -10,7 +10,6 @@ public static string[] ParseCSVRow(string csvLine) { return ParseSingleLine(csvLine).ToArray(); } - public static List ParseCSV(string csvText) { List rows = new List(); @@ -24,7 +23,6 @@ public static List ParseCSV(string csvText) return rows; } - public static string[] ParseCSVToFlatArray(string csvText) { List cells = new List(); @@ -37,7 +35,6 @@ public static string[] ParseCSVToFlatArray(string csvText) return cells.ToArray(); } - // This method parses a single line of CSV text and returns a list of strings. private static List ParseSingleLine(string csvLine) { diff --git a/Editor/Library/Utilities/CSV.cs.meta b/Editor/Library/Utilities/CSVLibrary.cs.meta similarity index 100% rename from Editor/Library/Utilities/CSV.cs.meta rename to Editor/Library/Utilities/CSVLibrary.cs.meta diff --git a/Editor/Library/Utilities/Core.cs b/Editor/Library/Utilities/Core.cs deleted file mode 100644 index e41574f2..00000000 --- a/Editor/Library/Utilities/Core.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.IO; -using UnityEditor; -using UnityEngine; - -namespace RealMethod.Editor -{ - public static class RM_CoreEditor - { - public const string SetttingAssetPath = "Assets/Resources/RealMethod/RealMethodSetting.asset"; - public static string ScriptTemplatesPath => GetPackagePath("com.mustard.realmethod") + "/Reservoir/ScriptTemplates"; - public static string PrefabTemplatePath => GetPackagePath("com.mustard.realmethod") + "/Reservoir/Prefabs"; - - private static string GetPackagePath(string packageName) - { - string[] guids = AssetDatabase.FindAssets("package", new[] { "Packages/" + packageName }); - foreach (string guid in guids) - { - string path = AssetDatabase.GUIDToAssetPath(guid); - if (path.Contains(packageName)) - { - string packagePath = Path.GetDirectoryName(path); - while (!string.IsNullOrEmpty(packagePath)) - { - if (File.Exists(Path.Combine(packagePath, "package.json"))) - return packagePath; - - packagePath = Path.GetDirectoryName(packagePath); - } - } - } - - Debug.LogError($"Could not find package path for: {packageName}"); - return null; - } - } -} \ No newline at end of file diff --git a/Editor/Library/Utilities/Create.cs b/Editor/Library/Utilities/Create.cs deleted file mode 100644 index 012366e5..00000000 --- a/Editor/Library/Utilities/Create.cs +++ /dev/null @@ -1,130 +0,0 @@ -using UnityEditor; -using UnityEngine; -using System.IO; - -namespace RealMethod.Editor -{ - public static class RM_Create - { - public static string Script(string templateFileName, string defaultName, bool UseProject = false) - { - string templatePath = string.Empty; - if (UseProject) - { - ProjectSettingAsset ProjectSetting = AssetDatabase.LoadAssetAtPath(RM_CoreEditor.SetttingAssetPath); - templatePath = Path.Combine(ProjectSetting.FindAddres(ProjectSettingAsset.IdentityAsset.ScriptTemplate).Path, templateFileName); - } - else - { - templatePath = Path.Combine(RM_CoreEditor.ScriptTemplatesPath, templateFileName); - } - - - if (!File.Exists(templatePath)) - { - Debug.LogError($"Template file not found: {templatePath}"); - return string.Empty; - } - - string selectedPath = RM_Assets.GetSelectedAssetPath(); - string newScriptPath = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(selectedPath, defaultName)); - - // Prompt user for script name before creating the file - string inputName = EditorUtility.SaveFilePanel( - "Create Script", - selectedPath, - Path.GetFileNameWithoutExtension(defaultName), - "cs" - ); - - if (string.IsNullOrEmpty(inputName)) - return string.Empty; - - // Ensure the path is relative to the Assets folder - if (inputName.StartsWith(Application.dataPath)) - newScriptPath = "Assets" + inputName.Substring(Application.dataPath.Length); - else - newScriptPath = inputName; - - string template = File.ReadAllText(templatePath); - template = template.Replace("#SCRIPTNAME#", Path.GetFileNameWithoutExtension(newScriptPath)); - string projectName = Application.productName; - template = template.Replace("#PROJECTNAME#", projectName); - - File.WriteAllText(newScriptPath, template); - AssetDatabase.Refresh(); - Selection.activeObject = AssetDatabase.LoadAssetAtPath(newScriptPath); - return newScriptPath; - } - public static GameObject Prefab(string prefabName, bool UseProject = false) - { - - string prefabPath = string.Empty; - if (UseProject) - { - ProjectSettingAsset ProjectSetting = AssetDatabase.LoadAssetAtPath(RM_CoreEditor.SetttingAssetPath); - prefabPath = Path.Combine(ProjectSetting.FindAddres(ProjectSettingAsset.IdentityAsset.PrefabTemplate).Path, prefabName); - } - else - { - prefabPath = Path.Combine(RM_CoreEditor.PrefabTemplatePath, prefabName); - } - - // Load the prefab from the specified path - GameObject prefab = AssetDatabase.LoadAssetAtPath(prefabPath); - - if (prefab != null) - { - // Create an instance of the prefab in the scene - GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab); - - // Register the creation in the undo system - Undo.RegisterCreatedObjectUndo(instance, "Create " + instance.name); - - // Select the newly created instance - Selection.activeObject = instance; - return instance; - } - else - { - Debug.LogError("Prefab not found at path: " + prefabPath); - return null; - } - } - public static void GameObjectInScene(string Name = "GameObject") where T : Component - { - GameObject instance = new GameObject(Name); - // Register the creation in the undo system - Undo.RegisterCreatedObjectUndo(instance, "Create " + instance.name); - instance.AddComponent(); - // Select the newly created instance - Selection.activeObject = instance; - } - public static T ScriptableObj(string path) where T : ScriptableObject - { - // Create an instance of the ScriptableObject - T asset = ScriptableObject.CreateInstance(); - - // Ensure the directory exists - string directory = System.IO.Path.GetDirectoryName(path); - if (!System.IO.Directory.Exists(directory)) - { - System.IO.Directory.CreateDirectory(directory); - } - - // Save the asset - AssetDatabase.CreateAsset(asset, path); - AssetDatabase.SaveAssets(); - - // Focus on the newly created asset in the Project window - EditorUtility.FocusProjectWindow(); - Selection.activeObject = asset; - - Debug.Log($"ScriptableObject of type {typeof(T).Name} created and saved at: {path}"); - - // Return the created asset - return asset; - } - } -} - diff --git a/Editor/Library/Utilities/CreateLibrary.cs b/Editor/Library/Utilities/CreateLibrary.cs new file mode 100644 index 00000000..e938f9c6 --- /dev/null +++ b/Editor/Library/Utilities/CreateLibrary.cs @@ -0,0 +1,45 @@ +using UnityEditor; +using UnityEngine; +using System.IO; + +namespace RealMethod.Editor +{ + public static class RM_Create + { + public static void GameObject(string Name = "GameObject") where T : Component + { + GameObject instance = new GameObject(Name); + // Register the creation in the undo system + Undo.RegisterCreatedObjectUndo(instance, "Create " + instance.name); + instance.AddComponent(); + // Select the newly created instance + Selection.activeObject = instance; + } + public static T Asset(string path) where T : PrimitiveAsset + { + // Create an instance of the PrimitiveAsset + T asset = ScriptableObject.CreateInstance(); + + // Ensure the directory exists + string directory = Path.GetDirectoryName(path); + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + // Save the asset + AssetDatabase.CreateAsset(asset, path); + AssetDatabase.SaveAssets(); + + // Focus on the newly created asset in the Project window + EditorUtility.FocusProjectWindow(); + Selection.activeObject = asset; + + Debug.Log($"PrimitiveAsset of type {typeof(T).Name} created and saved at: {path}"); + + // Return the created asset + return asset; + } + } +} + diff --git a/Editor/Library/Utilities/Create.cs.meta b/Editor/Library/Utilities/CreateLibrary.cs.meta similarity index 100% rename from Editor/Library/Utilities/Create.cs.meta rename to Editor/Library/Utilities/CreateLibrary.cs.meta diff --git a/Editor/Library/Utilities/MetaDataHandler.cs b/Editor/Library/Utilities/MetaDataLibrary.cs similarity index 90% rename from Editor/Library/Utilities/MetaDataHandler.cs rename to Editor/Library/Utilities/MetaDataLibrary.cs index b6fc635c..caf091b5 100644 --- a/Editor/Library/Utilities/MetaDataHandler.cs +++ b/Editor/Library/Utilities/MetaDataLibrary.cs @@ -9,7 +9,7 @@ public static class RM_MetaData { private static string GetMetaFilePath(string assetPath) => assetPath + ".meta"; - // 🔹 Automatically determines the mode (Text in Editor, Binary in Play Mode) + //Automatically determines the mode (Text in Editor, Binary in Play Mode) private static bool UseBinaryMode { get @@ -18,7 +18,7 @@ private static bool UseBinaryMode } } - // 🔹 Save metadata (Auto-Switch) + //Save metadata (Auto-Switch) public static void SaveCustomMetadata(string assetPath, string key, string value) { string metaFilePath = GetMetaFilePath(assetPath); @@ -35,7 +35,7 @@ public static void SaveCustomMetadata(string assetPath, string key, string value SaveTextMetadata(metaFilePath, key, value); } - // 🔹 Load metadata (Auto-Switch) + //Load metadata (Auto-Switch) public static string LoadCustomMetadata(string assetPath, string key) { string metaFilePath = GetMetaFilePath(assetPath); @@ -48,14 +48,14 @@ public static string LoadCustomMetadata(string assetPath, string key) return UseBinaryMode ? LoadBinaryMetadata(metaFilePath, key) : LoadTextMetadata(metaFilePath, key); } - // 🔹 Check if metadata exists + //Check if metadata exists public static bool HasMetadata(string assetPath, string key) { string metaFilePath = GetMetaFilePath(assetPath); return File.Exists(metaFilePath) && File.ReadAllText(metaFilePath).Contains($"{key}:"); } - // 🔹 Delete metadata entry + //Delete metadata entry public static void DeleteMetadata(string assetPath, string key) { string metaFilePath = GetMetaFilePath(assetPath); @@ -65,7 +65,7 @@ public static void DeleteMetadata(string assetPath, string key) File.WriteAllLines(metaFilePath, Array.FindAll(lines, line => !line.StartsWith($"{key}:"))); } - // 🔹 Save Text Metadata + //Save Text Metadata private static void SaveTextMetadata(string metaFilePath, string key, string value) { string[] lines = File.ReadAllLines(metaFilePath); @@ -85,7 +85,7 @@ private static void SaveTextMetadata(string metaFilePath, string key, string val else File.WriteAllLines(metaFilePath, lines); } - // 🔹 Load Text Metadata + //Load Text Metadata private static string LoadTextMetadata(string metaFilePath, string key) { foreach (string line in File.ReadAllLines(metaFilePath)) @@ -96,7 +96,7 @@ private static string LoadTextMetadata(string metaFilePath, string key) return null; } - // 🔹 Save Binary Metadata + //Save Binary Metadata private static void SaveBinaryMetadata(string metaFilePath, string key, string value) { using (BinaryWriter writer = new BinaryWriter(File.Open(metaFilePath, FileMode.Append))) @@ -106,7 +106,7 @@ private static void SaveBinaryMetadata(string metaFilePath, string key, string v } } - // 🔹 Load Binary Metadata + //Load Binary Metadata private static string LoadBinaryMetadata(string metaFilePath, string key) { using (BinaryReader reader = new BinaryReader(File.Open(metaFilePath, FileMode.Open))) diff --git a/Editor/Library/Utilities/MetaDataHandler.cs.meta b/Editor/Library/Utilities/MetaDataLibrary.cs.meta similarity index 100% rename from Editor/Library/Utilities/MetaDataHandler.cs.meta rename to Editor/Library/Utilities/MetaDataLibrary.cs.meta diff --git a/Editor/Library/Vendor/UnityEditorIcons.meta b/Editor/Library/Vendor/UnityEditorIcons.meta deleted file mode 100644 index 5a74db56..00000000 --- a/Editor/Library/Vendor/UnityEditorIcons.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b053aa00d882df041a089f1bd0dffd26 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Editor/Pattern/DataAssets.meta b/Editor/Pattern/DataAssets.meta deleted file mode 100644 index 9b782dc5..00000000 --- a/Editor/Pattern/DataAssets.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 8353593eea5c6884ea594f163d264236 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Editor/Pattern/Inspectors.meta b/Editor/Pattern/Inspectors.meta new file mode 100644 index 00000000..04fcdba6 --- /dev/null +++ b/Editor/Pattern/Inspectors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8e1de2e7481e79942ad4d69f21a3c713 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Pattern/Manager/CompositManagerCompWindow.cs b/Editor/Pattern/Inspectors/CompositManagerEditor.cs similarity index 95% rename from Editor/Pattern/Manager/CompositManagerCompWindow.cs rename to Editor/Pattern/Inspectors/CompositManagerEditor.cs index 7f44592c..6bcfc77a 100644 --- a/Editor/Pattern/Manager/CompositManagerCompWindow.cs +++ b/Editor/Pattern/Inspectors/CompositManagerEditor.cs @@ -1,10 +1,10 @@ using UnityEditor; using UnityEngine; -namespace RealMethod +namespace RealMethod.Editor { [CustomEditor(typeof(CompositManager), true)] - public class CompositManagerCompWindow : UnityEditor.Editor + public class CompositManagerEditor : UnityEditor.Editor { private CompositManager BaseComponent; diff --git a/Editor/Pattern/Manager/CompositManagerCompWindow.cs.meta b/Editor/Pattern/Inspectors/CompositManagerEditor.cs.meta similarity index 100% rename from Editor/Pattern/Manager/CompositManagerCompWindow.cs.meta rename to Editor/Pattern/Inspectors/CompositManagerEditor.cs.meta diff --git a/Editor/Pattern/Inspectors/DeveloperManagerEditor.cs b/Editor/Pattern/Inspectors/DeveloperManagerEditor.cs new file mode 100644 index 00000000..33a2b4aa --- /dev/null +++ b/Editor/Pattern/Inspectors/DeveloperManagerEditor.cs @@ -0,0 +1,39 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomEditor(typeof(DeveloperManager), true)] + public class DeveloperManagerEditor : UnityEditor.Editor + { + private DeveloperManager Comp; + private void OnEnable() + { + Comp = (DeveloperManager)target; + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.Space(); + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Open")) + { + Comp.Open(); + } + if (GUILayout.Button("Close")) + { + Comp.Close(); + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.LabelField($"Status: {IsOpen()}"); + } + + + private string IsOpen() + { + return Comp.IsOpen ? "Open" : "Close"; + } + } +} \ No newline at end of file diff --git a/Editor/Pattern/Inspectors/DeveloperManagerEditor.cs.meta b/Editor/Pattern/Inspectors/DeveloperManagerEditor.cs.meta new file mode 100644 index 00000000..f86534d1 --- /dev/null +++ b/Editor/Pattern/Inspectors/DeveloperManagerEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0d75ebb150273ea4c8884e5b7438b491 \ No newline at end of file diff --git a/Editor/Pattern/DataAssets/FactoryEditor.cs b/Editor/Pattern/Inspectors/FactoryAssetEditor.cs similarity index 96% rename from Editor/Pattern/DataAssets/FactoryEditor.cs rename to Editor/Pattern/Inspectors/FactoryAssetEditor.cs index 5d29cdaa..ac749a84 100644 --- a/Editor/Pattern/DataAssets/FactoryEditor.cs +++ b/Editor/Pattern/Inspectors/FactoryAssetEditor.cs @@ -5,7 +5,7 @@ namespace RealMethod.Editor { [CustomEditor(typeof(FactoryAsset), true)] - public class FactoryEditor : UnityEditor.Editor + public class FactoryAssetEditor : UnityEditor.Editor { private FactoryAsset TargetAsset; private string[] actionNames; diff --git a/Editor/Pattern/DataAssets/FactoryEditor.cs.meta b/Editor/Pattern/Inspectors/FactoryAssetEditor.cs.meta similarity index 100% rename from Editor/Pattern/DataAssets/FactoryEditor.cs.meta rename to Editor/Pattern/Inspectors/FactoryAssetEditor.cs.meta diff --git a/Editor/Pattern/DataAssets/ResourcEditor.cs b/Editor/Pattern/Inspectors/ResourcAssetEditor.cs similarity index 97% rename from Editor/Pattern/DataAssets/ResourcEditor.cs rename to Editor/Pattern/Inspectors/ResourcAssetEditor.cs index c578f720..55b8d1ad 100644 --- a/Editor/Pattern/DataAssets/ResourcEditor.cs +++ b/Editor/Pattern/Inspectors/ResourcAssetEditor.cs @@ -4,7 +4,7 @@ namespace RealMethod.Editor { [CustomEditor(typeof(ResourcAsset<>), true)] - public class ResourcEditor : UnityEditor.Editor + public class ResourcAssetEditor : UnityEditor.Editor { private object baseComponent; private System.Type targetType; diff --git a/Editor/Pattern/DataAssets/ResourcEditor.cs.meta b/Editor/Pattern/Inspectors/ResourcAssetEditor.cs.meta similarity index 100% rename from Editor/Pattern/DataAssets/ResourcEditor.cs.meta rename to Editor/Pattern/Inspectors/ResourcAssetEditor.cs.meta diff --git a/Editor/Pattern/Inspectors/SaveManagerEditor.cs b/Editor/Pattern/Inspectors/SaveManagerEditor.cs new file mode 100644 index 00000000..bf3653c3 --- /dev/null +++ b/Editor/Pattern/Inspectors/SaveManagerEditor.cs @@ -0,0 +1,43 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomEditor(typeof(SaveManager), true)] + public class SaveManagerEditor : UnityEditor.Editor + { + private SaveManager Component; + private bool IsShowLoadedFile = true; + + private void OnEnable() + { + Component = (SaveManager)target; + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + if (!Component.IsInSingleFile) + { + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + IsShowLoadedFile = EditorGUILayout.Foldout(IsShowLoadedFile, "Files", true, EditorStyles.foldoutHeader); + if (IsShowLoadedFile) + { + IFile[] files = Component.GetAllFiles(); + if (Component != null) + { + for (int i = 0; i < files.Length; i++) + { + EditorGUILayout.LabelField($"{i}.[{files[i].FileName}]: {files[i].Self.GetType()}"); + } + } + EditorGUILayout.Space(); + EditorGUILayout.LabelField($"Total: {files.Length}"); + } + } + } + + + } + +} \ No newline at end of file diff --git a/Editor/Pattern/Manager/DataManagerCompWindow.cs.meta b/Editor/Pattern/Inspectors/SaveManagerEditor.cs.meta similarity index 100% rename from Editor/Pattern/Manager/DataManagerCompWindow.cs.meta rename to Editor/Pattern/Inspectors/SaveManagerEditor.cs.meta diff --git a/Editor/Pattern/Inspectors/TaskManagerEditor.cs b/Editor/Pattern/Inspectors/TaskManagerEditor.cs new file mode 100644 index 00000000..9595a7c8 --- /dev/null +++ b/Editor/Pattern/Inspectors/TaskManagerEditor.cs @@ -0,0 +1,53 @@ +using System.Collections; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomEditor(typeof(TaskManager), true)] + public class TaskManagerEditor : UnityEditor.Editor + { + private TaskManager BaseComponent; + FieldInfo tasksField; + + private void OnEnable() + { + BaseComponent = (TaskManager)target; + tasksField = target.GetType().GetField( + "Tasks", + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public + + ); + + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + if (BaseComponent != null) + { + if (BaseComponent.Count > 0) + { + IList tasks = tasksField.GetValue(target) as IList; + for (int i = 0; i < tasks.Count; i++) + { + object task = tasks[i]; + if (task == null) + continue; + EditorGUILayout.LabelField($"{i}.{task.GetType().Name}", EditorStyles.boldLabel); + } + EditorGUILayout.Space(); + EditorGUILayout.LabelField($"Total: {BaseComponent.Count}"); + } + + } + + + } + } + + + +} \ No newline at end of file diff --git a/Editor/Pattern/Manager/TaskManagerCompWindow.cs.meta b/Editor/Pattern/Inspectors/TaskManagerEditor.cs.meta similarity index 100% rename from Editor/Pattern/Manager/TaskManagerCompWindow.cs.meta rename to Editor/Pattern/Inspectors/TaskManagerEditor.cs.meta diff --git a/Editor/Pattern/Manager.meta b/Editor/Pattern/Manager.meta deleted file mode 100644 index f5bedd28..00000000 --- a/Editor/Pattern/Manager.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 9536b0ab30e69e9409f6c9e050b38995 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Editor/Pattern/Manager/DataManagerCompWindow.cs b/Editor/Pattern/Manager/DataManagerCompWindow.cs deleted file mode 100644 index 28709107..00000000 --- a/Editor/Pattern/Manager/DataManagerCompWindow.cs +++ /dev/null @@ -1,39 +0,0 @@ -using UnityEditor; - -namespace RealMethod -{ - [CustomEditor(typeof(DataManager), true)] - public class DataManagerCompWindow : UnityEditor.Editor - { - private DataManager BaseComponent; - - private void OnEnable() - { - BaseComponent = (DataManager)target; - } - - public override void OnInspectorGUI() - { - base.OnInspectorGUI(); - EditorGUILayout.Space(); - EditorGUILayout.LabelField(" ----------------- History ----------------- "); - if (BaseComponent != null) - { - if (BaseComponent.DataLog != null && BaseComponent.DataLog.Length > 0) - { - foreach (var item in BaseComponent.DataLog) - { - if (item != string.Empty) - { - EditorGUILayout.LabelField(item); - } - } - } - EditorGUILayout.Space(); - EditorGUILayout.LabelField($"TotalLog: {BaseComponent.Logindex}"); - } - - - } - } -} \ No newline at end of file diff --git a/Editor/Pattern/Manager/TaskManagerCompWindow.cs b/Editor/Pattern/Manager/TaskManagerCompWindow.cs deleted file mode 100644 index cd8e5427..00000000 --- a/Editor/Pattern/Manager/TaskManagerCompWindow.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using UnityEditor; - -namespace RealMethod -{ - [CustomEditor(typeof(TaskManager), true)] - public class TaskManagerCompWindow : UnityEditor.Editor - { - private TaskManager BaseComponent; - - private void OnEnable() - { - BaseComponent = (TaskManager)target; - } - - public override void OnInspectorGUI() - { - base.OnInspectorGUI(); - EditorGUILayout.Space(); - EditorGUILayout.LabelField(" ----------------- Tasks ----------------- "); - if (BaseComponent != null) - { - if (BaseComponent.Count > 0) - { - ITask[] tasks = BaseComponent.GetAllTasks(); - foreach (var task in tasks) - { - EditorGUILayout.LabelField($"{task}"); - } - EditorGUILayout.Space(); - EditorGUILayout.LabelField($"Total: {tasks.Length}"); - } - - } - - - } - } - - - [CustomEditor(typeof(TaskAsset), true)] - public class TaskAssetCompWindow : UnityEditor.Editor - { - private TaskAsset BaseAsset; - - private void OnEnable() - { - BaseAsset = (TaskAsset)target; - } - - public override void OnInspectorGUI() - { - base.OnInspectorGUI(); - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Debug.... "); - if (BaseAsset != null) - { - EditorGUILayout.LabelField($"Status: {CheckStatus(BaseAsset)}"); - if (BaseAsset is TaskBehaviour provider) - { - if (provider.IsInfinit) - { - EditorGUILayout.LabelField($"Time: Infinit"); - } - else - { - EditorGUILayout.LabelField($"Time: {Math.Round(provider.ElapsedTime, 2)} ({Math.Round((1 - provider.NormalizedTime) * 100, 2)}%)"); - } - } - - } - } - - - private string CheckStatus(TaskAsset task) - { - return task.IsEnable ? "Enable" : "Disable"; - } - } - - - - -} \ No newline at end of file diff --git a/Editor/Pattern/MenuItem.meta b/Editor/Pattern/MenuItem.meta new file mode 100644 index 00000000..b13b520d --- /dev/null +++ b/Editor/Pattern/MenuItem.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2267a5fc0c3695047931a476d844fa6d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Pattern/MenuItem/PatternMenu.cs b/Editor/Pattern/MenuItem/PatternMenu.cs new file mode 100644 index 00000000..8402b5ab --- /dev/null +++ b/Editor/Pattern/MenuItem/PatternMenu.cs @@ -0,0 +1,149 @@ + +using UnityEditor; + +namespace RealMethod.Editor +{ + class PatternMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Pattern; + + + ////////////// Scripts \\\\\\\\\\\\ + // Managers + [MenuItem(RM_Editor.ScriptMenuItemPath + "Manager/AudioManager", false, RM_Editor.MenuOrder.Manager_Body)] + public static void CreateAudioManager() + { + RM_Editor.CreateScriptTemplate("AudioManager", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Manager/CompositManager", false, RM_Editor.MenuOrder.Manager_Body)] + public static void CreateCompositManager() + { + RM_Editor.CreateScriptTemplate("CompositManager", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Manager/SaveManager", false, RM_Editor.MenuOrder.Manager_Body)] + public static void CreateSaveManager() + { + RM_Editor.CreateScriptTemplate("SaveManager", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Manager/GizmoManager", false, RM_Editor.MenuOrder.Manager_Body)] + public static void CreateGizmoManager() + { + RM_Editor.CreateScriptTemplate("GizmoManager", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Manager/UIManager", false, RM_Editor.MenuOrder.Manager_Body)] + public static void CreateUIManager() + { + RM_Editor.CreateScriptTemplate("UIManager", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Manager/MixerManager", false, RM_Editor.MenuOrder.Manager_Body)] + public static void CreateMixerManager() + { + RM_Editor.CreateScriptTemplate("MixerManager", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Manager/HapticManager", false, RM_Editor.MenuOrder.Manager_Body)] + public static void CreateHapticManager() + { + RM_Editor.CreateScriptTemplate("HapticManager", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Manager/TickManager", false, RM_Editor.MenuOrder.Manager_Body)] + public static void CreateTickManager() + { + RM_Editor.CreateScriptTemplate("TickManager", MenuLayer); + } + + // Services + [MenuItem(RM_Editor.ScriptMenuItemPath + "Service/StateService", false, RM_Editor.MenuOrder.Service_Body)] + public static void CreateStateService() + { + RM_Editor.CreateScriptTemplate("StateService", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Service/RuleService", false, RM_Editor.MenuOrder.Service_Body)] + public static void CreateRuleService() + { + RM_Editor.CreateScriptTemplate("RuleService", MenuLayer); + } + + // Assets + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Data/Table", false, RM_Editor.MenuOrder.DataAsset_Body)] + public static void CreateTableAsset() + { + RM_Editor.CreateScriptTemplate("TableAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Data/Task", false, RM_Editor.MenuOrder.DataAsset_Body)] + public static void CreateTaskAsset() + { + RM_Editor.CreateScriptTemplate("TaskAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Config/Item", false, RM_Editor.MenuOrder.ConfigAsset_Body)] + public static void CreateItemConfig() + { + RM_Editor.CreateScriptTemplate("ItemConfig", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Config/Haptic", false, RM_Editor.MenuOrder.ConfigAsset_Body)] + public static void CreateHapticConfig() + { + RM_Editor.CreateScriptTemplate("HapticConfig", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/File/EmptyFileAsset", false, RM_Editor.MenuOrder.UniqueAsset_Body)] + public static void CreateFileAsset() + { + RM_Editor.CreateScriptTemplate("FileAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/File/Save", false, RM_Editor.MenuOrder.UniqueAsset_Body)] + public static void CreateSaveFile() + { + RM_Editor.CreateScriptTemplate("SaveFile", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/File/GameSetting", false, RM_Editor.MenuOrder.UniqueAsset_Body)] + public static void CreateGameSettingFile() + { + RM_Editor.CreateScriptTemplate("GameSettingFile", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Unique/SharedRootAsset", false, RM_Editor.MenuOrder.UniqueAsset_Body)] + public static void CreateSharedRootAsset() + { + RM_Editor.CreateScriptTemplate("SharedRootAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Asset/Unique/PoolAsset", false, RM_Editor.MenuOrder.UniqueAsset_Body)] + public static void CreatePoolAsset() + { + RM_Editor.CreateScriptTemplate("PoolAsset", MenuLayer); + } + + + // UI + [MenuItem(RM_Editor.ScriptMenuItemPath + "Method/UI/Widget", false, RM_Editor.MenuOrder.Method)] + public static void CreateWidget() + { + RM_Editor.CreateScriptTemplate("Widget", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Method/UI/WidgetToolkit", false, RM_Editor.MenuOrder.Method)] + public static void CreateWidgetToolkit() + { + RM_Editor.CreateScriptTemplate("WidgetToolkit", MenuLayer); + } + + // Command + [MenuItem(RM_Editor.ScriptMenuItemPath + "Method/Command", false, RM_Editor.MenuOrder.Method)] + public static void CreateCommand() + { + RM_Editor.CreateScriptTemplate("Command", MenuLayer); + } + + // Trigger + [MenuItem(RM_Editor.ScriptMenuItemPath + "Method/Trigger/Trigger3D", false, RM_Editor.MenuOrder.Method)] + public static void CreateTrigger3D() + { + RM_Editor.CreateScriptTemplate("Trigger3D", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Method/Trigger/Trigger2D", false, RM_Editor.MenuOrder.Method)] + public static void CreateTrigger2D() + { + RM_Editor.CreateScriptTemplate("Trigger2D", MenuLayer); + } + + + + + } +} \ No newline at end of file diff --git a/Editor/Pattern/MenuItem/PatternMenu.cs.meta b/Editor/Pattern/MenuItem/PatternMenu.cs.meta new file mode 100644 index 00000000..a00391b5 --- /dev/null +++ b/Editor/Pattern/MenuItem/PatternMenu.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b0e82e6f28f685a4481da01a36af2169 \ No newline at end of file diff --git a/Editor/Pattern/Scripts.meta b/Editor/Pattern/Scripts.meta new file mode 100644 index 00000000..e2c4f1f1 --- /dev/null +++ b/Editor/Pattern/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f5cd3bfd4d154e541a2b99bc9161a185 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Pattern/Scripts/AssetProcess.cs b/Editor/Pattern/Scripts/AssetProcess.cs new file mode 100644 index 00000000..85393ee9 --- /dev/null +++ b/Editor/Pattern/Scripts/AssetProcess.cs @@ -0,0 +1,67 @@ +using UnityEngine; +using UnityEditor; + + +namespace RealMethod.Editor +{ + public abstract class AssetProcess + { + public AssetProcess() + { + Initialized(); + } + + protected abstract void Initialized(); + public abstract void OnAssetImported(string AssetPath); + public abstract void OnAssetDeleted(string AssetPath); + public abstract void OnAssetMoved(string AssetPath, string FromPath); + public abstract void OnAssetClick(string AssetPath, Event e); + protected abstract string GetIconPath(); + } + public abstract class AssetProcess : AssetProcess where T : Object + { + protected abstract void DoubleClick(T asset); + + public override void OnAssetImported(string AssetPath) + { + T loadedAsset; + if (TryLoadAsset(AssetPath, out loadedAsset)) + { + if (loadedAsset.GetType() == typeof(J)) + { + // Load your icon from Resources (adjust the path as needed) + Texture2D icon = Resources.Load(GetIconPath()); + if (icon != null) + { + EditorGUIUtility.SetIconForObject(loadedAsset, icon); + } + else + { + Debug.LogWarning("Custom icon not found. Please ensure the path and file are correct."); + } + } + } + else + { + Debug.LogWarning("Cant Load "); + } + } + public override void OnAssetClick(string AssetPath, Event e) + { + var asset = AssetDatabase.LoadAssetAtPath(AssetPath); + + if (asset != null) + { + DoubleClick(asset); + e.Use(); // Consume the event + } + } + + protected bool TryLoadAsset(string assetPath, out K asset) where K : Object + { + asset = AssetDatabase.LoadAssetAtPath(assetPath); + return asset != null; + } + } + +} \ No newline at end of file diff --git a/Editor/Pattern/Scripts/AssetProcess.cs.meta b/Editor/Pattern/Scripts/AssetProcess.cs.meta new file mode 100644 index 00000000..0dc6766b --- /dev/null +++ b/Editor/Pattern/Scripts/AssetProcess.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 060b9dbad7dba424b9f55475deb3b39d \ No newline at end of file diff --git a/Editor/Pattern/Windows.meta b/Editor/Pattern/Windows.meta new file mode 100644 index 00000000..66b6dc52 --- /dev/null +++ b/Editor/Pattern/Windows.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 77cc5644be719ee4b8d874ef041e74a5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Pattern/DataAssets/TableViewerWindow.cs b/Editor/Pattern/Windows/TableViewerWindow.cs similarity index 100% rename from Editor/Pattern/DataAssets/TableViewerWindow.cs rename to Editor/Pattern/Windows/TableViewerWindow.cs diff --git a/Editor/Pattern/DataAssets/TableViewerWindow.cs.meta b/Editor/Pattern/Windows/TableViewerWindow.cs.meta similarity index 100% rename from Editor/Pattern/DataAssets/TableViewerWindow.cs.meta rename to Editor/Pattern/Windows/TableViewerWindow.cs.meta diff --git a/Editor/ReadySet/Content/RealMethod_Prefab.cs b/Editor/ReadySet/Content/RealMethod_Prefab.cs index 5227ed62..54cfc8b8 100644 --- a/Editor/ReadySet/Content/RealMethod_Prefab.cs +++ b/Editor/ReadySet/Content/RealMethod_Prefab.cs @@ -1,7 +1,7 @@ using RealMethod.Editor; using UnityEditor; -namespace RealMethod +namespace RealMethod.Editor { class RealMethodPrefab { diff --git a/Editor/ReadySet/Content/RealMethod_ScriptTemplate.cs b/Editor/ReadySet/Content/RealMethod_ScriptTemplate.cs deleted file mode 100644 index 5c017994..00000000 --- a/Editor/ReadySet/Content/RealMethod_ScriptTemplate.cs +++ /dev/null @@ -1,222 +0,0 @@ -using UnityEditor; - -namespace RealMethod.Editor -{ - class RealMethodScriptTemplate - { - // Essential - [MenuItem("Assets/Create/Scripting/RealMethod/Essential/Game", false, 80)] - public static void CreateGameClass() - { - string Path = RM_Create.Script("GameTemplate.txt", "MyGame.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Essential/World", false, 80)] - public static void CreateWorld() - { - string Path = RM_Create.Script("WorldTemplate.txt", "MyWorld.cs"); - } - - // Managers - [MenuItem("Assets/Create/Scripting/RealMethod/Manager/BaseManager", false, 80)] - public static void CreateManager() - { - string Path = RM_Create.Script("ManagerTemplate.txt", "MyManager.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Manager/AudioManager", false, 80)] - public static void CreateAudioManager() - { - string Path = RM_Create.Script("AudioManagerTemplater.txt", "MyAudioManager.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Manager/CompositManager", false, 80)] - public static void CreateCompositManager() - { - string Path = RM_Create.Script("CompositManagerTemplate.txt", "MyCompositManager.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Manager/DataManager", false, 80)] - public static void CreateDataManager() - { - string Path = RM_Create.Script("DataManagerTemplate.txt", "MyDataManager.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Manager/GizmoManager", false, 80)] - public static void CreateGizmoManager() - { - string Path = RM_Create.Script("GizmoManagerTemplate.txt", "MyGizmoManager.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Manager/UIManager", false, 80)] - public static void CreateUIManager() - { - string Path = RM_Create.Script("UIManagerTemplate.txt", "MyUIManager.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Manager/MixerManager", false, 80)] - public static void CreateMixerManager() - { - string Path = RM_Create.Script("MixerManagerTemplate.txt", "MyMixerManager.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Manager/HapticManager", false, 80)] - public static void CreateHapticManager() - { - string Path = RM_Create.Script("HapticManagerTemplate.txt", "MyHapticManager.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Manager/TickManager", false, 80)] - public static void CreateTickManager() - { - string Path = RM_Create.Script("TickManagerTemplate.txt", "MyTickManager.cs"); - } - - - // Service - [MenuItem("Assets/Create/Scripting/RealMethod/Service/BaseService", false, 80)] - public static void CreateService() - { - string Path = RM_Create.Script("ServiceTemplate.txt", "MyServicec.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Service/GameService", false, 80)] - public static void CreateGameServiceClass() - { - string Path = RM_Create.Script("GameServiceTemplate.txt", "MyGameService.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Service/StateService", false, 80)] - public static void CreateStateService() - { - string Path = RM_Create.Script("StateServiceTemplate.txt", "MyStateService.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Service/RuleService", false, 80)] - public static void CreateRuleService() - { - string Path = RM_Create.Script("RuleServiceTemplate.txt", "MyRuleService.cs"); - } - - - - // Assets - // // Data - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Data/BaseData", false, 80)] - public static void CreateDataAsset() - { - string Path = RM_Create.Script("DataAssetTemplate.txt", "MyDataAsset.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Data/ItemAsset", false, 80)] - public static void CreateItemAsset() - { - string Path = RM_Create.Script("ItemAssetTemplate.txt", "MyItemAsset.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Data/TableAsset", false, 80)] - public static void CreateTableAsset() - { - string Path = RM_Create.Script("TableTemplate.txt", "MyTableAsset.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Data/Task", false, 80)] - public static void CreateTaskAsset() - { - string Path = RM_Create.Script("TaskAssetTemplate.txt", "MyTaskAsset.cs"); - } - // // Config - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Config/BaseConfig", false, 80)] - public static void CreateConfigAsset() - { - string Path = RM_Create.Script("ConfigAssetTemplate.txt", "MyConfigAsset.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Config/ItemConfig", false, 80)] - public static void CreateItemConfig() - { - string Path = RM_Create.Script("ItemConfigTemplate.txt", "MyItemConfig.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Config/GameConfig", false, 80)] - public static void CreateGameConfig() - { - string Path = RM_Create.Script("GameConfigTemplate.txt", "MyGameConfig.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Config/HapticConfig", false, 80)] - public static void CreateHapticConfig() - { - string Path = RM_Create.Script("HapticConfigTemplate.txt", "MyHaptic.cs"); - } - // // Files - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/File/BaseFile", false, 80)] - public static void CreateFileAsset() - { - string Path = RM_Create.Script("FileAssetTemplate.txt", "MyFileAsset.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/File/SaveFile", false, 80)] - public static void CreateSaveFile() - { - string Path = RM_Create.Script("SaveFileTemplate.txt", "MySaveFile.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/File/GameSetting", false, 80)] - public static void CreateGameSettingFile() - { - string Path = RM_Create.Script("GameSettingFileTemplate.txt", "GameSettingFile.cs"); - } - // // Unique - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Unique/BaseUnique", false, 80)] - public static void CreateUniqueAsset() - { - string Path = RM_Create.Script("UniqueAssetTemplate.txt", "MyFileAsset.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Unique/SharedRootAsset", false, 80)] - public static void CreateSharedRootAsset() - { - string Path = RM_Create.Script("SharedRootAssetTemplate.txt", "MySharedRootAsset.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Asset/Unique/PoolAsset", false, 80)] - public static void CreatePoolAsset() - { - string Path = RM_Create.Script("PoolAssetTemplate.txt", "MyPoolAsset.cs"); - } - - // General - // // UI - [MenuItem("Assets/Create/Scripting/RealMethod/General/UI/Widget", false, 80)] - public static void CreateWidget() - { - string Path = RM_Create.Script("WidgetTemplate.txt", "MyWidget.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/General/UI/WidgetToolkit", false, 80)] - public static void CreateWidgetToolkit() - { - string Path = RM_Create.Script("WidgetToolkitTemplate.txt", "MyWidgetToolkit.cs"); - } - // // Command - [MenuItem("Assets/Create/Scripting/RealMethod/General/Command", false, 80)] - public static void CreateCommand() - { - string Path = RM_Create.Script("CommandTemplate.txt", "MyCommand.cs"); - } - // // Trigger - [MenuItem("Assets/Create/Scripting/RealMethod/General/Trigger/Trigger3D", false, 80)] - public static void CreateTrigger3D() - { - string Path = RM_Create.Script("Trigger3DTemplate.txt", "MyTrigger.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/General/Trigger/Trigger2D", false, 80)] - public static void CreateTrigger2D() - { - string Path = RM_Create.Script("Trigger2DTemplate.txt", "MyTrigger.cs"); - } - - - // Editor - [MenuItem("Assets/Create/Scripting/RealMethod/Editor/SettingSection", false, 80)] - public static void CreateSettingSection() - { - string Path = RM_Create.Script("SettingSectionTemplate.txt", "MySection.cs"); - } - - - - - - - - - - - - - - - - - - } -} \ No newline at end of file diff --git a/Editor/ReadySet/Content/RealMethod_ScriptTemplate.cs.meta b/Editor/ReadySet/Content/RealMethod_ScriptTemplate.cs.meta deleted file mode 100644 index 66206723..00000000 --- a/Editor/ReadySet/Content/RealMethod_ScriptTemplate.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: a58e933f91efb7f4192f2e164c491a85 \ No newline at end of file diff --git a/Editor/ReadySet/Content/RealMethod_UnityAsset.cs b/Editor/ReadySet/Content/RealMethod_UnityAsset.cs index 48c1cdee..635a67f9 100644 --- a/Editor/ReadySet/Content/RealMethod_UnityAsset.cs +++ b/Editor/ReadySet/Content/RealMethod_UnityAsset.cs @@ -2,7 +2,7 @@ namespace RealMethod.Editor { - public class Table_UnityAsset : AssetHandeler + public class Table_UnityAsset : AssetProcess { protected override void Initialized() { @@ -26,7 +26,7 @@ protected override void DoubleClick(TableAsset asset) TableViewerWindow.OpenWindow(asset); } } - public class WorldScene_UnityAsset : AssetHandeler + public class WorldAsset_UnityAsset : AssetProcess { protected override void Initialized() { @@ -44,12 +44,12 @@ protected override string GetIconPath() { return "Icons/Core/WorldSceneAsset"; } - protected override void DoubleClick(WorldSceneConfig asset) + protected override void DoubleClick(WorldAsset asset) { asset.OnAssetClick(); } } - public class Game_UnityAsset : AssetHandeler + public class Game_UnityAsset : AssetProcess { protected override void Initialized() { @@ -69,7 +69,7 @@ protected override string GetIconPath() } protected override void DoubleClick(MonoScript asset) { - + } } diff --git a/Editor/ReadySet/Content/UnityAsset_Postprocessor.cs b/Editor/ReadySet/Content/UnityAsset_Postprocessor.cs new file mode 100644 index 00000000..173e2a34 --- /dev/null +++ b/Editor/ReadySet/Content/UnityAsset_Postprocessor.cs @@ -0,0 +1,58 @@ +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + public class UnityAsset_Postprocessor : AssetPostprocessor + { + private static AssetProcess[] AssetList = new AssetProcess[5] + { + new WorldAsset_UnityAsset(), + new Table_UnityAsset(), + new PCGResource_UnityAsset(), + new PCGGeneration_UnityAsset(), + new PCGCash_UnityAsset() + }; + + [InitializeOnLoadMethod] + private static void OnDoubleClickScriptableObject() + { + EditorApplication.projectWindowItemOnGUI += (guid, rect) => + { + Event e = Event.current; + if (e.type == EventType.MouseDown && e.clickCount == 2) + { + string assetPath = AssetDatabase.GUIDToAssetPath(guid); + foreach (var asset in AssetList) + { + asset.OnAssetClick(assetPath, e); + } + } + }; + } + + // private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) + // { + // if (AssetList == null) + // { + // return; + // } + + // foreach (var asset in AssetList) + // { + // foreach (string assetPath in importedAssets) + // { + // asset.OnAssetImported(assetPath); + // } + // foreach (string assetPath in deletedAssets) + // { + // asset.OnAssetDeleted(assetPath); + // } + // for (int i = 0; i < movedAssets.Length; i++) + // { + // asset.OnAssetMoved(movedAssets[i], movedFromAssetPaths[i]); + // } + // } + // } + } +} \ No newline at end of file diff --git a/Editor/Core/ProjectSetting/UnityAsset_Postprocessor.cs.meta b/Editor/ReadySet/Content/UnityAsset_Postprocessor.cs.meta similarity index 100% rename from Editor/Core/ProjectSetting/UnityAsset_Postprocessor.cs.meta rename to Editor/ReadySet/Content/UnityAsset_Postprocessor.cs.meta diff --git a/Editor/ReadySet/Inspectors.meta b/Editor/ReadySet/Inspectors.meta new file mode 100644 index 00000000..232a6b04 --- /dev/null +++ b/Editor/ReadySet/Inspectors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dfdfee6ded1444748b9cf7cbeaa31b5d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ReadySet/Inspectors/MotionAssetEditor.cs b/Editor/ReadySet/Inspectors/MotionAssetEditor.cs new file mode 100644 index 00000000..eb9dfb69 --- /dev/null +++ b/Editor/ReadySet/Inspectors/MotionAssetEditor.cs @@ -0,0 +1,46 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + [CustomEditor(typeof(MotionAsset), true)] + public class TaskAssetCompWindow : UnityEditor.Editor + { + private MotionAsset BaseAsset; + + private void OnEnable() + { + BaseAsset = (MotionAsset)target; + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + EditorGUILayout.LabelField("Debug.... "); + if (BaseAsset != null) + { + EditorGUILayout.LabelField($"Status: {CheckStatus(BaseAsset)}"); + if (BaseAsset is IHandleBehaviourAction provider) + { + if (provider.IsInfinit) + { + EditorGUILayout.LabelField($"Time: Infinit"); + } + else + { + EditorGUILayout.LabelField($"Time: {Math.Round(provider.ElapsedTime, 2)} ({Math.Round((1 - provider.NormalizedTime) * 100, 2)}%)"); + } + } + + } + } + + + private string CheckStatus(MotionAsset task) + { + return task.IsEnable ? "Enable" : "Disable"; + } + } +} \ No newline at end of file diff --git a/Editor/ReadySet/Inspectors/MotionAssetEditor.cs.meta b/Editor/ReadySet/Inspectors/MotionAssetEditor.cs.meta new file mode 100644 index 00000000..5043f2e5 --- /dev/null +++ b/Editor/ReadySet/Inspectors/MotionAssetEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3cd743d5832d4f94a943b7e8e19a2042 \ No newline at end of file diff --git a/Editor/ReadySet/Tools/AnimatorScriptGenerator.cs b/Editor/ReadySet/Tools/AnimatorScriptGenerator.cs index b5d512fc..5c03c5c2 100644 --- a/Editor/ReadySet/Tools/AnimatorScriptGenerator.cs +++ b/Editor/ReadySet/Tools/AnimatorScriptGenerator.cs @@ -14,9 +14,9 @@ public class AnimatorScriptGenerator public static void GenerateScriptsFromAnimators() { ProjectSettingAsset TargetStorage; - if (ProjectSettingWindow.GetSettingStorage(out TargetStorage)) + if (RM_Editor.TryGetSettingAsset(out TargetStorage)) { - outputFolder = TargetStorage.FindAddres(ProjectSettingAsset.IdentityAsset.AnimatorParam).Path; + outputFolder = TargetStorage.GetFolderPathByType(ProjectSettingAsset.AssetFormat.Script) + "/General/AnimatorParam"; } else { diff --git a/Editor/ReadySet/Tools/ClassViewerWindow.cs b/Editor/ReadySet/Tools/ClassViewerWindow.cs new file mode 100644 index 00000000..f1cc3d76 --- /dev/null +++ b/Editor/ReadySet/Tools/ClassViewerWindow.cs @@ -0,0 +1,635 @@ +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Reflection; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + public class ClassViewerWindow : EditorWindow + { + private class FieldModule + { + private ClassViewerWindow MyOwner; + private MonoScript MyScript = null; + private List MyChilds = new List(); + private string MyName = string.Empty; + + + public string Title + { + get + { + if (MyScript != null) + { + Type targetclass = MyScript.GetClass(); + if (targetclass != null) + { + return MyScript.GetClass().Name; + } + else + { + return MyScript.name; + } + } + else + { + return MyName; + } + } + } + public bool HasFile => MyScript != null; + public MonoScript ScriptFile => MyScript; + public bool IsExpand { get; private set; } = false; + + + public FieldModule(ClassViewerWindow owner, string Name) + { + MyOwner = owner; + MyName = Name; + } + public FieldModule(ClassViewerWindow owner, MonoScript script) + { + MyOwner = owner; + MyScript = script; + } + + + public void Draw() + { + if (MyScript != null) + { + if (MyScript.GetClass() == null) + return; + } + + EditorGUILayout.BeginHorizontal(); + DrawField(); + EditorGUILayout.EndHorizontal(); + if (IsExpand) + { + EditorGUI.indentLevel++; + foreach (var child in MyChilds) + { + child.Draw(); + } + EditorGUI.indentLevel--; + } + } + public void AddChild(FieldModule ChildModule) + { + if (ChildModule == null) + { + Print("ChildModule is not valid!"); + return; + } + MyChilds.Add(ChildModule); + } + public void AddChild(MonoScript File) + { + Type NewType = File.GetClass(); + if (NewType == null || NewType.Namespace == null) + { + Print($"MonoScript does't have have any 'MainClass'or'NameSpace' for Child[{File.name}]"); + return; + } + + FieldModule NewModule = new FieldModule(MyOwner, File); + FieldModule ParentField = TraverseHierarchy(File.GetClass(), true); + + if (ParentField.TryFindField(NewModule.Title, out FieldModule result)) + { + if (!result.HasFile) + { + result.SetFileScript(File); + } + } + else + { + ParentField.AddChild(NewModule); + } + + } + public void Expand() + { + IsExpand = true; + for (int i = 2; i < MyChilds.Count; i++) + { + MyChilds[i].SortChild(); + } + } + + + private void DrawField() + { + Color old = GUI.color; + if (!HasFile) + { + GUI.color = new Color(0.9f, 0.9f, 0.9f); + } + + // Write Name as Label or Foldout + if (MyChilds.Count == 0) + { + EditorGUILayout.LabelField(Title, GUILayout.Width(300)); + IsExpand = false; + } + else + { + IsExpand = EditorGUILayout.Foldout(IsExpand, Title, true); + } + + // Add Button + if (MyScript) + { + if (GUILayout.Button("INFO ", EditorStyles.linkLabel)) + { + MyOwner.SelectedScript = MyScript; + } + if (MyScript != null) + { + if (GUILayout.Button("OpenFile ", EditorStyles.linkLabel)) + { + AssetDatabase.OpenAsset(MyScript); + } + } + } + GUI.color = old; + } + private FieldModule TraverseHierarchy(Type Target, bool ReturnParent = false) + { + FieldModule ParentField = null; + Type ParentChildType = Target.BaseType; + if (ParentChildType != null) + { + if (ParentChildType.Namespace == Target.Namespace) + { + //Recursive + ParentField = TraverseHierarchy(ParentChildType); + } + } + if (ParentField == null) + { + ParentField = GetOrCreateField(Target.Namespace, true); + if (Target.IsInterface) + { + ParentField = ParentField.GetOrCreateField(""); + } + if (Target.IsValueType && !Target.IsEnum) + { + ParentField = ParentField.GetOrCreateField(""); + } + } + return ReturnParent ? ParentField : ParentField.GetOrCreateField(Target.Name); + } + private void SetFileScript(MonoScript File) + { + MyScript = File; + } + private FieldModule GetOrCreateField(string title, bool IsNameSpace = false) + { + FieldModule Result = FindField(title); + if (Result == null) + { + Result = new FieldModule(MyOwner, title); + MyChilds.Add(Result); + if (IsNameSpace) + { + Result.AddChild(new FieldModule(MyOwner, "")); + Result.AddChild(new FieldModule(MyOwner, "")); + } + } + return Result; + } + private FieldModule FindField(string title) + { + foreach (var child in MyChilds) + { + if (child.Title == title) + { return child; } + } + return null; + } + private bool TryFindField(string title, out FieldModule module) + { + foreach (var child in MyChilds) + { + if (child.Title == title) + { + module = child; + return true; + } + } + module = null; + return false; + } + private void SortChild() + { + int fixedCount = 2; + + var sortablePart = MyChilds.GetRange(fixedCount, MyChilds.Count - fixedCount); + + sortablePart.Sort((a, b) => string.Compare(a.Title, b.Title, StringComparison.OrdinalIgnoreCase)); + + for (int i = 0; i < sortablePart.Count; i++) + { + MyChilds[fixedCount + i] = sortablePart[i]; + } + } + private void Print(string message) + { + Debug.Log($"[{Title}]: {message}"); + } + } + public class Ceckbox : EditorProperty + { + public Ceckbox(string Name, UnityEngine.Object other) : base(Name, other) + { + } + + + protected override byte UpdateRender() + { + CashValue = GUILayout.Toggle(CurrentValue, GUIContent.none, GUILayout.Width(18)); + if (CashValue == CurrentValue) + { + return 0; + } + else + { + SetValue(CashValue); + return 1; + } + } + protected override void FixError(int Id) + { + } + + } + private class ComboBox : EditorProperty where T : Enum + { + public ComboBox(string Name, UnityEngine.Object other) : base(Name, other) + { + } + + protected override byte UpdateRender() + { + CashValue = (T)EditorGUILayout.EnumPopup(CurrentValue, GUI.skin.FindStyle("ToolbarPopup"), GUILayout.Width(120)); + if (EqualityComparer.Default.Equals(CashValue, CurrentValue)) + { + return 0; // No change + } + else + { + SetValue(CashValue); + return 1; // Changed + } + } + protected override void FixError(int Id) + { + + } + + } + private enum FilterType + { + All, + MonoBehaviour, + ScriptableObject, + Editor + } + + + private Vector2 scroll; + private MonoScript[] ProjectScripts; + private FieldModule Root; + private string search = string.Empty; + private ComboBox filter; + private Ceckbox AdvanceSerach; + private MonoScript SelectedScript; + + public bool IsSearching + { + get + { + if (!string.IsNullOrEmpty(search)) + return true; + + if (filter.GetValue() != FilterType.All) + return true; + + return false; + } + } + + + [MenuItem("Tools/RealMethod/Viewer/ClassViewer")] + public static void Open() + { + GetWindow("Class Viewer"); + } + private void OnEnable() + { + filter = new ComboBox("Filter", this); + AdvanceSerach = new Ceckbox("Checkbox", this); + ProjectScripts = LoadScripts(); + Preper(); + } + private void OnGUI() + { + DrawToolbar(); + scroll = EditorGUILayout.BeginScrollView(scroll); + if (IsSearching) + { + DrawScriptList(); + } + else + { + Root.Draw(); + } + EditorGUILayout.EndScrollView(); + if (SelectedScript != null) + { + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + EditorGUILayout.BeginHorizontal(); + GUILayout.Label($"{SelectedScript.name}.cs"); + if (GUILayout.Button(GUIContent.none, GUI.skin.FindStyle("ToolbarSearchCancelButton"))) + { + SelectedScript = null; + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.TextArea(Analyze(SelectedScript), GUILayout.ExpandHeight(true)); + EditorGUILayout.EndVertical(); + } + EditorGUILayout.HelpBox( + " Note: This inspector uses reflection and can only detect the primary type in this script and its nested types. " + + "Additional classes, structs, enums, or interfaces declared outside the main type in the same file will not appear.", + MessageType.Info); + } + + + + private void DrawToolbar() + { + EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); + + AdvanceSerach.Render(); + + search = GUILayout.TextField( + search, + GUI.skin.FindStyle("ToolbarSearchTextField"), + GUILayout.ExpandWidth(true) + ); + + if (GUILayout.Button( + GUIContent.none, + GUI.skin.FindStyle("ToolbarSearchCancelButton"))) + { + search = ""; + GUI.FocusControl(null); + } + + filter.Render(); + + if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(70))) + { + search = ""; + filter.SetValue(FilterType.All); + Root = null; + ProjectScripts = LoadScripts(); + SelectedScript = null; + Preper(); + } + + EditorGUILayout.EndHorizontal(); + } + private void DrawScriptList() + { + foreach (var script in ProjectScripts) + { + if (!PassSearch(script)) continue; + if (!PassFilter(script)) continue; + + DrawScript(script); + } + } + private void DrawScript(MonoScript script) + { + Vector2 scroller = Vector2.zero; + Type type = script.GetClass(); + string namespaceName = type?.Namespace ?? "No Namespace"; + + EditorGUILayout.BeginHorizontal(); + + GUILayout.Label($"{script.name}({namespaceName})", GUILayout.Width(400)); + + if (GUILayout.Button("INFO ", EditorStyles.linkLabel)) + { + SelectedScript = script; + } + + if (GUILayout.Button("OpenFile ", EditorStyles.linkLabel)) + { + AssetDatabase.OpenAsset(script); + } + + EditorGUILayout.EndHorizontal(); + } + private bool PassSearch(MonoScript script) + { + if (string.IsNullOrEmpty(search)) return true; + + string Result = string.Empty; + if (AdvanceSerach.GetValue()) + { + Result = GetScriptInfo(script); + } + else + { + string type = script.GetClass() != null ? script.GetClass().Name : string.Empty; + Result = $"{script.name},{type}"; + } + + return Result.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0; + + } + private bool PassFilter(MonoScript script) + { + Type type = script.GetClass(); + if (type == null) return false; + + return filter.GetValue() switch + { + FilterType.MonoBehaviour => type.IsSubclassOf(typeof(MonoBehaviour)), + FilterType.ScriptableObject => type.IsSubclassOf(typeof(ScriptableObject)), + FilterType.Editor => type.IsSubclassOf(typeof(UnityEditor.Editor)), + _ => true + }; + } + private string GetScriptInfo(MonoScript script) + { + if (script == null) return ""; + + Type type = script.GetClass(); + if (type == null) return script.name; + + string result = + script.name + "," + + type.Name + "," + + type.Namespace + "," + + (type.BaseType != null ? type.BaseType.Name : ""); + + var nestedTypes = type.GetNestedTypes( + BindingFlags.Public | BindingFlags.NonPublic); + + foreach (var nested in nestedTypes) + { + result += "," + nested.Name; + } + + return result; + } + private MonoScript[] LoadScripts() + { + List scripts = new List(); + + string[] guids = AssetDatabase.FindAssets("t:MonoScript"); + + foreach (string guid in guids) + { + string path = AssetDatabase.GUIDToAssetPath(guid); + MonoScript script = AssetDatabase.LoadAssetAtPath(path); + + scripts.Add(script); + } + + scripts.Sort((a, b) => a.name.CompareTo(b.name)); + + return scripts.ToArray(); + } + private string Analyze(MonoScript script) + { + if (script == null) + { + return "No script selected."; + } + + Type type = script.GetClass(); + + if (type == null) + { + return "Could not find class in script."; + } + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("=== SCRIPT INFO ==="); + sb.AppendLine($"Namespace: {type.Namespace}"); + sb.AppendLine($"Class: {type.Name}"); + sb.AppendLine($"Abstract: {type.IsAbstract}"); + sb.AppendLine($"Sealed: {type.IsSealed}"); + sb.AppendLine($"Static: {type.IsAbstract && type.IsSealed}"); + sb.AppendLine(""); + + BindingFlags flags = + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.Static | + BindingFlags.DeclaredOnly; + + // Fields + sb.AppendLine("=== FIELDS ==="); + foreach (var field in type.GetFields(flags)) + { + sb.AppendLine($"{GetAccess(field)} {field.FieldType.Name} {field.Name}"); + } + + sb.AppendLine(""); + + // Properties + sb.AppendLine("=== PROPERTIES ==="); + foreach (var prop in type.GetProperties(flags)) + { + sb.AppendLine($"{prop.PropertyType.Name} {prop.Name}"); + } + + sb.AppendLine(""); + + // Methods + sb.AppendLine("=== METHODS ==="); + foreach (var method in type.GetMethods(flags)) + { + if (method.IsSpecialName) continue; + + sb.Append($"{GetAccess(method)} {method.ReturnType.Name} {method.Name}("); + + var parameters = method.GetParameters(); + + for (int i = 0; i < parameters.Length; i++) + { + sb.Append($"{parameters[i].ParameterType.Name} {parameters[i].Name}"); + + if (i < parameters.Length - 1) + sb.Append(", "); + } + + sb.AppendLine(")"); + } + + return sb.ToString(); + } + private string GetAccess(FieldInfo field) + { + if (field.IsPublic) return "public"; + if (field.IsPrivate) return "private"; + if (field.IsFamily) return "protected"; + if (field.IsAssembly) return "internal"; + return ""; + } + private string GetAccess(MethodInfo method) + { + if (method.IsPublic) return "public"; + if (method.IsPrivate) return "private"; + if (method.IsFamily) return "protected"; + if (method.IsAssembly) return "internal"; + return ""; + } + private void Preper() + { + Root = new FieldModule(this, "Root"); + FieldModule NoneNamespace = new FieldModule(this, " (No Namespace)"); + FieldModule NoneClass = new FieldModule(this, " (No Type)"); + Root.AddChild(NoneNamespace); + Root.AddChild(NoneClass); + + foreach (var script in ProjectScripts) + { + if (script != null) + { + Type ScriptType = script.GetClass(); + if (ScriptType != null) + { + if (ScriptType.Namespace != null) + { + Root.AddChild(script); + } + else + { + NoneNamespace.AddChild(new FieldModule(this, script)); + } + } + else + { + NoneClass.AddChild(new FieldModule(this, script)); + } + + } + } + + Root.Expand(); + } + } +} diff --git a/Editor/ReadySet/Tools/ClassViewerWindow.cs.meta b/Editor/ReadySet/Tools/ClassViewerWindow.cs.meta new file mode 100644 index 00000000..7d84b2ca --- /dev/null +++ b/Editor/ReadySet/Tools/ClassViewerWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cd4da7ba3d8b8fe4ea12071681b3d0ac \ No newline at end of file diff --git a/Editor/ReadySet/Tools/HelpWindow.cs b/Editor/ReadySet/Tools/HelpWindow.cs new file mode 100644 index 00000000..0a1cc81e --- /dev/null +++ b/Editor/ReadySet/Tools/HelpWindow.cs @@ -0,0 +1,264 @@ +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.IO; + +namespace RealMethod.Editor +{ + [System.Serializable] + public class HelpNode + { + public string name; + public string toturial; // text after -> + public string link; // text afeter https + public List children = new List(); + } + + public class HelpWindow : EditorWindow + { + private List rootNodes = new List(); + private Dictionary foldoutStates = new Dictionary(); + + private TextAsset textFile; + private Vector2 scrollPos; + private string searchQuery = ""; + + [MenuItem("Tools/RealMethod/Help")] + public static void Open() + { + GetWindow("Help"); + } + + // Unity Methods + private void OnEnable() + { + string ClassViewPath = "Assets/Realmethod/Documentation/Information/Help.txt"; // Just for Test + // string ClassViewPath = Path.Combine(RM_CoreEditor.Documentation, "Help.txt"); + if (!File.Exists(ClassViewPath)) + { + Debug.LogError($"ClassView file not found: {ClassViewPath}"); + Close(); + } + string ClassFile = File.ReadAllText(ClassViewPath); + LoadFromText(ClassFile); + } + private void OnGUI() + { + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Collaps")) + { + foreach (var node in rootNodes) + { + FoldLine(node, false); + } + } + if (GUILayout.Button("Expanded")) + { + foreach (var node in rootNodes) + { + FoldLine(node, true); + } + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + searchQuery = EditorGUILayout.TextField("Search", searchQuery); + + EditorGUILayout.Space(); + + // 🔽 Scroll View + scrollPos = EditorGUILayout.BeginScrollView(scrollPos); + + foreach (var node in rootNodes) + { + DrawNodeWithSearch(node, 0); + } + + EditorGUILayout.EndScrollView(); + // 🔼 Scroll View + } + + private void LoadFromText(string text) + { + rootNodes.Clear(); + foldoutStates.Clear(); + + string[] lines = text.Split('\n'); + Stack stack = new Stack(); + + foreach (string rawLine in lines) + { + if (string.IsNullOrWhiteSpace(rawLine)) + continue; + + int indent = CountIndent(rawLine); + string trimmed = rawLine.Trim(); + + string nodeName = trimmed; + string endText = null; + string linkText = null; + + // 🔹 Parse "-> End Text" + string middleText = null; + int arrowIndex = trimmed.IndexOf("->"); + if (arrowIndex >= 0) + { + nodeName = trimmed.Substring(0, arrowIndex).Trim(); + middleText = trimmed.Substring(arrowIndex + 2).Trim(); + } + + if (middleText != null) + { + int linkindex = middleText.IndexOf("https"); + if (linkindex >= 0) + { + endText = middleText.Substring(0, linkindex).Trim(); + linkText = middleText.Substring(linkindex).Trim(); + } + else + { + endText = middleText; + } + } + + HelpNode node = new HelpNode + { + name = nodeName, + toturial = endText, + link = linkText + }; + + if (indent == 0) + { + rootNodes.Add(node); + stack.Clear(); + stack.Push(node); + } + else + { + while (stack.Count > indent) + stack.Pop(); + + stack.Peek().children.Add(node); + stack.Push(node); + } + } + } + private int CountIndent(string line) + { + int spaces = 0; + foreach (char c in line) + { + if (c == ' ') + spaces++; + else + break; + } + return spaces / 2; // 2 spaces = 1 level + } + + private bool DrawNodeWithSearch(HelpNode node, int indent) + { + // Check if node matches search + bool nodeMatches = string.IsNullOrEmpty(searchQuery) || + node.name.ToLower().Contains(searchQuery.ToLower()) || + node.toturial?.ToLower().Contains(searchQuery.ToLower()) == true; + + // Check if any child matches + bool anyChildMatches = false; + foreach (var child in node.children) + { + if (NodeOrChildrenMatchSearch(child)) + { + anyChildMatches = true; + break; + } + } + + // If nothing matches, skip + if (!nodeMatches && !anyChildMatches) + return false; + + // Draw parent node + if (!foldoutStates.ContainsKey(node)) + foldoutStates[node] = true; + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(indent * 20); + foldoutStates[node] = + EditorGUILayout.Foldout(foldoutStates[node], node.name, true); + EditorGUILayout.EndHorizontal(); + + // Show endText as link if expanded + if (foldoutStates[node] && !string.IsNullOrEmpty(node.toturial)) + { + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(indent * 20); + EditorGUILayout.BeginVertical("box"); + GUIStyle richLabel = new GUIStyle(EditorStyles.wordWrappedLabel); + richLabel.richText = true; + GUILayout.Label(node.toturial, richLabel); + //GUILayout.Label(node.toturial, new GUIStyle(EditorStyles.wordWrappedLabel)); + if (!string.IsNullOrEmpty(node.link)) + { + if (GUILayout.Button("Link", EditorStyles.linkLabel)) + { + OnEndTextClicked(node); + } + } + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + } + + + + // Draw children recursively only if expanded + if (foldoutStates[node]) + { + foreach (var child in node.children) + { + DrawNodeWithSearch(child, indent + 1); + } + } + + return true; + } + // Helper: check recursively if a node or any child matches search + private bool NodeOrChildrenMatchSearch(HelpNode node) + { + bool match = string.IsNullOrEmpty(searchQuery) || + node.name.ToLower().Contains(searchQuery.ToLower()) || + node.toturial?.ToLower().Contains(searchQuery.ToLower()) == true; + + if (match) + return true; + + foreach (var child in node.children) + { + if (NodeOrChildrenMatchSearch(child)) + return true; + } + + return false; + } + private void FoldLine(HelpNode node, bool result) + { + foldoutStates[node] = result; + if (foldoutStates[node]) + { + foreach (var child in node.children) + FoldLine(child, result); + } + } + private void OnEndTextClicked(HelpNode node) + { + if (EditorUtility.DisplayDialog("OpenLink", node.link, "Open", "Cancel")) + { + // 3️⃣ OR open URL (if endText is a URL) + Application.OpenURL(node.link); + } + // 2️⃣ OR ping asset + // EditorGUIUtility.PingObject(yourObject); + } + + } +} diff --git a/Editor/ReadySet/Tools/HelpWindow.cs.meta b/Editor/ReadySet/Tools/HelpWindow.cs.meta new file mode 100644 index 00000000..4a309112 --- /dev/null +++ b/Editor/ReadySet/Tools/HelpWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 15438cb6b5774124f90a5a787acca4c8 \ No newline at end of file diff --git a/Editor/ReadySet/Tools/LibraryViewerWindow.cs b/Editor/ReadySet/Tools/LibraryViewerWindow.cs new file mode 100644 index 00000000..aec57fc7 --- /dev/null +++ b/Editor/ReadySet/Tools/LibraryViewerWindow.cs @@ -0,0 +1,305 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace RealMethod.Editor +{ + public class LibraryViewerWindow : EditorWindow + { + private class FieldModule + { + //private Vector2 scroll; + private MonoScript File; + + + public Type Class { get; private set; } + public MethodInfo TargetMethod { get; private set; } + public string Title + { + get + { + return $"{Class.Name}.{TargetMethod.Name}"; + } + } + public bool IsExpand { get; private set; } = false; + public bool isStatic => Class.IsAbstract && Class.IsSealed; + + public FieldModule(MonoScript script, MethodInfo method) + { + File = script; + + if (method == null) + Print("Method is not valid!"); + TargetMethod = method; + + Type ClassType = script.GetClass(); + if (ClassType == null) + Print("Class is not valid!"); + Class = ClassType; + } + + public void Render() + { + EditorGUILayout.BeginHorizontal(); + IsExpand = EditorGUILayout.Foldout(IsExpand, $"{Title}({TargetMethod.GetParameters().Length})", true); + if (GUILayout.Button("OpenFile ", EditorStyles.linkLabel)) + { + Debug.Log("sdsdsd"); + AssetDatabase.OpenAsset(File); + } + EditorGUILayout.EndHorizontal(); + if (IsExpand) + { + //EditorGUI.BeginDisabledGroup(true); + //scroll = EditorGUILayout.BeginScrollView(scroll, GUILayout.Height(800)); + EditorGUILayout.TextArea(GetMethodBody(File, TargetMethod)); + //EditorGUILayout.EndScrollView(); + //EditorGUI.EndDisabledGroup(); + } + + } + + private string GetMethodBody(MonoScript script, MethodInfo method) + { + string path = AssetDatabase.GetAssetPath(script); + if (string.IsNullOrEmpty(path)) + { + return "Invalid script path."; + } + string[] lines = System.IO.File.ReadAllLines(path); + + StringBuilder sb = new StringBuilder(); + + int MethodLineNumber = -1; + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].Contains(method.Name)) + { + MethodLineNumber = i; + break; + } + } + + if (MethodLineNumber == -1) + { + return "Something wrong!"; + } + + for (int i = MethodLineNumber; i < MethodLineNumber + 10; i++) + { + sb.AppendLine(lines[i]); + } + return sb.ToString(); + } + private void Print(string message) + { + Debug.Log($"[{Title}]: {message}"); + } + } + private class Dropdown : EditorProperty + { + private string[] Options; + public string CurrentOption => Options[GetValue()]; + + public Dropdown(string Name, string[] options, UnityEngine.Object other) : base(Name, other) + { + Options = options; + } + + protected override byte UpdateRender() + { + CashValue = EditorGUILayout.Popup(string.Empty, CurrentValue, Options, GUI.skin.FindStyle("ToolbarPopup"), GUILayout.Width(120)); + if (CashValue == CurrentValue) + { + return 0; // No change + } + else + { + SetValue(CashValue); + return 1; // Changed + } + } + protected override void FixError(int Id) + { + throw new NotImplementedException(); + } + } + + + private Vector2 scroll; + private Dropdown NameSpace_Filter; + private MonoScript[] Scripts; + private List Fields = new List(0); + private string search = string.Empty; + + + [MenuItem("Tools/RealMethod/Viewer/LibraryViewer")] + public static void Open() + { + GetWindow("LibraryViewer"); + } + private void OnEnable() + { + + Scripts = LoadScripts(); + CreateNameSpaceList(); + ReSetField(); + } + private void OnGUI() + { + DrawToolbar(); + scroll = EditorGUILayout.BeginScrollView(scroll); + foreach (var field in Fields) + { + if (!PassSearch(field)) continue; + if (!PassFilter(field)) continue; + + field.Render(); + } + EditorGUILayout.EndScrollView(); + EditorGUILayout.HelpBox( + " Note: This inspector uses reflection and can only detect the primary type in this script and its nested types. " + + "Additional classes, structs, enums, or interfaces declared outside the main type in the same file will not appear.", + MessageType.Info); + } + + + private void ReSetField() + { + Fields.Clear(); + + + foreach (var script in Scripts) + { + Type mainType = script.GetClass(); + if (mainType == null) + continue; + + if (mainType.IsAbstract && mainType.IsSealed) + { + DrawField(script,mainType); + Type[] nestedTypes = mainType.GetNestedTypes(BindingFlags.Public); + foreach (var classtype in nestedTypes) + { + DrawField(script,classtype); + } + } + + } + } + private void DrawField(MonoScript script, Type mainType) + { + BindingFlags flags = + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.Static | + BindingFlags.DeclaredOnly; + + foreach (var method in mainType.GetMethods(flags)) + { + if (method.IsSpecialName) continue; + + if (!method.IsPublic) continue; + + if (!method.IsStatic) continue; + + if (method.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false)) continue; + + Fields.Add(new FieldModule(script, method)); + } + } + private void DrawToolbar() + { + EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); + + search = GUILayout.TextField(search, GUI.skin.FindStyle("ToolbarSearchTextField"), GUILayout.ExpandWidth(true)); + + if (GUILayout.Button(GUIContent.none, GUI.skin.FindStyle("ToolbarSearchCancelButton"))) + { + search = ""; + GUI.FocusControl(null); + } + + if (NameSpace_Filter.Render() == 1) + ReSetField(); + + if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(70))) + { + search = ""; + Scripts = LoadScripts(); + CreateNameSpaceList(); + ReSetField(); + } + + EditorGUILayout.EndHorizontal(); + } + private bool PassSearch(FieldModule Field) + { + if (string.IsNullOrEmpty(search)) return true; + + return Field.Title.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0; + } + private bool PassFilter(FieldModule Field) + { + if (NameSpace_Filter.GetValue() == 0) + return true; + + if (Field.Class.Namespace == NameSpace_Filter.CurrentOption) + return true; + + return false; + } + private void CreateNameSpaceList() + { + int RealMethodIndex = 0; + HashSet NameSpaceList = new HashSet() { "All" }; + foreach (var script in Scripts) + { + if (script == null) + continue; + + Type ClassType = script.GetClass(); + if (ClassType != null) + { + if (!string.IsNullOrEmpty(ClassType.Namespace)) + { + if (NameSpaceList.Add(ClassType.Namespace)) + { + if (ClassType.Namespace == "RealMethod") + { + RealMethodIndex = NameSpaceList.Count - 1; + } + } + } + } + } + // Set NameSpace Lisst to Dropdown box + NameSpace_Filter = new Dropdown("Filter", NameSpaceList.ToArray(), this); + NameSpace_Filter.SetValue(RealMethodIndex); + } + private MonoScript[] LoadScripts() + { + List scripts = new List(); + + string[] guids = AssetDatabase.FindAssets("t:MonoScript"); + + foreach (string guid in guids) + { + string path = AssetDatabase.GUIDToAssetPath(guid); + MonoScript script = AssetDatabase.LoadAssetAtPath(path); + + scripts.Add(script); + } + + scripts.Sort((a, b) => a.name.CompareTo(b.name)); + + return scripts.ToArray(); + } + + } +} \ No newline at end of file diff --git a/Editor/ReadySet/Tools/LibraryViewerWindow.cs.meta b/Editor/ReadySet/Tools/LibraryViewerWindow.cs.meta new file mode 100644 index 00000000..890bcc2c --- /dev/null +++ b/Editor/ReadySet/Tools/LibraryViewerWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5ff9e75fbed2b884b83172d51263511a \ No newline at end of file diff --git a/Editor/Toolkit/Ability/AbilityControllerEditor.cs b/Editor/Toolkit/Ability/AbilityControllerEditor.cs index 9f15cb55..8d0b736e 100644 --- a/Editor/Toolkit/Ability/AbilityControllerEditor.cs +++ b/Editor/Toolkit/Ability/AbilityControllerEditor.cs @@ -23,7 +23,7 @@ public override void OnInspectorGUI() EditorGUILayout.LabelField($"Debug ({MyController.Count})", EditorStyles.boldLabel); for (int i = 0; i < MyController.Count; i++) { - EditorGUILayout.LabelField($"{MyController.GetAbility(i).NameID}: {IsReady(MyController.GetAbility(i))}"); + EditorGUILayout.LabelField($"{MyController.GetAbility(i).Self}: {IsReady(MyController.GetAbility(i))}"); } } diff --git a/Editor/Toolkit/Ability/AbilityMenu.cs b/Editor/Toolkit/Ability/AbilityMenu.cs new file mode 100644 index 00000000..c21b344b --- /dev/null +++ b/Editor/Toolkit/Ability/AbilityMenu.cs @@ -0,0 +1,27 @@ +using UnityEditor; + +namespace RealMethod.Editor +{ + class AbilityMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Toolkit; + + + + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Ability/AbilityAsset", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateAbilityAsset() + { + RM_Editor.CreateScriptTemplate("AbilityAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Ability/AbilityActionAsset", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateAbilityAction() + { + RM_Editor.CreateScriptTemplate("AbilityActionAsset", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Ability/Effect", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateEffect() + { + RM_Editor.CreateScriptTemplate("AbilityEffect", MenuLayer); + } + } +} \ No newline at end of file diff --git a/Editor/Toolkit/Ability/Ability_ScriptTemplate.cs.meta b/Editor/Toolkit/Ability/AbilityMenu.cs.meta similarity index 100% rename from Editor/Toolkit/Ability/Ability_ScriptTemplate.cs.meta rename to Editor/Toolkit/Ability/AbilityMenu.cs.meta diff --git a/Editor/Toolkit/Ability/Ability_ScriptTemplate.cs b/Editor/Toolkit/Ability/Ability_ScriptTemplate.cs deleted file mode 100644 index 9c3c07f3..00000000 --- a/Editor/Toolkit/Ability/Ability_ScriptTemplate.cs +++ /dev/null @@ -1,23 +0,0 @@ -using UnityEditor; - -namespace RealMethod.Editor -{ - class Ability_ScriptTemplate - { - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Ability/AbilityAsset", false, 80)] - public static void CreateAbilityAsset() - { - string Path = RM_Create.Script("AbilityAssetTemplate.txt", "MyAbility.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Ability/AbilityActionAsset", false, 80)] - public static void CreateAbilityAction() - { - string Path = RM_Create.Script("AbilityActionAssetTemplate.txt", "MyAbilityAction.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Ability/Effect", false, 80)] - public static void CreateEffect() - { - string Path = RM_Create.Script("AbilityEffectTemplate.txt", "MyEffect.cs"); - } - } -} \ No newline at end of file diff --git a/Editor/Toolkit/Actor/ActorMenu.cs b/Editor/Toolkit/Actor/ActorMenu.cs new file mode 100644 index 00000000..0b357075 --- /dev/null +++ b/Editor/Toolkit/Actor/ActorMenu.cs @@ -0,0 +1,16 @@ +using UnityEditor; + +namespace RealMethod.Editor +{ + class ActorMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Toolkit; + + + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Actor/Act", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateActCommand() + { + RM_Editor.CreateScriptTemplate("Act", MenuLayer); + } + } +} \ No newline at end of file diff --git a/Editor/Toolkit/Actor/Actor_ScriptTemplate.cs.meta b/Editor/Toolkit/Actor/ActorMenu.cs.meta similarity index 100% rename from Editor/Toolkit/Actor/Actor_ScriptTemplate.cs.meta rename to Editor/Toolkit/Actor/ActorMenu.cs.meta diff --git a/Editor/Toolkit/Actor/Actor_ScriptTemplate.cs b/Editor/Toolkit/Actor/Actor_ScriptTemplate.cs deleted file mode 100644 index d1c971e2..00000000 --- a/Editor/Toolkit/Actor/Actor_ScriptTemplate.cs +++ /dev/null @@ -1,13 +0,0 @@ -using UnityEditor; - -namespace RealMethod.Editor -{ - class Actor_ScriptTemplate - { - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Actor/Act", false, 80)] - public static void CreateActCommand() - { - string Path = RM_Create.Script("ActTemplate.txt", "MyAct.cs"); - } - } -} \ No newline at end of file diff --git a/Editor/Toolkit/CSVFile/CSVFileEditor.cs b/Editor/Toolkit/CSVFile/CSVFileEditor.cs index c368931b..905e4eed 100644 --- a/Editor/Toolkit/CSVFile/CSVFileEditor.cs +++ b/Editor/Toolkit/CSVFile/CSVFileEditor.cs @@ -10,7 +10,7 @@ namespace RealMethod.Editor [CustomEditor(typeof(TextAsset))] public class CSVFileEditor : UnityEditor.Editor { - class CustomList : EPS_ScriptableObjectList where T : ScriptableObject + class CustomList : EPS_AssetList where T : PrimitiveAsset { Color originalColor = GUI.backgroundColor; @@ -52,7 +52,7 @@ enum SheetType private string assetPath; private EPS_Enum ReadStyle; private SheetViewer TabelGUI; - private CustomList ObjectsPart; + private CustomList ObjectsPart; private EPS_Date LastUpdate; private EPS_Enum OnlineSheetType; private EPS_string SheetID; @@ -74,7 +74,7 @@ private void OnEnable() // Load the file content TabelGUI = new SheetViewer(textAsset); ReadStyle = new EPS_Enum(this, "ReadType"); - ObjectsPart = new CustomList(this, "SObjects"); + ObjectsPart = new CustomList(this, "SObjects"); LastUpdate = new EPS_Date(this, "LastUpdate"); SheetID = new EPS_string(this, "SheetID"); OnlineSheetType = new EPS_Enum(this, "SheetType"); diff --git a/Editor/Toolkit/Inventory/InventoryEditor.cs b/Editor/Toolkit/Inventory/InventoryEditor.cs index d67918b2..79422425 100644 --- a/Editor/Toolkit/Inventory/InventoryEditor.cs +++ b/Editor/Toolkit/Inventory/InventoryEditor.cs @@ -26,7 +26,7 @@ public override void OnInspectorGUI() { //EditorGUILayout.BeginHorizontal(); int ItemQuantity = BaseComponent.GetQuantity(item); - EditorGUILayout.LabelField($"Name: {item.NameID}({item.NameID}) - Quantity: {ItemQuantity} "); + EditorGUILayout.LabelField($"Name: {item.SelfName}({item.SelfName}) - Quantity: {ItemQuantity} "); total += ItemQuantity; //EditorGUILayout.EndHorizontal(); } diff --git a/Editor/Toolkit/Inventory/InventoryMenu.cs b/Editor/Toolkit/Inventory/InventoryMenu.cs new file mode 100644 index 00000000..83f1a090 --- /dev/null +++ b/Editor/Toolkit/Inventory/InventoryMenu.cs @@ -0,0 +1,17 @@ +using UnityEditor; + +namespace RealMethod.Editor +{ + class InventoryMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Toolkit; + + + + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Inventory/Item", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateItem() + { + RM_Editor.CreateScriptTemplate("InventoryItem", MenuLayer); + } + } +} \ No newline at end of file diff --git a/Editor/Toolkit/Inventory/Inventory_ScriptTemplate.cs.meta b/Editor/Toolkit/Inventory/InventoryMenu.cs.meta similarity index 100% rename from Editor/Toolkit/Inventory/Inventory_ScriptTemplate.cs.meta rename to Editor/Toolkit/Inventory/InventoryMenu.cs.meta diff --git a/Editor/Toolkit/Inventory/Inventory_ScriptTemplate.cs b/Editor/Toolkit/Inventory/Inventory_ScriptTemplate.cs deleted file mode 100644 index 8f3da799..00000000 --- a/Editor/Toolkit/Inventory/Inventory_ScriptTemplate.cs +++ /dev/null @@ -1,13 +0,0 @@ -using UnityEditor; - -namespace RealMethod.Editor -{ - class Inventory_ScriptTemplate - { - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Inventory/Item", false, 80)] - public static void CreateItem() - { - string Path = RM_Create.Script("InventoryItemTemplate.txt", "MyItem.cs"); - } - } -} \ No newline at end of file diff --git a/Editor/Toolkit/PCG/PCGEditorWindow.cs b/Editor/Toolkit/PCG/PCGEditorWindow.cs index a558103c..96f84d01 100644 --- a/Editor/Toolkit/PCG/PCGEditorWindow.cs +++ b/Editor/Toolkit/PCG/PCGEditorWindow.cs @@ -63,9 +63,9 @@ private enum PCGExportType } // Fields - private EP_ScriptableObject Resurce; - private EP_ScriptableObject Genration; - private EP_ScriptableObject Cash; + private EP_Asset Resurce; + private EP_Asset Genration; + private EP_Asset Cash; private EP_List SelectedData; private EP_String CashAddress; private EP_String PrefabAddress; @@ -102,14 +102,14 @@ private void OnEnable() Debug.LogError("ProjectSettingAsset is missing from Resources folder!"); } - Resurce = new EP_ScriptableObject("Resurce", this); - Genration = new EP_ScriptableObject("Genration", this); - Cash = new EP_ScriptableObject("Cash", this); + Resurce = new EP_Asset("Resurce", this); + Genration = new EP_Asset("Genration", this); + Cash = new EP_Asset("Cash", this); SelectedData = new EP_List("Data", this); CashAddress = new EP_String("Address", this); - CashAddress.SetValue(ProjectSetting.FindAddres(ProjectSettingAsset.IdentityAsset.PCG).Path + "/PCGCashAsset.asset"); + CashAddress.SetValue(ProjectSetting.GetFolderPathByType(ProjectSettingAsset.AssetFormat.ScriptableObject) + "/PCGCashAsset.asset"); PrefabAddress = new EP_String("Address", this); - PrefabAddress.SetValue(ProjectSetting.FindAddres(ProjectSettingAsset.IdentityAsset.Prefab).Path + "/PCG.prefab"); + PrefabAddress.SetValue(ProjectSetting.GetFolderAddressByType(ProjectSettingAsset.AssetFormat.Prefab).AssetPath + "/PCG.prefab"); ExportType = new EP_Enum("ExportType", this); // Subscribe to the selectionChanged event @@ -391,7 +391,7 @@ private void CashPanel() Cash.Render(); if (GUILayout.Button("CreateCash")) { - Cash.SetValue(RM_Create.ScriptableObj(CashAddress.GetValue())); + Cash.SetValue(RM_Create.Asset(CashAddress.GetValue())); } EditorGUILayout.EndHorizontal(); } diff --git a/Editor/Toolkit/PCG/PCGMenu.cs b/Editor/Toolkit/PCG/PCGMenu.cs new file mode 100644 index 00000000..3c97e9eb --- /dev/null +++ b/Editor/Toolkit/PCG/PCGMenu.cs @@ -0,0 +1,15 @@ +using UnityEditor; + +namespace RealMethod.Editor +{ + class PCGMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Toolkit; + + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/PCG/Request", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreatePCGRequest() + { + RM_Editor.CreateScriptTemplate("PCGRequest", MenuLayer); + } + } +} \ No newline at end of file diff --git a/Editor/Toolkit/PCG/PCG_ScriptTemplate.cs.meta b/Editor/Toolkit/PCG/PCGMenu.cs.meta similarity index 100% rename from Editor/Toolkit/PCG/PCG_ScriptTemplate.cs.meta rename to Editor/Toolkit/PCG/PCGMenu.cs.meta diff --git a/Editor/Toolkit/PCG/PCG_ScriptTemplate.cs b/Editor/Toolkit/PCG/PCG_ScriptTemplate.cs deleted file mode 100644 index ade88096..00000000 --- a/Editor/Toolkit/PCG/PCG_ScriptTemplate.cs +++ /dev/null @@ -1,13 +0,0 @@ -using UnityEditor; - -namespace RealMethod.Editor -{ - class PCG_ScriptTemplate - { - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/PCG/Request", false, 80)] - public static void CreatePCGRequest() - { - string Path = RM_Create.Script("PCGRequestTamplate.txt", "MyRequest.cs"); - } - } -} \ No newline at end of file diff --git a/Editor/Toolkit/PCG/PCG_UnityAsset.cs b/Editor/Toolkit/PCG/PCG_UnityAsset.cs index 1a976e3a..01de736f 100644 --- a/Editor/Toolkit/PCG/PCG_UnityAsset.cs +++ b/Editor/Toolkit/PCG/PCG_UnityAsset.cs @@ -1,6 +1,6 @@ namespace RealMethod.Editor { - public class PCGResource_UnityAsset : AssetHandeler + public class PCGResource_UnityAsset : AssetProcess { protected override void Initialized() { @@ -24,7 +24,7 @@ protected override void DoubleClick(PCGResourceConfig asset) } } - public class PCGGeneration_UnityAsset : AssetHandeler + public class PCGGeneration_UnityAsset : AssetProcess { protected override void Initialized() { @@ -48,7 +48,7 @@ protected override void DoubleClick(PCGGenerationAsset asset) } } - public class PCGCash_UnityAsset : AssetHandeler + public class PCGCash_UnityAsset : AssetProcess { protected override void Initialized() { diff --git a/Editor/Toolkit/Pickup/PickupMenu.cs b/Editor/Toolkit/Pickup/PickupMenu.cs new file mode 100644 index 00000000..27716487 --- /dev/null +++ b/Editor/Toolkit/Pickup/PickupMenu.cs @@ -0,0 +1,21 @@ +using UnityEditor; + +namespace RealMethod.Editor +{ + class PickupMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Toolkit; + + + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Pickup/Pickup3D", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreatePickup3D() + { + RM_Editor.CreateScriptTemplate("Pickup3D", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Pickup/Pickup2D", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreatePickup2D() + { + RM_Editor.CreateScriptTemplate("Pickup2D", MenuLayer); + } + } +} \ No newline at end of file diff --git a/Editor/Toolkit/Pickup/Pickup_ScriptTemplate.cs.meta b/Editor/Toolkit/Pickup/PickupMenu.cs.meta similarity index 100% rename from Editor/Toolkit/Pickup/Pickup_ScriptTemplate.cs.meta rename to Editor/Toolkit/Pickup/PickupMenu.cs.meta diff --git a/Editor/Toolkit/Pickup/Pickup_ScriptTemplate.cs b/Editor/Toolkit/Pickup/Pickup_ScriptTemplate.cs deleted file mode 100644 index 2f3809ff..00000000 --- a/Editor/Toolkit/Pickup/Pickup_ScriptTemplate.cs +++ /dev/null @@ -1,18 +0,0 @@ -using UnityEditor; - -namespace RealMethod.Editor -{ - class Pickup_ScriptTemplate - { - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Pickup/Pickup3D", false, 80)] - public static void CreatePickup3D() - { - string Path = RM_Create.Script("Pickup3DTemplate.txt", "MyPickup.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Pickup/Pickup2D", false, 80)] - public static void CreatePickup2D() - { - string Path = RM_Create.Script("Pickup2DTemplate.txt", "MyPickup.cs"); - } - } -} \ No newline at end of file diff --git a/Editor/Toolkit/RPG/RPGMenu.cs b/Editor/Toolkit/RPG/RPGMenu.cs new file mode 100644 index 00000000..527d00a7 --- /dev/null +++ b/Editor/Toolkit/RPG/RPGMenu.cs @@ -0,0 +1,33 @@ +using UnityEditor; + +namespace RealMethod.Editor +{ + class RPGMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Toolkit; + + + + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/RPG/StatDefinition", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateStatDefinition() + { + RM_Editor.CreateScriptTemplate("StatDefinition", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/RPG/StatProfile", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateStatProfile() + { + RM_Editor.CreateScriptTemplate("StatProfile", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/RPG/StatBuff", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateBuffConfig() + { + RM_Editor.CreateScriptTemplate("BuffConfig", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/RPG/ResourceData", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateResourceData() + { + RM_Editor.CreateScriptTemplate("ResourceData", MenuLayer); + } + + } +} \ No newline at end of file diff --git a/Editor/Toolkit/RPG/RPG_ScriptTemplate.cs.meta b/Editor/Toolkit/RPG/RPGMenu.cs.meta similarity index 100% rename from Editor/Toolkit/RPG/RPG_ScriptTemplate.cs.meta rename to Editor/Toolkit/RPG/RPGMenu.cs.meta diff --git a/Editor/Toolkit/RPG/RPG_ScriptTemplate.cs b/Editor/Toolkit/RPG/RPG_ScriptTemplate.cs deleted file mode 100644 index 956250cc..00000000 --- a/Editor/Toolkit/RPG/RPG_ScriptTemplate.cs +++ /dev/null @@ -1,29 +0,0 @@ -using UnityEditor; - -namespace RealMethod.Editor -{ - class RPG_ScriptTemplate - { - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/RPG/StatDefinition", false, 80)] - public static void CreateStatDefinition() - { - string Path = RM_Create.Script("StatDefinitionTemplate.txt", "StatDefinition.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/RPG/StatProfile", false, 80)] - public static void CreateStatProfile() - { - string Path = RM_Create.Script("StatProfileTemplate.txt", "MyProfile.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/RPG/StatBuff", false, 80)] - public static void CreateBuffConfig() - { - string Path = RM_Create.Script("BuffConfigTemplate.txt", "MyBuff.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/RPG/ResourceData", false, 80)] - public static void CreateResourceData() - { - string Path = RM_Create.Script("ResourceDataTemplate.txt", "MyResource.cs"); - } - - } -} \ No newline at end of file diff --git a/Editor/Toolkit/TerrainTools/TerrainEditor.cs b/Editor/Toolkit/TerrainTools/TerrainEditor.cs index cf50fcce..72a9462d 100644 --- a/Editor/Toolkit/TerrainTools/TerrainEditor.cs +++ b/Editor/Toolkit/TerrainTools/TerrainEditor.cs @@ -71,7 +71,7 @@ private int GetTreeCount() // If You Remove PCG Kit Just Remove ExportTreeData from this code. public class ExportTreeData : Object { - private EP_ScriptableObject CashFile; + private EP_Asset CashFile; private EP_String CashAddress; private ProjectSettingAsset ProjectSetting; private Terrain OwnerTerrain; @@ -92,9 +92,9 @@ public ExportTreeData(Terrain owner, UnityEditor.Editor editor) return; } - CashFile = new EP_ScriptableObject("Cash", editor); + CashFile = new EP_Asset("Cash", editor); CashAddress = new EP_String("Address", editor); - CashAddress.SetValue(ProjectSetting.FindAddres(ProjectSettingAsset.IdentityAsset.PCG).Path + "/TerrainCash.asset"); + CashAddress.SetValue(ProjectSetting.GetFolderPathByType(ProjectSettingAsset.AssetFormat.ScriptableObject) + "/TerrainCash.asset"); } public void OnRender() @@ -138,8 +138,8 @@ public void OnRender() if (GUILayout.Button("CreateCash")) { string directoryfile = Path.GetDirectoryName(CashAddress.GetValue()); - PCGResourceConfig ResurcePack = RM_Create.ScriptableObj(directoryfile + "/TerrainResource.asset"); - PCGCashAsset Temporery = RM_Create.ScriptableObj(CashAddress.GetValue()); + PCGResourceConfig ResurcePack = RM_Create.Asset(directoryfile + "/TerrainResource.asset"); + PCGCashAsset Temporery = RM_Create.Asset(CashAddress.GetValue()); TerrainData Data = OwnerTerrain.terrainData; PCGSource[] TerrainSource = new PCGSource[Data.treePrototypes.Length]; TreeInstance[] trees = OwnerTerrain.terrainData.treeInstances; diff --git a/Editor/Toolkit/Tutorial/TutorialMenu.cs b/Editor/Toolkit/Tutorial/TutorialMenu.cs new file mode 100644 index 00000000..6ced5b67 --- /dev/null +++ b/Editor/Toolkit/Tutorial/TutorialMenu.cs @@ -0,0 +1,26 @@ +using UnityEditor; + +namespace RealMethod.Editor +{ + class TutorialMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Toolkit; + + + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Tutorial/Screen", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateTutorialScreen() + { + RM_Editor.CreateScriptTemplate("TutorialScreen", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Tutorial/UIunit", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateTutorialMessage() + { + RM_Editor.CreateScriptTemplate("TutorialUnit", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Tutorial/Config", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateTutorialConfig() + { + RM_Editor.CreateScriptTemplate("TutorialConfig", MenuLayer); + } + } +} \ No newline at end of file diff --git a/Editor/Toolkit/Tutorial/Tutorial_ScriptTemplate.cs.meta b/Editor/Toolkit/Tutorial/TutorialMenu.cs.meta similarity index 100% rename from Editor/Toolkit/Tutorial/Tutorial_ScriptTemplate.cs.meta rename to Editor/Toolkit/Tutorial/TutorialMenu.cs.meta diff --git a/Editor/Toolkit/Tutorial/Tutorial_ScriptTemplate.cs b/Editor/Toolkit/Tutorial/Tutorial_ScriptTemplate.cs deleted file mode 100644 index e5f76533..00000000 --- a/Editor/Toolkit/Tutorial/Tutorial_ScriptTemplate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using UnityEditor; - -namespace RealMethod.Editor -{ - class Tutorial_ScriptTemplate - { - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Tutorial/ScreenWidget", false, 80)] - public static void CreateTutorialScreen() - { - string Path = RM_Create.Script("TutorialScreenTemplate.txt", "MyTutorialScreen.cs"); - } - - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Tutorial/UIunit", false, 80)] - public static void CreateTutorialMessage() - { - string Path = RM_Create.Script("TutorialUnitTemplate.txt", "MyTutorialUnit.cs"); - } - - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Tutorial/Config", false, 80)] - public static void CreateTutorialConfig() - { - string Path = RM_Create.Script("TutorialConfigTemplate.txt", "MyTutorialConfig.cs"); - } - } -} \ No newline at end of file diff --git a/Editor/Toolkit/Upgrade/UpgradeMenu.cs b/Editor/Toolkit/Upgrade/UpgradeMenu.cs new file mode 100644 index 00000000..bffe6af1 --- /dev/null +++ b/Editor/Toolkit/Upgrade/UpgradeMenu.cs @@ -0,0 +1,22 @@ +using UnityEditor; + +namespace RealMethod.Editor +{ + class UpgradeMenu + { + private const RealMethodLayer MenuLayer = RealMethodLayer.Toolkit; + + + + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Upgrade/Item", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateItem() + { + RM_Editor.CreateScriptTemplate("UpgradeItem", MenuLayer); + } + [MenuItem(RM_Editor.ScriptMenuItemPath + "Toolkit/Upgrade/Map", false, RM_Editor.MenuOrder.Toolkit)] + public static void CreateConfig() + { + RM_Editor.CreateScriptTemplate("UpgradeConfig", MenuLayer); + } + } +} \ No newline at end of file diff --git a/Editor/Toolkit/Upgrade/Upgrade_ScriptTemplate.cs.meta b/Editor/Toolkit/Upgrade/UpgradeMenu.cs.meta similarity index 100% rename from Editor/Toolkit/Upgrade/Upgrade_ScriptTemplate.cs.meta rename to Editor/Toolkit/Upgrade/UpgradeMenu.cs.meta diff --git a/Editor/Toolkit/Upgrade/Upgrade_ScriptTemplate.cs b/Editor/Toolkit/Upgrade/Upgrade_ScriptTemplate.cs deleted file mode 100644 index 063f71a8..00000000 --- a/Editor/Toolkit/Upgrade/Upgrade_ScriptTemplate.cs +++ /dev/null @@ -1,18 +0,0 @@ -using UnityEditor; - -namespace RealMethod.Editor -{ - class Upgrade_ScriptTemplate - { - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Upgrade/ItemAsset", false, 80)] - public static void CreateItem() - { - string Path = RM_Create.Script("UpgradeItemTemplate.txt", "MyUpgradeAsset.cs"); - } - [MenuItem("Assets/Create/Scripting/RealMethod/Toolkit/Upgrade/MapConfig", false, 80)] - public static void CreateConfig() - { - string Path = RM_Create.Script("UpgradeConfigTemplate.txt", "MyUpgradeConfig.cs"); - } - } -} \ No newline at end of file diff --git a/README.md b/README.md index abe4bee8..718e059e 100644 --- a/README.md +++ b/README.md @@ -1,148 +1,31 @@ -# 🌌 RealMethod -*A lightweight Unity architecture for scalable and modular project creation.* ---- - -## ✨ Overview - -**RealMethod** is a Unity package that defines a clean and consistent **project architecture**. -It focuses on separation of responsibility and lifecycle management, allowing developers to build games that are easily extendable, maintainable, and modular. - -RealMethod introduces five main layers: -- **Core** – Defines the base relationships between Game, World, Manager, and Service. -- **Library** – Common utility functions, interfaces, and shared components. -- **Pattern** – Predefined architecture patterns and reusable managers. -- **Toolkit** – Ready-to-use tools, inspectors, and debugging helpers. -- **ReadySet** – Example setups and templates for quick project initialization. - ---- - -## 🧩 Core Architecture - -### **Game** -- The **Game** class is the entry point of the RealMethod framework. -- It is a **singleton** that lives for the entire game lifecycle (until quit). -- Responsible for global operations such as: - - Scene management (`OpenScene`, `ReloadScene`, etc.) - - Time control (`SetGameSpeed`) - - Service construction and destruction - -All **Managers** and **Services** are registered through `Game`, ensuring consistent global access. - ---- - -### **World** -- The **World** class exists **once per scene** and acts as the runtime context for that scene. -- It initializes all **World-scoped Managers** and prepares the scene for gameplay. -- While **Game** persists between scenes, **World** resets when scenes change. -- Required in every scene that uses RealMethod. - ---- - -### **Manager** -- A **Manager** defines a controllable system within a given scope (Game or World). -- Implements the `IManager` interface. -- Managers are initialized **before Unity’s Awake/Start** callbacks. -- Can live in one of two scopes: - - **Game scope:** persists between scenes (registered under Game). - - **World scope:** tied to a specific scene (registered under World). - -Both Game and World automatically call `DontDestroyOnLoad` for their scoped Managers. - ---- - -### **Service** -- A **Service** is a lightweight, non-MonoBehaviour object managed by the Game. -- Created dynamically using `Game.CreateService()`. -- All Managers automatically recognize and can interact with new Services. -- Can be destroyed at any time via `Game.DestroyService()`. -- Ideal for runtime systems like data caching, analytics, or network clients. - ---- - -## ⚙️ Lifecycle Summary - -| Layer | Scope | Lifetime | Created By | Notes | -|-------|--------|-----------|-------------|-------| -| Game | Global | Until Quit | App Start | Singleton | -| World | Scene | Per Scene | Scene Load | Scene Context | -| Manager | Global/Scene | Anytime | Game/World | Registered in Game/Scene scope | -| Service | Runtime | Dynamic | Game | Fully managed objects | - ---- - -## 📦 Package Structure -RealMethod is organized into clearly separated runtime, editor, and resource layers — each designed to keep your project scalable, readable, and modular. -### 🧩 Runtime -Core runtime code that runs inside Unity builds. - -- **Core/** - - `Architecture/` – Core systems such as **Game**, **World**, **Manager**, and **Service**. - - `Attributes/` – Custom attributes used across the framework. - - `Definitions/` – Global enums, tags, and static definitions. - - `ProjectSetting/` – Runtime configuration and project constants. - -- **Library/** - - `Extension/` – Unity extensions and helper methods. - - `Interfaces/` – Common interfaces for modular communication. - - `SharedScripts/` – Shared data structures (Classes, Enums, Structs). - - `Utilities/` – Core utility scripts. - - `Vendor/SerializableDictionary/` – Third-party generic dictionary support. - -- **Pattern/** - - `Components/` – Base components using RealMethod patterns. - - `DataAssets/` – ScriptableObject-based configuration. - - `DesignPatterns/` – Common gameplay and architecture patterns. - - `Managers/` – Runtime manager implementations. - - `Services/` – Service classes managed by the Game/World. - -- **ReadySet/** - - `Commands/` – Command execution framework (Executors, Tasks). - - `Components/` – Common building blocks (Input, Method, Physics, Time, UI, Visual). - - `DefaultsClass/` – Predefined data and logic templates. - - `Managers/` – Ready-to-use manager classes. - - `Presets/` – Resource and pooling presets (PoolAsset, ResourceAsset, Task). - - `Services/` – Prebuilt services and systems. - -- **Toolkit/** - - `Ability/` – Ability system and samples. - - `Actor/` – Actor handling and lifecycle logic. - - `CSVFile/` – CSV parsing and data import tools. - - `CurveViewer/` – Editor curve visualization. - - `Interaction/` – Interaction handling system. - - `Inventory/` – Inventory architecture. - - `PCG/` – Procedural generation tools and resources. - - `Pickup/` – Item pickup logic. - - `RPG/` – RPG systems (Resource, StatSystem). - - `Tutorial/` – Tutorial system and utilities. - - `Upgrade/` – Upgrade and progression tools. - ---- - -### 🛠️ Editor -Unity Editor extensions for all RealMethod layers. - -- **Core/** – Editor scripts for Architecture, Definitions, and Project Settings. -- **Library/** – Shared scripts, vendor tools, and utilities. -- **Pattern/** – Custom editors for data assets and managers. -- **ReadySet/** – Editor tools for content setup and asset generation. -- **Toolkit/** – Editors for gameplay systems (Ability, Inventory, TerrainTools, etc.). - ---- - -### 🧃 Reservoir -Central storage for framework assets. - -- `Icons/` – Organized icons for Core, Pattern, and Toolkit editors. -- `Prefabs/` – Prefab resources for samples and managers. -- `SceneTemplates/` – Example scenes for quick setup. -- `ScriptTemplates/` – Script templates for fast development. - ---- - -### 🧪 Samples~ -Example projects demonstrating **PopupMessage** and **Tutorial** systems. - ---- - -### 🧠 Tests -Unit and integration tests for **General**, **Inspector**, and **ScenesDot** systems. +# RealMethod +**"`RealMethod` is a minimal, Unreal-inspired architecture for structuring Unity games with clear lifetime, ownership, and system boundaries."** +### Links +* [Documentation(Wiki)](https://github.com/AliJimpa/RealMethod/wiki/Home) +* [Video Tutorials]() +### The Pitch +`RealMethod` is a minimal architectural framework for Unity. It provides a small, explicit structure for organizing game lifetime, world context, and systems, inspired by **Unreal Engine** concepts such as `GameInstance` and `GameMode`. + +`RealMethod` is designed to help programmers build and maintain scalable Unity projects by enforcing clear ownership and predictable lifecycles. It favors simplicity and clarity over abstraction and avoids heavy frameworks, dependency injection containers, or hidden execution flows. `RealMethod` focuses on structure, not gameplay, and does not attempt to replace Unity workflows. + +`RealMethod` is particularly suited for games and real-time applications where long-term maintainability matters: indie and studio projects, system-heavy games, tool-driven workflows, and projects that must evolve over time without architectural collapse. +* Clear ownership and responsibility +* Unreal-like mental model for Unity +* Minimal core, flexible edges +* Scales from small games +* experimental for productions +* Team-friendly and testable architecture +### Quick Setup +Install via Unity Package Manager: +1. Open Package Manager +2. Click Add package from Git URL +3. Paste +>https://github.com/AliJimpa/RealMethod.git +4. Follow the Getting Started guide +>https://github.com/AliJimpa/RealMethod/wiki/Quick-Setup +### Gallery +Examples projects using RealMethod: [Death Pulse](https://github.com/wolfpld/tracy](https://cafebazaar.ir/app/com.Mustard.DeathPulse?l=en)), [Crush Conquest](https://cafebazaar.ir/app/com.Mustard.CrushConquest?l=en), [HeardSpoken]() and [Fireball](). + +| | | +|--|--| +|
![Crush Conquest](https://s.cafebazaar.ir/images/icons/com.Mustard.CrushConquest-7bbd0921-42dc-4c79-8676-5a51a79bc6e4_512x512.png?x-img=v1/format,type_webp,lossless_false/resize,h_256,w_256,lossless_false/optimize) |
![Death Pulse](https://s.cafebazaar.ir/images/icons/com.Mustard.DeathPulse-eb40fcf1-095b-4619-97d5-527a7a86dc4f_512x512.png?x-img=v1/format,type_webp,lossless_false/resize,h_256,w_256,lossless_false/optimize) | diff --git a/Reservoir/ScriptTemplates/CompileRuleTemplate.txt b/Reservoir/ScriptTemplates/CompileRuleTemplate.txt new file mode 100644 index 00000000..73e984b9 --- /dev/null +++ b/Reservoir/ScriptTemplates/CompileRuleTemplate.txt @@ -0,0 +1,33 @@ +using System; +using RealMethod.Editor; +using UnityEngine; + +public class #SCRIPTNAME# : CompileRule +{ + // CompileRule Methods + protected override void Initilized() + { + // Called right after Construct + } + public override void OnStartCheck(RuleExecutionMode mode) + { + // Called once per mode befor any cheking. + } + public override bool CanCheck(RuleExecutionMode mode, Type type) + { + // A Type that all target classes must derive from + if (mode == RuleExecutionMode.AfterCompilation) + { + return type.IsSubclassOf(typeof(????)); + } + else + { + // Skip other mode + return false; + } + } + public override void OnCheck(Type type) + { + // Called when CanCheck was true. + } +} diff --git a/Reservoir/ScriptTemplates/CompileRuleTemplate.txt.meta b/Reservoir/ScriptTemplates/CompileRuleTemplate.txt.meta new file mode 100644 index 00000000..07c8093c --- /dev/null +++ b/Reservoir/ScriptTemplates/CompileRuleTemplate.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ff50126801b38d34db2274c3060c4695 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Reservoir/ScriptTemplates/CompositManagerTemplate.txt b/Reservoir/ScriptTemplates/CompositManagerTemplate.txt deleted file mode 100644 index 753502e6..00000000 --- a/Reservoir/ScriptTemplates/CompositManagerTemplate.txt +++ /dev/null @@ -1,65 +0,0 @@ -using RealMethod; - -public class #SCRIPTNAME# : CompositManager -{ - [Header("Music")] - [SerializeField] - private AudioClip[] CreateLayers; - [SerializeField] - private bool AddServiceOnInitiate = false; - - protected override void OnInitiate(bool AlwaysLoaded) - { - foreach (var clip in CreateLayers) - { - CreateLayer(clip); - } - if (AddServiceOnInitiate) - Game.AddService(this); - } - protected override void MusicStateAssigned() - { - } -} - -public enum MUSCIENUM -{ - Default, - STATE_1, - STATE_2, -} - -public sealed class STATESETVICE : StateService -{ - public MUSCIENUM() : base(MUSCIENUM.Default) // This is the First State Value - { - - } - - // Service Methods - protected override void OnStart(object Author) - { - } - protected override void OnEnd(object Author) - { - - } - - // StateService Methods - protected override DefaulMusicLayer DefaultState() - { - return DefaulMusicLayer.Default; - } - public override bool CanSwitch(DefaulMusicLayer A, DefaulMusicLayer B) - { - if (A == B) - { - return false; - } - return true; - } - protected override bool CanResetforNewWorld(World NewWorld) - { - return false; - } -} \ No newline at end of file diff --git a/Reservoir/ScriptTemplates/Core.meta b/Reservoir/ScriptTemplates/Core.meta new file mode 100644 index 00000000..92623ef3 --- /dev/null +++ b/Reservoir/ScriptTemplates/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d66d434cac454c34f823e1a3cea9a39e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Reservoir/ScriptTemplates/Core/CloneAssetTemplate.txt b/Reservoir/ScriptTemplates/Core/CloneAssetTemplate.txt new file mode 100644 index 00000000..9c24adb7 --- /dev/null +++ b/Reservoir/ScriptTemplates/Core/CloneAssetTemplate.txt @@ -0,0 +1,7 @@ +using UnityEngine; +using RealMethod; + +[CreateAssetMenu(fileName = "#SCRIPTNAME#", menuName = "#PROJECTNAME#/#SCRIPTNAME#", order = 1)] +public class #SCRIPTNAME# : CloneAsset +{ +} \ No newline at end of file diff --git a/Reservoir/ScriptTemplates/Core/CloneAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/CloneAssetTemplate.txt.meta new file mode 100644 index 00000000..e5b5e0fe --- /dev/null +++ b/Reservoir/ScriptTemplates/Core/CloneAssetTemplate.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 22f923a8fe4c59b4baca28070f31141c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Reservoir/ScriptTemplates/ConfigAssetTemplate.txt b/Reservoir/ScriptTemplates/Core/ConfigAssetTemplate.txt similarity index 58% rename from Reservoir/ScriptTemplates/ConfigAssetTemplate.txt rename to Reservoir/ScriptTemplates/Core/ConfigAssetTemplate.txt index 42a4a16f..397f8885 100644 --- a/Reservoir/ScriptTemplates/ConfigAssetTemplate.txt +++ b/Reservoir/ScriptTemplates/Core/ConfigAssetTemplate.txt @@ -4,10 +4,4 @@ using RealMethod; [CreateAssetMenu(fileName = "#SCRIPTNAME#", menuName = "#PROJECTNAME#/#SCRIPTNAME#", order = 1)] public class #SCRIPTNAME# : ConfigAsset { - #if UNITY_EDITOR - // public override void OnEditorPlay() - // { - // base.OnEditorPlay(); - // } - #endif } diff --git a/Reservoir/ScriptTemplates/ConfigAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/ConfigAssetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/ConfigAssetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Core/ConfigAssetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/DataAssetTemplate.txt b/Reservoir/ScriptTemplates/Core/DataAssetTemplate.txt similarity index 58% rename from Reservoir/ScriptTemplates/DataAssetTemplate.txt rename to Reservoir/ScriptTemplates/Core/DataAssetTemplate.txt index 2b4c0cc6..895c8cc7 100644 --- a/Reservoir/ScriptTemplates/DataAssetTemplate.txt +++ b/Reservoir/ScriptTemplates/Core/DataAssetTemplate.txt @@ -4,10 +4,4 @@ using RealMethod; [CreateAssetMenu(fileName = "#SCRIPTNAME#", menuName = "#PROJECTNAME#/#SCRIPTNAME#", order = 1)] public class #SCRIPTNAME# : DataAsset { - #if UNITY_EDITOR - // public override void OnEditorPlay() - // { - // base.OnEditorPlay(); - // } - #endif } \ No newline at end of file diff --git a/Reservoir/ScriptTemplates/DataAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/DataAssetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/DataAssetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Core/DataAssetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Core/GameBridgeTemplate.txt b/Reservoir/ScriptTemplates/Core/GameBridgeTemplate.txt new file mode 100644 index 00000000..fabf4ee5 --- /dev/null +++ b/Reservoir/ScriptTemplates/Core/GameBridgeTemplate.txt @@ -0,0 +1,5 @@ +using RealMethod; + +public class #SCRIPTNAME# : GameBridge +{ +} diff --git a/Reservoir/ScriptTemplates/GameServiceTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/GameBridgeTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/GameServiceTemplate.txt.meta rename to Reservoir/ScriptTemplates/Core/GameBridgeTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/GameConfigTemplate.txt b/Reservoir/ScriptTemplates/Core/GameConfigTemplate.txt similarity index 75% rename from Reservoir/ScriptTemplates/GameConfigTemplate.txt rename to Reservoir/ScriptTemplates/Core/GameConfigTemplate.txt index 7e7ae088..bca67f27 100644 --- a/Reservoir/ScriptTemplates/GameConfigTemplate.txt +++ b/Reservoir/ScriptTemplates/Core/GameConfigTemplate.txt @@ -4,8 +4,9 @@ using RealMethod; [CreateAssetMenu(fileName = "#SCRIPTNAME#", menuName = "#PROJECTNAME#/#SCRIPTNAME#", order = 1)] public class #SCRIPTNAME# : GameConfig { - // Base GameSettingAsset Methods + // GameConfig Methods public override void Initialized(Game Author) { + // Called after load in Game by GameClass } } diff --git a/Reservoir/ScriptTemplates/GameConfigTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/GameConfigTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/GameConfigTemplate.txt.meta rename to Reservoir/ScriptTemplates/Core/GameConfigTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Core/GameTemplate.txt b/Reservoir/ScriptTemplates/Core/GameTemplate.txt new file mode 100644 index 00000000..69ff4ff2 --- /dev/null +++ b/Reservoir/ScriptTemplates/Core/GameTemplate.txt @@ -0,0 +1,39 @@ +using RealMethod; + +public class #SCRIPTNAME# : Game +{ + + // Game Methods + protected override void OnGameOpen() + { + // Invoked when starting up the runtime. Called before the first scene is loaded. + // Called when game run in platform befor any scene loaded or even splash screen + // In this stage your game component just created. + } + protected override void OnGameInitialized() + { + // Invoked when the first scene's objects are loaded into memory but before Awake has been called. + // Called right after Unity finishes loading the engine before any scene or subsystem is loaded. + // You can insure when called that GameBridge , GameConfig and all Managers in GameScope Initilized. + } + protected override void OnGameStart() + { + // Invoked when the first scene's objects are loaded into memory but before Awake has been called. + // Called after Unity finishes initializing the engine, but before the first scene is loaded. + // It’s guaranteed to execute before any Awake() or Start() in your scene objects. + } + protected override void OnWorldChanged(World NewWorld) + { + // Called when each World Initialized + // You can insure the Game.world refrence is valid + // Note: if you use world in scene and load scene as additive not OpenScen() that world didnt connect to Game and removed by Main World class (more= GameBridge) + } + protected override void OnGameClosed() + { + // Called when application start exit + // You can insure this called befor and object destroy in scene (yes befor) + } + + + +} diff --git a/Reservoir/ScriptTemplates/GameTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/GameTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/GameTemplate.txt.meta rename to Reservoir/ScriptTemplates/Core/GameTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Core/ManagerTemplate.txt b/Reservoir/ScriptTemplates/Core/ManagerTemplate.txt new file mode 100644 index 00000000..83cef781 --- /dev/null +++ b/Reservoir/ScriptTemplates/Core/ManagerTemplate.txt @@ -0,0 +1,15 @@ +using UnityEngine; +using RealMethod; + +public class #SCRIPTNAME# : MonoBehaviour, IGameManager +{ + // Implement IGameManage Interface + MonoBehaviour IGameManager.GetManagerClass() => this; + void IGameManager.InitiateManager(Scope owner) + { + // Called Just Once Befor any Awake called + // Called when World or Game initializing + // Owner means your manager initialize in GameScope(always valid) or World Scope(destroy after change World) + } + +} diff --git a/Reservoir/ScriptTemplates/ManagerTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/ManagerTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/ManagerTemplate.txt.meta rename to Reservoir/ScriptTemplates/Core/ManagerTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Core/ServiceTemplate.txt b/Reservoir/ScriptTemplates/Core/ServiceTemplate.txt new file mode 100644 index 00000000..a71c6c14 --- /dev/null +++ b/Reservoir/ScriptTemplates/Core/ServiceTemplate.txt @@ -0,0 +1,22 @@ +using RealMethod; + +public class #SCRIPTNAME# : Service +{ + + // Service Methods + protected override void OnStart(object Author) + { + // Called right after Construct and stored in Game + // Called befor any Manager Know this Service Created + } + protected override void OnNewWorld() + { + // Called after each World Initialized + } + protected override void OnEnd(object Author) + { + // Called befor Destroyed. + // Called after all Manager know this Service going to Destroyed + } + +} diff --git a/Reservoir/ScriptTemplates/ServiceTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/ServiceTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/ServiceTemplate.txt.meta rename to Reservoir/ScriptTemplates/Core/ServiceTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/UniqueAssetTemplate.txt b/Reservoir/ScriptTemplates/Core/UniqueAssetTemplate.txt similarity index 58% rename from Reservoir/ScriptTemplates/UniqueAssetTemplate.txt rename to Reservoir/ScriptTemplates/Core/UniqueAssetTemplate.txt index 85899e0d..c5f53889 100644 --- a/Reservoir/ScriptTemplates/UniqueAssetTemplate.txt +++ b/Reservoir/ScriptTemplates/Core/UniqueAssetTemplate.txt @@ -4,10 +4,4 @@ using RealMethod; [CreateAssetMenu(fileName = "#SCRIPTNAME#", menuName = "#PROJECTNAME#/#SCRIPTNAME#", order = 1)] public class #SCRIPTNAME# : UniqueAsset { - #if UNITY_EDITOR - // public override void OnEditorPlay() - // { - // base.OnEditorPlay(); - // } - #endif } diff --git a/Reservoir/ScriptTemplates/UniqueAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/UniqueAssetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/UniqueAssetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Core/UniqueAssetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Core/WorldTemplate.txt b/Reservoir/ScriptTemplates/Core/WorldTemplate.txt new file mode 100644 index 00000000..e81b1750 --- /dev/null +++ b/Reservoir/ScriptTemplates/Core/WorldTemplate.txt @@ -0,0 +1,17 @@ +using RealMethod; + +public class #SCRIPTNAME# : World +{ + // World Methods + protected override void WorldBegin() + { + // When World Awake + // Called befor awake and befor any Monobehaviort in Scene (by executionorder) + // You can insure your world is connect to game class and all Manager Initilize & Player Selected or Spawn in Scene + } + protected override void WorldEnd() + { + // When World Destroy + } + +} diff --git a/Reservoir/ScriptTemplates/WorldTemplate.txt.meta b/Reservoir/ScriptTemplates/Core/WorldTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/WorldTemplate.txt.meta rename to Reservoir/ScriptTemplates/Core/WorldTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/DataManagerTemplate.txt b/Reservoir/ScriptTemplates/DataManagerTemplate.txt deleted file mode 100644 index 9991f8e0..00000000 --- a/Reservoir/ScriptTemplates/DataManagerTemplate.txt +++ /dev/null @@ -1,28 +0,0 @@ -using RealMethod; - -public class #SCRIPTNAME# : DataManager -{ - - // Base DataManager Methods - protected override void ResolveService(Service service, bool active) - { - throw new System.NotImplementedException(); - } - protected override void OnSaveFile(SaveFile targetfile) - { - throw new System.NotImplementedException(); - } - protected override void OnLoadFile(SaveFile targetfile) - { - throw new System.NotImplementedException(); - } - protected override void OnDelete(SaveFile targetfile) - { - throw new System.NotImplementedException(); - } - protected override bool IsExist(SaveFile targetfile) - { - throw new System.NotImplementedException(); - } - -} diff --git a/Reservoir/ScriptTemplates/GameServiceTemplate.txt b/Reservoir/ScriptTemplates/GameServiceTemplate.txt deleted file mode 100644 index f2476d26..00000000 --- a/Reservoir/ScriptTemplates/GameServiceTemplate.txt +++ /dev/null @@ -1,24 +0,0 @@ -using RealMethod; - -public class #SCRIPTNAME# : GameService -{ - // Base Service Methods - protected override void OnStart(object Author) { } - protected override void OnNewWorld() { } - protected override void OnNewAdditiveWorld(World target) { } - protected override void OnEnd(object Author) { } - - // GameService Virtual Methods - // public override IEnumerator GetLoadScneCorotine(SceneReference TargetScene) - // { - // return base.GetLoadScneCorotine(); - // } - // public override IEnumerator GetLoadWorldCorotine(WorldSceneConfig WorldScene) - // { - // return base.GetLoadWorldCorotine(); - // } - // public override IEnumerator GetReloadSWCorotine() - // { - // return base.GetReloadSWCorotine(); - // } -} diff --git a/Reservoir/ScriptTemplates/GameTemplate.txt b/Reservoir/ScriptTemplates/GameTemplate.txt deleted file mode 100644 index de24ed55..00000000 --- a/Reservoir/ScriptTemplates/GameTemplate.txt +++ /dev/null @@ -1,22 +0,0 @@ -using RealMethod; - -public class #SCRIPTNAME# : Game -{ - - // Base Game Methods - protected override void GameInitialized() - { - } - protected override void GameStarted() - { - } - protected override void GameWorldSynced(World NewWorld) - { - } - protected override void GameClosed() - { - } - - - -} diff --git a/Reservoir/ScriptTemplates/ItemAssetTemplate.txt b/Reservoir/ScriptTemplates/ItemAssetTemplate.txt deleted file mode 100644 index c1c8d60b..00000000 --- a/Reservoir/ScriptTemplates/ItemAssetTemplate.txt +++ /dev/null @@ -1,13 +0,0 @@ -using UnityEngine; -using RealMethod; - -[CreateAssetMenu(fileName = "#SCRIPTNAME#", menuName = "#PROJECTNAME#/#SCRIPTNAME#", order = 1)] -public class #SCRIPTNAME# : ItemAsset -{ - #if UNITY_EDITOR - // public override void OnEditorPlay() - // { - // base.OnEditorPlay(); - // } - #endif -} diff --git a/Reservoir/ScriptTemplates/ManagerTemplate.txt b/Reservoir/ScriptTemplates/ManagerTemplate.txt deleted file mode 100644 index c3ad458f..00000000 --- a/Reservoir/ScriptTemplates/ManagerTemplate.txt +++ /dev/null @@ -1,21 +0,0 @@ -using UnityEngine; -using RealMethod; - -public class #SCRIPTNAME# : MonoBehaviour, IGameManager -{ - - // Implement IGameManage Methods - MonoBehaviour IGameManager.GetManagerClass() - { - return this; - } - void IGameManager.InitiateManager(bool AlwaysLoaded) - { - throw new System.NotImplementedException(); - } - void IGameManager.ResolveService(Service service, bool active) - { - throw new System.NotImplementedException(); - } - -} diff --git a/Reservoir/ScriptTemplates/MixerManagerTemplate.txt b/Reservoir/ScriptTemplates/MixerManagerTemplate.txt deleted file mode 100644 index 0d2d04b2..00000000 --- a/Reservoir/ScriptTemplates/MixerManagerTemplate.txt +++ /dev/null @@ -1,16 +0,0 @@ -using RealMethod; - -public class #SCRIPTNAME# : MixerManager -{ - - // Implement IGameManage Methods - protected override void InitiateManager(bool AlwaysLoaded) - { - throw new System.NotImplementedException(); - } - protected override void ResolveService(Service service, bool active) - { - throw new System.NotImplementedException(); - } - -} diff --git a/Reservoir/ScriptTemplates/Pattern.meta b/Reservoir/ScriptTemplates/Pattern.meta new file mode 100644 index 00000000..65b0d77c --- /dev/null +++ b/Reservoir/ScriptTemplates/Pattern.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bbc5ddc017cc6cf43a5f82f18222a728 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Reservoir/ScriptTemplates/AudioManagerTemplater.txt b/Reservoir/ScriptTemplates/Pattern/AudioManagerTemplate.txt similarity index 96% rename from Reservoir/ScriptTemplates/AudioManagerTemplater.txt rename to Reservoir/ScriptTemplates/Pattern/AudioManagerTemplate.txt index 21601618..b3e80db4 100644 --- a/Reservoir/ScriptTemplates/AudioManagerTemplater.txt +++ b/Reservoir/ScriptTemplates/Pattern/AudioManagerTemplate.txt @@ -2,6 +2,4 @@ using RealMethod; public class #SCRIPTNAME# : AudioManager { - - } diff --git a/Reservoir/ScriptTemplates/AudioManagerTemplater.txt.meta b/Reservoir/ScriptTemplates/Pattern/AudioManagerTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/AudioManagerTemplater.txt.meta rename to Reservoir/ScriptTemplates/Pattern/AudioManagerTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/CommandTemplate.txt b/Reservoir/ScriptTemplates/Pattern/CommandTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/CommandTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/CommandTemplate.txt diff --git a/Reservoir/ScriptTemplates/CommandTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/CommandTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/CommandTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/CommandTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Pattern/CompositManagerTemplate.txt b/Reservoir/ScriptTemplates/Pattern/CompositManagerTemplate.txt new file mode 100644 index 00000000..3d54e3bd --- /dev/null +++ b/Reservoir/ScriptTemplates/Pattern/CompositManagerTemplate.txt @@ -0,0 +1,23 @@ +using RealMethod; + +public class #SCRIPTNAME# : CompositManager +{ + [Header("MusicList")] + [SerializeField] + private Map Clips = new Map(); + + // IGameManager Interface + protected override void InitiateManager(Scope owner) + { + base.InitiateManager(owner); + foreach (var clip in Clips) + { + CreateLayer(clip.Key, clip.Value); + } + } + + protected override bool CompairStates(MUSCIENUM State_A, MUSCIENUM State_B) + { + return State_A == State_B; + } +} \ No newline at end of file diff --git a/Reservoir/ScriptTemplates/CompositManagerTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/CompositManagerTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/CompositManagerTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/CompositManagerTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/FileAssetTemplate.txt b/Reservoir/ScriptTemplates/Pattern/FileAssetTemplate.txt similarity index 58% rename from Reservoir/ScriptTemplates/FileAssetTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/FileAssetTemplate.txt index be13179c..61eaebc6 100644 --- a/Reservoir/ScriptTemplates/FileAssetTemplate.txt +++ b/Reservoir/ScriptTemplates/Pattern/FileAssetTemplate.txt @@ -4,10 +4,4 @@ using RealMethod; [CreateAssetMenu(fileName = "#SCRIPTNAME#", menuName = "#PROJECTNAME#/#SCRIPTNAME#", order = 1)] public class #SCRIPTNAME# : FileAsset { - #if UNITY_EDITOR - // public override void OnEditorPlay() - // { - // base.OnEditorPlay(); - // } - #endif } diff --git a/Reservoir/ScriptTemplates/FileAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/FileAssetTemplate.txt.meta similarity index 75% rename from Reservoir/ScriptTemplates/FileAssetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/FileAssetTemplate.txt.meta index c2f1e25a..375ee173 100644 --- a/Reservoir/ScriptTemplates/FileAssetTemplate.txt.meta +++ b/Reservoir/ScriptTemplates/Pattern/FileAssetTemplate.txt.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4744f0022d011cf44a0b25e6e9f8cd79 +guid: 939c3f2e8c0d6a347a60d9b6a104ed73 TextScriptImporter: externalObjects: {} userData: diff --git a/Reservoir/ScriptTemplates/GameSettingFileTemplate.txt b/Reservoir/ScriptTemplates/Pattern/GameSettingFileTemplate.txt similarity index 91% rename from Reservoir/ScriptTemplates/GameSettingFileTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/GameSettingFileTemplate.txt index 5a0d620f..e749ac6b 100644 --- a/Reservoir/ScriptTemplates/GameSettingFileTemplate.txt +++ b/Reservoir/ScriptTemplates/Pattern/GameSettingFileTemplate.txt @@ -5,7 +5,7 @@ using UnityEngine; public class #SCRIPTNAME# : SettingFile { // SaveFile Methods - protected override void OnStable(DataManager manager){} + protected override void OnStable(SaveManager manager){} protected override void OnLoaded(){} protected override void OnDeleted(){} diff --git a/Reservoir/ScriptTemplates/GameSettingFileTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/GameSettingFileTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/GameSettingFileTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/GameSettingFileTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/GizmoManagerTemplate.txt b/Reservoir/ScriptTemplates/Pattern/GizmoManagerTemplate.txt similarity index 51% rename from Reservoir/ScriptTemplates/GizmoManagerTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/GizmoManagerTemplate.txt index 546c370d..4653ff1e 100644 --- a/Reservoir/ScriptTemplates/GizmoManagerTemplate.txt +++ b/Reservoir/ScriptTemplates/Pattern/GizmoManagerTemplate.txt @@ -2,14 +2,10 @@ using RealMethod; public class #SCRIPTNAME# : GizmoManager { - // Base DataManager Methods + // Base SaveManager Methods protected override GUIRenderer[] GetRenderSlots() { throw new System.NotImplementedException(); } - protected override void ResolveService(Service service, bool active) - { - throw new System.NotImplementedException(); - } } diff --git a/Reservoir/ScriptTemplates/GizmoManagerTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/GizmoManagerTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/GizmoManagerTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/GizmoManagerTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/HapticConfigTemplate.txt b/Reservoir/ScriptTemplates/Pattern/HapticConfigTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/HapticConfigTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/HapticConfigTemplate.txt diff --git a/Reservoir/ScriptTemplates/HapticConfigTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/HapticConfigTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/HapticConfigTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/HapticConfigTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/ItemConfigTemplate.txt b/Reservoir/ScriptTemplates/Pattern/ItemConfigTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/ItemConfigTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/ItemConfigTemplate.txt diff --git a/Reservoir/ScriptTemplates/ItemConfigTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/ItemConfigTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/ItemConfigTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/ItemConfigTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Pattern/MixerManagerTemplate.txt b/Reservoir/ScriptTemplates/Pattern/MixerManagerTemplate.txt new file mode 100644 index 00000000..b044190e --- /dev/null +++ b/Reservoir/ScriptTemplates/Pattern/MixerManagerTemplate.txt @@ -0,0 +1,12 @@ +using RealMethod; + +public class #SCRIPTNAME# : MixerManager +{ + + // Implement IGameManage Methods + protected override void InitiateManager(Scope owner) + { + throw new System.NotImplementedException(); + } + +} diff --git a/Reservoir/ScriptTemplates/MixerManagerTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/MixerManagerTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/MixerManagerTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/MixerManagerTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/PoolAssetTemplate.txt b/Reservoir/ScriptTemplates/Pattern/PoolAssetTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/PoolAssetTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/PoolAssetTemplate.txt diff --git a/Reservoir/ScriptTemplates/PoolAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/PoolAssetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/PoolAssetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/PoolAssetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/SaveFileTemplate.txt b/Reservoir/ScriptTemplates/Pattern/SaveFileTemplate.txt similarity index 71% rename from Reservoir/ScriptTemplates/SaveFileTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/SaveFileTemplate.txt index 7631c755..84f31a95 100644 --- a/Reservoir/ScriptTemplates/SaveFileTemplate.txt +++ b/Reservoir/ScriptTemplates/Pattern/SaveFileTemplate.txt @@ -5,16 +5,10 @@ using UnityEngine; public class #SCRIPTNAME# : SaveFile { // SaveFile Method - protected override void OnStable(DataManager manager) - { - } protected override void OnSaved() { } protected override void OnLoaded() { } - protected override void OnDeleted() - { - } } diff --git a/Reservoir/ScriptTemplates/SaveFileTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/SaveFileTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/SaveFileTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/SaveFileTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Pattern/SaveManagerTemplate.txt b/Reservoir/ScriptTemplates/Pattern/SaveManagerTemplate.txt new file mode 100644 index 00000000..7a70b659 --- /dev/null +++ b/Reservoir/ScriptTemplates/Pattern/SaveManagerTemplate.txt @@ -0,0 +1,6 @@ +using RealMethod; + +public class #SCRIPTNAME# : SaveMethodManager +{ + +} diff --git a/Reservoir/ScriptTemplates/DataManagerTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/SaveManagerTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/DataManagerTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/SaveManagerTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/SharedRootAssetTemplate.txt b/Reservoir/ScriptTemplates/Pattern/SharedRootAssetTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/SharedRootAssetTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/SharedRootAssetTemplate.txt diff --git a/Reservoir/ScriptTemplates/SharedRootAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/SharedRootAssetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/SharedRootAssetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/SharedRootAssetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/TableTemplate.txt b/Reservoir/ScriptTemplates/Pattern/TableAssetTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/TableTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/TableAssetTemplate.txt diff --git a/Reservoir/ScriptTemplates/TableTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/TableAssetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/TableTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/TableAssetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/TaskAssetTemplate.txt b/Reservoir/ScriptTemplates/Pattern/TaskAssetTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/TaskAssetTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/TaskAssetTemplate.txt diff --git a/Reservoir/ScriptTemplates/TaskAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/TaskAssetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/TaskAssetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/TaskAssetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/TickManagerTemplate.txt b/Reservoir/ScriptTemplates/Pattern/TickManagerTemplate.txt similarity index 55% rename from Reservoir/ScriptTemplates/TickManagerTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/TickManagerTemplate.txt index 1a7ab79d..72e4e8a1 100644 --- a/Reservoir/ScriptTemplates/TickManagerTemplate.txt +++ b/Reservoir/ScriptTemplates/Pattern/TickManagerTemplate.txt @@ -4,13 +4,9 @@ public class #SCRIPTNAME# : TickManager { // TickManager Methods - protected override void InitiateManager(bool alwaysLoaded) + protected override void InitiateManager(Scope owner) { - } - protected override void ResolveService(Service service, bool active) - { - } protected override bool CheckUnit(T unit) { diff --git a/Reservoir/ScriptTemplates/TickManagerTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/TickManagerTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/TickManagerTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/TickManagerTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Trigger2DTemplate.txt b/Reservoir/ScriptTemplates/Pattern/Trigger2DTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/Trigger2DTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/Trigger2DTemplate.txt diff --git a/Reservoir/ScriptTemplates/Trigger2DTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/Trigger2DTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/Trigger2DTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/Trigger2DTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Trigger3DTemplate.txt b/Reservoir/ScriptTemplates/Pattern/Trigger3DTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/Trigger3DTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/Trigger3DTemplate.txt diff --git a/Reservoir/ScriptTemplates/Trigger3DTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/Trigger3DTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/Trigger3DTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/Trigger3DTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Pattern/UIManagerTemplate.txt b/Reservoir/ScriptTemplates/Pattern/UIManagerTemplate.txt new file mode 100644 index 00000000..33137c4e --- /dev/null +++ b/Reservoir/ScriptTemplates/Pattern/UIManagerTemplate.txt @@ -0,0 +1,12 @@ +using RealMethod; + +public class #SCRIPTNAME# : UIManager +{ + + // UIManager Methods + protected override void InitiateManager(Scope owner) + { + + } + +} diff --git a/Reservoir/ScriptTemplates/UIManagerTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/UIManagerTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/UIManagerTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/UIManagerTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/WidgetTemplate.txt b/Reservoir/ScriptTemplates/Pattern/WidgetTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/WidgetTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/WidgetTemplate.txt diff --git a/Reservoir/ScriptTemplates/WidgetTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/WidgetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/WidgetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/WidgetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/WidgetToolkitTemplate.txt b/Reservoir/ScriptTemplates/Pattern/WidgetToolkitTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/WidgetToolkitTemplate.txt rename to Reservoir/ScriptTemplates/Pattern/WidgetToolkitTemplate.txt diff --git a/Reservoir/ScriptTemplates/WidgetToolkitTemplate.txt.meta b/Reservoir/ScriptTemplates/Pattern/WidgetToolkitTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/WidgetToolkitTemplate.txt.meta rename to Reservoir/ScriptTemplates/Pattern/WidgetToolkitTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/ServiceTemplate.txt b/Reservoir/ScriptTemplates/ServiceTemplate.txt deleted file mode 100644 index 2f895170..00000000 --- a/Reservoir/ScriptTemplates/ServiceTemplate.txt +++ /dev/null @@ -1,17 +0,0 @@ -using RealMethod; - -public class #SCRIPTNAME# : Service -{ - - // Service Methods - protected override void OnStart(object Author) - { - } - protected override void OnNewWorld() - { - } - protected override void OnEnd(object Author) - { - } - -} diff --git a/Reservoir/ScriptTemplates/Toolkit.meta b/Reservoir/ScriptTemplates/Toolkit.meta new file mode 100644 index 00000000..efa985c2 --- /dev/null +++ b/Reservoir/ScriptTemplates/Toolkit.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 002acfcd71cdf2e45a91d3a78b0c40a0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Reservoir/ScriptTemplates/AbilityActionAssetTemplate.txt b/Reservoir/ScriptTemplates/Toolkit/AbilityActionAssetTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/AbilityActionAssetTemplate.txt rename to Reservoir/ScriptTemplates/Toolkit/AbilityActionAssetTemplate.txt diff --git a/Reservoir/ScriptTemplates/AbilityActionAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/AbilityActionAssetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/AbilityActionAssetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/AbilityActionAssetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/AbilityAssetTemplate.txt b/Reservoir/ScriptTemplates/Toolkit/AbilityAssetTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/AbilityAssetTemplate.txt rename to Reservoir/ScriptTemplates/Toolkit/AbilityAssetTemplate.txt diff --git a/Reservoir/ScriptTemplates/AbilityAssetTemplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/AbilityAssetTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/AbilityAssetTemplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/AbilityAssetTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/AbilityEffectTemplate.txt b/Reservoir/ScriptTemplates/Toolkit/AbilityEffectTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/AbilityEffectTemplate.txt rename to Reservoir/ScriptTemplates/Toolkit/AbilityEffectTemplate.txt diff --git a/Reservoir/ScriptTemplates/AbilityEffectTemplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/AbilityEffectTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/AbilityEffectTemplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/AbilityEffectTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/BuffConfigTemplate.txt b/Reservoir/ScriptTemplates/Toolkit/BuffConfigTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/BuffConfigTemplate.txt rename to Reservoir/ScriptTemplates/Toolkit/BuffConfigTemplate.txt diff --git a/Reservoir/ScriptTemplates/BuffConfigTemplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/BuffConfigTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/BuffConfigTemplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/BuffConfigTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/InventoryItemTemplate.txt b/Reservoir/ScriptTemplates/Toolkit/InventoryItemTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/InventoryItemTemplate.txt rename to Reservoir/ScriptTemplates/Toolkit/InventoryItemTemplate.txt diff --git a/Reservoir/ScriptTemplates/InventoryItemTemplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/InventoryItemTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/InventoryItemTemplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/InventoryItemTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/PCGRequestTamplate.txt b/Reservoir/ScriptTemplates/Toolkit/PCGRequestTamplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/PCGRequestTamplate.txt rename to Reservoir/ScriptTemplates/Toolkit/PCGRequestTamplate.txt diff --git a/Reservoir/ScriptTemplates/PCGRequestTamplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/PCGRequestTamplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/PCGRequestTamplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/PCGRequestTamplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Pickup2DTemplate.txt b/Reservoir/ScriptTemplates/Toolkit/Pickup2DTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/Pickup2DTemplate.txt rename to Reservoir/ScriptTemplates/Toolkit/Pickup2DTemplate.txt diff --git a/Reservoir/ScriptTemplates/Pickup2DTemplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/Pickup2DTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/Pickup2DTemplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/Pickup2DTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/Pickup3DTemplate.txt b/Reservoir/ScriptTemplates/Toolkit/Pickup3DTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/Pickup3DTemplate.txt rename to Reservoir/ScriptTemplates/Toolkit/Pickup3DTemplate.txt diff --git a/Reservoir/ScriptTemplates/Pickup3DTemplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/Pickup3DTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/Pickup3DTemplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/Pickup3DTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/UpgradeConfigTemplate.txt b/Reservoir/ScriptTemplates/Toolkit/UpgradeConfigTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/UpgradeConfigTemplate.txt rename to Reservoir/ScriptTemplates/Toolkit/UpgradeConfigTemplate.txt diff --git a/Reservoir/ScriptTemplates/UpgradeConfigTemplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/UpgradeConfigTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/UpgradeConfigTemplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/UpgradeConfigTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/UpgradeItemTemplate.txt b/Reservoir/ScriptTemplates/Toolkit/UpgradeItemTemplate.txt similarity index 100% rename from Reservoir/ScriptTemplates/UpgradeItemTemplate.txt rename to Reservoir/ScriptTemplates/Toolkit/UpgradeItemTemplate.txt diff --git a/Reservoir/ScriptTemplates/UpgradeItemTemplate.txt.meta b/Reservoir/ScriptTemplates/Toolkit/UpgradeItemTemplate.txt.meta similarity index 100% rename from Reservoir/ScriptTemplates/UpgradeItemTemplate.txt.meta rename to Reservoir/ScriptTemplates/Toolkit/UpgradeItemTemplate.txt.meta diff --git a/Reservoir/ScriptTemplates/UIManagerTemplate.txt b/Reservoir/ScriptTemplates/UIManagerTemplate.txt deleted file mode 100644 index e3274d33..00000000 --- a/Reservoir/ScriptTemplates/UIManagerTemplate.txt +++ /dev/null @@ -1,16 +0,0 @@ -using RealMethod; - -public class #SCRIPTNAME# : UIManager -{ - - // UIManager Methods - protected override void InitiateManager(bool alwaysLoaded) - { - - } - protected override void ResolveService(Service service, bool active) - { - - } - -} diff --git a/Reservoir/ScriptTemplates/WorldTemplate.txt b/Reservoir/ScriptTemplates/WorldTemplate.txt deleted file mode 100644 index 380a4323..00000000 --- a/Reservoir/ScriptTemplates/WorldTemplate.txt +++ /dev/null @@ -1,14 +0,0 @@ -using RealMethod; - -public class #SCRIPTNAME# : World -{ - - // World Methods - protected override void AwakeWorld() - { - } - protected override void DestroyWorld() - { - } - -} diff --git a/Runtime/Core/Architecture/EnumStorage.cs b/Runtime/Core/Architecture/EnumStorage.cs new file mode 100644 index 00000000..d2075042 --- /dev/null +++ b/Runtime/Core/Architecture/EnumStorage.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; + +namespace RealMethod +{ + public sealed class EnumStorage : IDisposable + { + private GlobalEnum _state; + private readonly Dictionary _values = new(); + /// + /// Invoked when game state changed. + /// + public event Action OnStateChanged; + + public GlobalEnum Global + { + get => _state; + set + { + if (_state == value) + return; + + var old = _state; + _state = value; + + OnStateChanged?.Invoke(old, _state); + } + } + + // Implement IDisposable Interface + void IDisposable.Dispose() + { + _values.Clear(); + } + + public void Set(T enumValue) where T : Enum + { + _values[typeof(T)] = Convert.ToByte(enumValue); + } + public T Get() where T : Enum + { + Type type = typeof(T); + + if (!_values.TryGetValue(type, out byte storedValue)) + { + storedValue = 0; + _values[type] = 0; + } + + return (T)Enum.ToObject(type, storedValue); + } + + + // -------- Operator Overloads -------- + public static implicit operator GlobalEnum(EnumStorage storage) + { + return storage.Global; + } + + public static implicit operator EnumStorage(GlobalEnum value) + { + return new EnumStorage { Global = value }; + } + + public static bool operator ==(EnumStorage a, GlobalEnum b) + => a is not null && a._state == b; + + public static bool operator !=(EnumStorage a, GlobalEnum b) + => !(a == b); + + public static bool operator <(EnumStorage a, GlobalEnum b) + => a is not null && a._state < b; + + public static bool operator >(EnumStorage a, GlobalEnum b) + => a is not null && a._state > b; + + public static bool operator <=(EnumStorage a, GlobalEnum b) + => a is not null && a._state <= b; + + public static bool operator >=(EnumStorage a, GlobalEnum b) + => a is not null && a._state >= b; + + public static bool operator ==(GlobalEnum a, EnumStorage b) + => b == a; + + public static bool operator !=(GlobalEnum a, EnumStorage b) + => !(b == a); + + public static bool operator <(GlobalEnum a, EnumStorage b) + => b is not null && a < b._state; + + public static bool operator >(GlobalEnum a, EnumStorage b) + => b is not null && a > b._state; + + public static bool operator <=(GlobalEnum a, EnumStorage b) + => b is not null && a <= b._state; + + public static bool operator >=(GlobalEnum a, EnumStorage b) + => b is not null && a >= b._state; + + // -------- Overrides -------- + + public override bool Equals(object obj) + { + if (obj is EnumStorage other) + return _state.Equals(other._state); + + if (obj is GlobalEnum e) + return _state.Equals(e); + + return false; + } + public override int GetHashCode() + { + return _state.GetHashCode(); + } + public override string ToString() + { + return _state.ToString(); + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Architecture/EnumStorage.cs.meta b/Runtime/Core/Architecture/EnumStorage.cs.meta new file mode 100644 index 00000000..6b5981d7 --- /dev/null +++ b/Runtime/Core/Architecture/EnumStorage.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 62bca4ee2575e6240a01e4f582caa5c8 \ No newline at end of file diff --git a/Runtime/Core/Architecture/Game.cs b/Runtime/Core/Architecture/Game.cs index 81997b3a..5167e80f 100644 --- a/Runtime/Core/Architecture/Game.cs +++ b/Runtime/Core/Architecture/Game.cs @@ -2,17 +2,43 @@ using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; -using System.Linq; + + +#if UNITY_EDITOR +using UnityEditor; +using UnityEditor.SceneManagement; +#endif namespace RealMethod { - public abstract class Game : MonoBehaviour + + /// + /// Core game singleton that manages the active , registered s, + /// configuration and high-level game lifecycle (initialization, start, and shutdown). + /// Derive from this class to implement project-specific behavior for the game's lifecycle hooks. + /// + public abstract class Game : Scope { - // Public Static Variables + /// + /// Singleton instance of the active game. + /// public static Game Instance; - public static GameConfig Config { get; private set; } + /// + /// The currently active . Updated when a world is initiated. + /// public static World World { get; private set; } - public static GameService Service { get; private set; } + /// + /// The core implementation used for scene/world loading and basic events. + /// + public static GameBridge Bridge { get; private set; } + /// + /// Active game configuration instance. + /// + public static GameConfig Config { get; private set; } + /// + /// Convenience property returning the player GameObject from the current . + /// Returns null and logs a warning if no world is set. + /// public static GameObject Player { get @@ -25,72 +51,210 @@ public static GameObject Player return World.GetPlayerObject(); } } - public static bool isPaused => Time.timeScale == 0; - - // Private Variable - private IGameManager[] Managers; - private List GameServices; - - // Public Functions - public T GetManager() where T : class + /// + /// Reperesent Game State that youser can define state in ProjectSetting + /// + public static readonly EnumStorage State = new EnumStorage(); + /// + /// Indicates whether a scene or world load operation is currently in progress. + /// + public static bool IsPaused { - foreach (var manager in Managers) + get { - if (manager.GetManagerClass() is T Result) + if (Instance != null) { - return Result; + return Instance.IsGamePaused(); + } + else + { + Debug.LogWarning("GameInstance did not called !"); + return false; } } - return null; } - public IGameManager GetManager(string ObjectName) + /// + /// Indicates whether the game is in loading stage + /// Return true when game in loading section for new scene + /// + public static bool IsLoading { - foreach (var manger in Managers) + get { - if (manger.GetManagerClass().gameObject.name == ObjectName) + if (Instance != null) { - return manger; + return Instance.IsGameLoading(); + } + else + { + Debug.LogWarning("GameInstance did not called !"); + return false; } } - return null; } - // Protected Functions - protected T NeedManager() where T : MonoBehaviour + /// + /// Indicate whether the game complitly initialized. + /// after true OnGameInitialized called. + /// befor first scene load + /// + public static bool IsGameInitialized { get; private set; } = false; + + + + + /// + /// Initializes the game singleton and core systems on subsystem registration. + /// This sets up the , game , + /// configuration, prefabs and managers and registers quit callbacks. + /// Invoked when starting up the runtime. Called before the first scene is loaded. + /// + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void InitializeGame() { - T Result = GetManager(); - if (Result == null) + // Load Project Setting + ProjectSettingAsset ProjectSettings = Resources.Load("RealMethod/RealMethodSetting"); + if (ProjectSettings == null) { - Result = gameObject.AddComponent(); - Debug.LogWarning($"Manager of type {typeof(T).Name} was not found. [A new one has been added]."); + Debug.LogError("ProjectSettingAsset is missing from Resources folder!"); + Quit(); + return; + } + // Initiate GameClass + var RealObject = new GameObject("RealMethod"); + Type TargetClass = ProjectSettings.GetGameType(); + if (TargetClass == null) + { + Debug.LogWarning("GameInstanceClass that was empty. DefaultGame Created"); + Instance = RealObject.AddComponent(); } - return Result; + else + { + if (typeof(Game).IsAssignableFrom(TargetClass)) + { + Instance = (Game)RealObject.AddComponent(TargetClass); + } + else + { + Debug.LogWarning($"Component of type {TargetClass} is not assignable from Game. DefaultGame Created"); + Instance = RealObject.AddComponent(); + } + } + Instance.OnProjectSeettingLoaded(ref ProjectSettings); + + Instance.OnGameOpen(); + + // Create GameBridge + Type targetService = ProjectSettings.GetBridgeType(); + if (targetService == null) + { + Debug.LogWarning($"GetGameBridgeType that was empty. DefaultGameBridge Created"); + Bridge = new DefaultGameBridge(Instance.Notify_OnWorldInitiate); + } + else + { + if (typeof(GameBridge).IsAssignableFrom(targetService)) + { + try + { + var parameter = new object[1] { (Action)Instance.Notify_OnWorldInitiate }; + Bridge = (GameBridge)Activator.CreateInstance(targetService, parameter); + } + catch (Exception ex) + { + Debug.LogError($"Failed to instantiate {targetService}: {ex.Message}. DefaultGameBridge Created"); + Bridge = new DefaultGameBridge(Instance.Notify_OnWorldInitiate); + } + } + else + { + Debug.LogWarning($"Type {targetService} is not assignable to GameBridge. DefaultGameBridge Created"); + Bridge = new DefaultGameBridge(Instance.Notify_OnWorldInitiate); + } + } + + // Set GameConfig + if (ProjectSettings.GetGameConfigAsset() != null) + { + Config = ProjectSettings.GetGameConfigAsset(); + } + else + { + Config = ScriptableObject.CreateInstance(); + } + + // Initiate GamePrefab & Managers + GameObject[] Objects = new GameObject[3]; + if (ProjectSettings.GetPrefab_1() != null) + { + GameObject newobj = Instantiate(ProjectSettings.GetPrefab_1()); + newobj.name = "GameScope(Runtime)"; + Objects[0] = newobj; + newobj.transform.SetParent(RealObject.transform); + } +#if UNITY_EDITOR + if (ProjectSettings.GetPrefab_2() != null) + { + GameObject newobj = Instantiate(ProjectSettings.GetPrefab_2()); + newobj.name = "GameScope(Editor)"; + Objects[1] = newobj; + newobj.transform.SetParent(RealObject.transform); + } +#endif +#if UNITY_SERVER + if (ProjectSettings.GetPrefab_3() != null) + { + GameObject newobj = Instantiate(ProjectSettings.GetPrefab_3()); + newobj.name = "GameScope(Server)"; + Objects[2] = newobj; + newobj.transform.SetParent(RealObject.transform); + } +#endif + Instance.OpenScope(Objects); + + // Unload Project Setting + Resources.UnloadAsset(ProjectSettings); + ProjectSettings = null; + + // Move Self GameObject to DontDestroy + DontDestroyOnLoad(RealObject); + Application.quitting += Instance.Notify_OnGameQuit; } - // Private Functions - private void OnGameWorldReplaced(World NewWorld) + /// + /// Called before any scene is loaded. Invokes on the active instance. + /// Invoked when the first scene's objects are loaded into memory but before Awake has been called. + /// + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + private static void RuntimeBeforeSceneLoad() { - World = NewWorld; - foreach (var service in GameServices) + if (Instance != null) { - service.provider.WorldUpdated(); + IsGameInitialized = true; + Instance.OnGameInitialized(); } - GameWorldSynced(World); } - private void OnGameQuit() + /// + /// Called after a scene has finished loading. Invokes on the active instance. + /// Right after all Awake() and OnEnable() calls but befor Start() + /// Invoked when the first scene's objects are loaded into memory but before Awake has been called. + /// + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] + private static void RuntimeAfterSceneLoad() { - Application.quitting -= OnGameQuit; - if (GameServices != null) + if (Instance != null) { - for (int i = 0; i < GameServices.Count; i++) - { - GameServices[i].provider.Deleted(this); - GameServices.RemoveAt(i); - } + Instance.OnGameStart(); } - Service.provider.Deleted(this); - GameClosed(); } - // Public Static Functions + + + + /// + /// Attempts to cast the global to the specified type . + /// Logs an error and returns null if the cast fails. + /// + /// The target type to cast the instance to. + /// The casted instance of type , or null on failure. public static T CastInstance() where T : class { if (Instance is T CastedInstance) @@ -103,6 +267,12 @@ public static T CastInstance() where T : class return null; } } + /// + /// Attempts to cast the current to the specified type . + /// Logs an error and returns null if the cast fails. + /// + /// The target type to cast the world to. + /// The casted world of type , or null on failure. public static T CastWorld() where T : class { if (World is T CastedWorld) @@ -115,78 +285,109 @@ public static T CastWorld() where T : class return null; } } - public static T AddService(object author) where T : Service, new() + /// + /// Retrieves a manager of type from the active manager scopes. + /// The search is performed in the following order: + /// 1. The current World scope (if available). + /// 2. The global Instance scope. + /// + /// The type of manager to retrieve. + /// + /// The manager of type if found; otherwise null. + /// + public static T GetManager() where T : Component, IGameManager + { + if (World != null && World.TryFindGameManager(out T worldResult)) + return worldResult; + + if (Instance.TryFindGameManager(out T gameResult)) + return gameResult; + + return null; + } + /// + /// Retrieves the service instance of type if available. + /// + /// IService type to retrieve. + /// The service instance of type , or null if not found. + public static T GetService() where T : IService { - // Check if a service of this type already exists - if (Instance.GameServices.Any(s => s.GetType() == typeof(T))) + if (Services.TryGet(out T Myservice)) { - Debug.LogWarning($"Service of type {typeof(T).Name} already exists."); - return null; + return Myservice; } - - // Create Service - T newService = new T(); - newService.provider.Created(author); - if (Instance.Managers != null) + else { - foreach (var manager in Instance.Managers) - { - manager.ResolveService(newService, true); - } + return default; } - Service.OnServiceCreated?.Invoke(newService); - Instance.GameServices.Add(newService); - return newService; } - public static bool RemoveService(object author) where T : Service + /// + /// Injects dependencies into the specified target object using the internal dependency injection system. + /// + /// The object whose dependencies should be injected. + public static void Inject(object target) { - var service = Instance.GameServices.FirstOrDefault(s => s.GetType() == typeof(T)); - if (service != null) - { - if (Instance.Managers != null) - { - foreach (var manager in Instance.Managers) - { - manager.ResolveService(service, false); - } - } - Service.OnServiceRemoved?.Invoke(service); - service.provider.Deleted(author); - Instance.GameServices.Remove(service); - return true; - } - - Debug.LogWarning($"Service of type {typeof(T).Name} not found to remove."); - return false; + DInjection.Inject(target); } - public static T GetService() where T : Service + /// + /// Registers and enables a feature instance in the dependency injection container. + /// + /// Type of the feature implementing . + /// The feature instance to register. + /// + /// If true, replaces an existing registered feature of the same type; otherwise keeps the existing one. + /// + public static void Enable(F instance, bool overwrite = false) where F : IFeature { - return Instance.GameServices.OfType().FirstOrDefault(); + DInjection.Register(instance, overwrite); } - public static Service GetService(Type type) + /// + /// Disables and unregisters a feature of the specified type from the dependency injection container. + /// + /// Type of the feature implementing . + /// True if the feature was successfully removed; otherwise false. + public static bool Disable() where F : IFeature { - if (!typeof(Service).IsAssignableFrom(type)) - { - Debug.LogError($"Type {type.Name} is not a valid Service."); - return null; - } - - return Instance.GameServices.FirstOrDefault(s => s.GetType() == type); + return DInjection.Unregister(); + } + /// + /// Publishes an event to all subscribers of the specified event type. + /// + /// Type of the event. + /// The event data to publish. + public static void Publish(T eventData) where T : IEvent + { + EventBus.Publish(eventData); } - public static bool TryFindService(out T service) where T : Service + /// + /// Subscribes a listener to a specific event type. + /// + /// Type of the event to listen for. + /// Callback invoked when the event is published. + public static void Subscribe(Action listener) where T : IEvent { - service = Instance.GameServices.OfType().FirstOrDefault(); - return service != null; + EventBus.Subscribe(listener); } - public string[] GetAllServiceNames() + /// + /// Unsubscribes a listener from a specific event type. + /// + /// Type of the event. + /// The listener to remove. + public static void Unsubscribe(Action listener) where T : IEvent { - return GameServices.Select(service => service.GetType().Name).ToArray(); + EventBus.Subscribe(listener); } + /// + /// Requests a scene load by build index . + /// If the requested scene is already active, a warning is logged and null is returned. + /// + /// Build index of the scene to open. + /// A driving the load operation, or null if not started. public static Coroutine OpenScene(int sceneIndex) { if (SceneManager.GetActiveScene().buildIndex != sceneIndex) { - return Instance.StartCoroutine(Service.GetLoadScneCorotine(sceneIndex)); + return Instance.StartCoroutine(Bridge.GetLoadScneCorotine(sceneIndex)); } else { @@ -194,15 +395,39 @@ public static Coroutine OpenScene(int sceneIndex) return null; } } - public static Coroutine OpenScene(SceneReference scene) + /// + /// Requests a scene load using a . + /// Note: this method work in [Editor]. + /// + /// Reference describing the scene to load. + /// A driving the load operation, or null if not started. + public static Coroutine OpenScene(SceneAsset scene) { +#if UNITY_EDITOR + if (!Application.isPlaying) + { + EditorSceneManager.OpenScene(scene.ScenePath, OpenSceneMode.Single); + return null; + } + else + { + return OpenScene(scene.ScneName); + } +#else return OpenScene(scene.ScneName); +#endif } + /// + /// Requests a scene load by name. + /// If the requested scene is already active, a warning is logged and null is returned. + /// + /// Name of the scene to open. + /// A driving the load operation, or null if not started. public static Coroutine OpenScene(string sceneName) { if (SceneManager.GetActiveScene().name != sceneName) { - return Instance.StartCoroutine(Service.GetLoadScneCorotine(sceneName)); + return Instance.StartCoroutine(Bridge.GetLoadScneCorotine(sceneName)); } else { @@ -210,190 +435,649 @@ public static Coroutine OpenScene(string sceneName) return null; } } - public static Coroutine OpenWorld(WorldSceneConfig WorldScene) + /// + /// Requests a Add scene by build index via the configured . + /// If the requested scene is already active, a warning is logged and null is returned. + /// + /// Build index of the scene to open. + /// callback event when scene complitly added + public static void AddScene(int sceneIndex, Action callback) { - if (SceneManager.GetActiveScene().buildIndex != SceneManager.GetSceneByPath(WorldScene.Persistent).buildIndex) + if (SceneManager.GetActiveScene().buildIndex != sceneIndex) { - return Instance.StartCoroutine(Service.GetLoadWorldCorotine(WorldScene)); + Instance.StartCoroutine(Bridge.GetAddScneCorotine(sceneIndex, callback)); } else { - Debug.LogWarning("The Persistent Scene is already loaded."); - return null; + Debug.LogWarning("The scene is already loaded."); } } - public static Coroutine ReOpenScene() + /// + /// Requests a scene load using a . + /// Note: this method work in [Editor]. + /// + /// Reference describing the scene to load. + /// callback event when scene complitly added + public static void AddScene(SceneAsset scene, Action callback) { - return Instance.StartCoroutine(Service.GetLoadScneCorotine(SceneManager.GetActiveScene().name)); ; +#if UNITY_EDITOR + if (!Application.isPlaying) + { + EditorSceneManager.OpenScene(scene.ScenePath, OpenSceneMode.Additive); + } + else + { + AddScene(scene.ScneName, callback); + } +#else + AddScene(scene.ScneName, callback); +#endif } - public static T FindManager() where T : MonoBehaviour + /// + /// Requests a scene load by name. + /// If the requested scene is already active, a warning is logged and null is returned. + /// + /// Name of the scene to open. + /// callback event when scene complitly added + public static void AddScene(string sceneName, Action callback) { - T Result = null; - - if (World != null) + if (SceneManager.GetActiveScene().name != sceneName) { - Result = World.GetManager(); + Instance.StartCoroutine(Bridge.GetAddScneCorotine(sceneName, callback)); } - - if (Result != null) + else { - return Result; + Debug.LogWarning("The scene is already loaded."); + } + } + /// + /// Loads a multi-scene world configuration using the provided . + /// If the persistent scene for the world is already loaded, a warning is logged and null is returned. + /// Note: this method work in [Editor]. + /// + /// World scene configuration to load. + /// A driving the world load operation, or null if not started. + public static Coroutine OpenWorld(WorldAsset WorldScene) + { +#if UNITY_EDITOR + if (!Application.isPlaying) + { + WorldScene.OnAssetClick(); + return null; } - return Instance.GetManager(); + else + { + if (SceneManager.GetActiveScene().buildIndex != SceneManager.GetSceneByPath(WorldScene.Persistent).buildIndex) + { + return Instance.StartCoroutine(Bridge.GetLoadWorldCorotine(WorldScene)); + } + else + { + Debug.LogWarning("The Persistent Scene is already loaded."); + return null; + } + } +#else + if (SceneManager.GetActiveScene().buildIndex != SceneManager.GetSceneByPath(WorldScene.Persistent).buildIndex) + { + return Instance.StartCoroutine(Bridge.GetLoadWorldCorotine(WorldScene)); + } + else + { + Debug.LogWarning("The Persistent Scene is already loaded."); + return null; + } +#endif + } - public static void HoldGameObject(GameObject Target) + /// + /// Reloads the currently active scene via the configured . + /// + /// A driving the reload operation. + public static Coroutine ReOpenScene() + { + return Instance.StartCoroutine(Bridge.GetLoadScneCorotine(SceneManager.GetActiveScene().name)); ; + } + /// + /// Parents the provided GameObject to the game root instance. + /// + /// The GameObject to hold under the game root. + /// The GameObject name change to new Name for searching. + public static void HoldGameObject(GameObject Target, Name16 TargetName) { + Target.name = TargetName; Target.transform.SetParent(Instance.transform); } - public static bool UnHoldGameObject(string GameObjectName, GameObject Target) + /// + /// Searches for a child GameObject with the given name and reparents it to . + /// + /// Name of the child GameObject to find. + /// New parent GameObject to assign. + /// true if the child was found and reparented; otherwise false. + public static bool TryUnholdGameObject(Name16 GameObjectName, out GameObject result) { + string TargetName = GameObjectName.ToString(); Transform[] Childs = Instance.GetComponentsInChildren(); foreach (var item in Childs) { - if (item.gameObject.name == GameObjectName) + if (item.gameObject.name == TargetName) { - item.SetParent(Target.transform); + item.SetParent(World.transform); + result = item.gameObject; return true; } } + result = null; return false; } + /// + /// Pauses or resumes the game by setting . + /// + /// If true the game is paused; otherwise resumed. public static void SetPause(bool paused) { Time.timeScale = paused ? 0 : 1; } + /// + /// Sets the global time scale and optionally adjusts fixed delta time for physics safety. + /// + /// New time scale to apply. + /// If true adjusts to keep physics stable. public static void SetSpeed(float speed, bool physicSafe = true) { Time.timeScale = speed; if (physicSafe) Time.fixedDeltaTime = 0.02f * Time.timeScale; // Keeps physics in sync } - - // Private Static Functions - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] - private static void InitializeGame() + /// + /// Saves the provided file using the active implementation. + /// Logs a warning if no save system is available. + /// + public static void Save(bool cloude = false) { - Game[] components = FindObjectsByType(FindObjectsSortMode.InstanceID); - if (components.Length > 1) + IStorageService storage = GetService(); + if (storage != null) { - Debug.LogError($"Expected exactly one active 'Game' component in the scene, but found {components.Length}."); - return; + storage.Save(); } - // Load Project Setting - ProjectSettingAsset ProjectSettings = Resources.Load("RealMethod/RealMethodSetting"); - if (ProjectSettings != null) + else { - // Initiate Game Class - if (components.Length == 0) - { - var emptyObject = new GameObject("RealGame"); - Type TargetClass = ProjectSettings.GetGameInstanceClass(); - if (TargetClass != null) - { - Instance = (Game)emptyObject.AddComponent(TargetClass); - if (Instance == null) - { - Debug.LogError($"Component of type {TargetClass} is not assignable from Game."); - Instance = emptyObject.AddComponent(); - } - } - else - { - Instance = emptyObject.AddComponent(); - } - } - else - { - Instance = components[0]; - } - // Create Game Service - Type targetService = ProjectSettings.GetGameServiceClass(); - if (targetService != null) + Debug.LogWarning("There is not any ISaveSystem Implemntation"); + } + + if (cloude) + { + ICloudService cloudeserv = GetService(); + if (cloudeserv != null) { - if (typeof(Service).IsAssignableFrom(targetService)) - { - try - { - Service = (GameService)Activator.CreateInstance(targetService); - } - catch (Exception ex) - { - Debug.LogError($"Failed to instantiate {targetService}: {ex.Message}"); - Service = new DefaultGameService(); - } - } - else - { - Debug.LogError($"Type {targetService} is not assignable to Service."); - Service = new DefaultGameService(); - } + cloudeserv.Save(); } else { - Service = new DefaultGameService(); + Debug.LogWarning("There is not any ICloudService Implemntation"); } - Instance.GameServices = new List(3); - Service.OnWorldUpdate += Instance.OnGameWorldReplaced; - Service.provider.Created(Instance); - // Set Game Config - if (ProjectSettings.GetGameConfig() != null) + } + } + /// + /// Loads the provided file using the active implementation. + /// Logs a warning if no save system is available. + /// + public static void Load(bool cloude = false) + { + IStorageService storage = GetService(); + if (storage != null) + { + storage.Load(); + } + else + { + Debug.LogWarning("There is not any ISaveSystem Implemntation"); + } + + if (cloude) + { + ICloudService cloudeserv = GetService(); + if (cloudeserv != null) { - Config = ProjectSettings.GetGameConfig(); + cloudeserv.Load(); } else { - Config = ScriptableObject.CreateInstance(); + Debug.LogWarning("There is not any ICloudService Implemntation"); } - Config.Initialized(Instance); - // Initiate GamePrefab & Managers - List CashManagers = new List(5); - foreach (var obj in ProjectSettings.GetGamePrefabs()) + } + } + /// + /// Quits the application. In the Unity Editor this stops play mode instead. + /// + public static void Quit() + { +#if UNITY_EDITOR + EditorApplication.isPlaying = false; +#else + Application.Quit(); +#endif + } + /// + /// Logs a message to the Unity Console. + /// + /// String or object to be converted to string representation for display. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Log(object message) + { + Debug.Log(message); + } + /// + /// Logs a message to the Unity Console. + /// + /// String or object to be converted to string representation for display. + /// Object to which the message applies. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Log(object message, UnityEngine.Object context) + { + Debug.Log(message, context); + } + /// + /// A variant of Debug.Log that logs a warning message to the console. + /// + /// String or object to be converted to string representation for display. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void LogWarning(object message) + { + Debug.LogWarning(message); + } + /// + /// A variant of Debug.Log that logs a warning message to the console. + /// + /// String or object to be converted to string representation for display. + /// Object to which the message applies. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void LogWarning(object message, UnityEngine.Object context) + { + Debug.LogWarning(message, context); + } + /// + /// A variant of Debug.Log that logs an error message to the console. + /// + /// String or object to be converted to string representation for display. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void LogError(object message) + { + Debug.LogError(message); + } + /// + /// A variant of Debug.Log that logs an error message to the console. + /// + /// String or object to be converted to string representation for display. + /// Object to which the message applies. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void LogError(object message, UnityEngine.Object context) + { + Debug.LogError(message, context); + } + /// + /// A variant of Debug.Log that logs an error message to the console. + /// + /// Runtime Exception. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void LogException(Exception exception) + { + Debug.LogException(exception); + } + /// + /// A variant of Debug.Log that logs an error message to the console. + /// + /// Runtime Exception + /// Object to which the message applies. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void LogException(Exception exception, UnityEngine.Object context) + { + Debug.LogException(exception, context); + } + /// + /// Assert a condition and logs an error message to the Unity console on failure. + /// + /// Condition you expect to be true. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Assert(bool condition) + { + Debug.Assert(condition); + } + /// + /// Assert a condition and logs an error message to the Unity console on failure. + /// + /// Condition you expect to be true. + /// String or object to be converted to string representation for display. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Assert(bool condition, object message) + { + Debug.Assert(condition, message); + } + /// + /// Assert a condition and logs an error message to the Unity console on failure. + /// + /// Condition you expect to be true. + /// Object to which the message applies. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Assert(bool condition, UnityEngine.Object context) + { + Debug.Assert(condition, context); + } + /// + /// Assert a condition and logs an error message to the Unity console on failure. + /// + /// Condition you expect to be true. + /// String or object to be converted to string representation for display. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Assert(bool condition, string message) + { + Debug.Assert(condition, message); + } + /// + /// Assert a condition and logs an error message to the Unity console on failure. + /// + /// Condition you expect to be true. + /// String or object to be converted to string representation for display. + /// Object to which the message applies. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Assert(bool condition, object message, UnityEngine.Object context) + { + Debug.Assert(condition, message, context); + } + /// + /// Assert a condition and logs an error message to the Unity console on failure. + /// + /// Condition you expect to be true. + /// String or object to be converted to string representation for display. + /// Object to which the message applies. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Assert(bool condition, string message, UnityEngine.Object context) + { + Debug.Assert(condition, message, context); + } + /// + /// Adds a new draw task to the rendering queue. + /// + /// The draw task to add. Ignored if null. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Draw(IDrawTask element) + { + if (element != null) + { + Instance.DrawTasks.Add(element); + if (element.Priority != 0) { - if (obj != null) - { - GameObject newobj = Instantiate(obj); - foreach (var manager in newobj.GetComponents()) - { - manager.InitiateManager(true); - CashManagers.Add(manager); - } - DontDestroyOnLoad(newobj); - } + Instance.DrawTasks.Sort((a, b) => a.Priority.CompareTo(b.Priority)); } - Instance.Managers = CashManagers.ToArray(); - // Unload Project Setting - Resources.UnloadAsset(ProjectSettings); - // Move Self GameObject to DontDestroy - DontDestroyOnLoad(Instance.gameObject); - Application.quitting += Instance.OnGameQuit; + element.Active(); } - else + } + /// + /// Removes the specified draw task from the rendering queue. + /// + /// The draw task to remove. + [System.Diagnostics.Conditional("UNITY_EDITOR")] + [System.Diagnostics.Conditional("DEVELOPMENT_BUILD")] + [HideInCallstack] + public static void Erase(IDrawTask element) + { + Instance.DrawTasks.Remove(element); + element.Deactive(); + } + + + + + /// + /// Called after GameInstance Created befor GameBridge , GameConfig & Managers Initilized + /// if you use custom PtojectSetttingAsset class you can use instances after loaded in game + /// this refrence unloaded befor OnGameInitialized Called. + /// + /// ProjectSettingAsset refrence + protected virtual void OnProjectSeettingLoaded(ref ProjectSettingAsset setting) + { + // Nothing todo + } + /// + /// Check GamePause with time or any custom override. + /// + /// true if the timescale is 0; otherwise false. + protected virtual bool IsGamePaused() + { + return Time.timeScale == 0; + } + /// + /// Check GameLoading with Bridge to check loading stage. + /// + /// true if any scne in loading stage; otherwise false. + protected virtual bool IsGameLoading() + { + return Bridge.IsLoading; + } + + + + /// + /// Callback invoked when a new is created or assigned. + /// Updates the static reference and notifies all services. + /// + /// The newly initiated world instance. + private void Notify_OnWorldInitiate(World NewWorld) + { + World = NewWorld; + OnWorldChanged(World); + } + /// + /// Handles application quit events: unbinds world callbacks, deletes modules and invokes . + /// + private void Notify_OnGameQuit() + { + Application.quitting -= Notify_OnGameQuit; + OnGameClosed(); + // State + ((IDisposable)State).Dispose(); + // Scope + CloseScope(); + // Bridge + ((IDisposable)Bridge).Dispose(); + Bridge = null; + // Draw +#if UNITY_EDITOR || DEVELOPMENT_BUILD + DrawTasks.Clear(); +#endif + // GC +#if UNITY_EDITOR + // Debug only: force GC to verify no references remain + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); +#endif + // Kernel + ClearKernel(); + } + + +#if UNITY_EDITOR + private void Awake() + { + if (Instance != null) { - Debug.LogError("ProjectSettingAsset is missing from Resources folder!"); + Debug.LogError($"This [{this}] component should not be added manually to the scene."); + Destroy(this); } } - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] - private static void RuntimeBeforeSceneLoad() + private void OnEnable() { - if (Instance != null) + + } + private void Start() + { + + } + private void OnDisable() + { + if (!EditorApplication.isPlayingOrWillChangePlaymode) + return; // Ignore disable caused by editor closing play mode + + if (gameObject.activeSelf == false) + { + Debug.LogWarning($"You can't Deactive {gameObject.name} GameObject"); + gameObject.SetActive(true); + } + if (enabled == false) { - Instance.GameInitialized(); + Debug.LogWarning($"You can't Disable {GetType().Name} Component"); + enabled = true; } } - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] - private static void RuntimeAfterSceneLoad() + private void LateUpdate() { - if (Instance != null) + if (transform.position != Vector3.zero) { - Instance.GameStarted(); + Debug.LogWarning($"{gameObject.name} position should not be changed!"); + transform.position = Vector3.zero; + } + if (transform.rotation != Quaternion.identity) + { + Debug.LogWarning($"{gameObject.name} rotation should not be changed!"); + transform.rotation = Quaternion.identity; } } + private void Update() + { - // Abstract Methods - protected abstract void GameInitialized(); - protected abstract void GameStarted(); - protected abstract void GameWorldSynced(World NewWorld); - protected abstract void GameClosed(); + } + private void FixedUpdate() + { + + } + /// + /// Returns the type names of all registered game services. + /// + /// Array of service type names. + public override IInspectorInfo[] GetAllInfo() + { + List Result = new List(10) { Bridge, Config }; + foreach (var item in base.GetAllInfo()) + { + Result.Add(item); + } + return Result.ToArray(); + } +#endif + + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + /// + /// A list containing all active draw tasks queued for rendering. + /// + private readonly List DrawTasks = new List(); + private void OnGUI() + { + for (int i = 0; i < DrawTasks.Count; i++) + { + IDrawTask task = DrawTasks[i]; + + if (task == null || task.IsExpired()) + { + if (task != null) + task.Deactive(); + DrawTasks.RemoveAt(i); + continue; + } + + if (task.GetDrawMode() != DrawMode.GUI) + continue; + + if (task.CanDraw(i)) + task.Draw(i); + } + } + private void OnDrawGizmos() + { + for (int i = 0; i < DrawTasks.Count; i++) + { + IDrawTask task = DrawTasks[i]; + + if (task == null || task.IsExpired()) + { + if (task != null) + task.Deactive(); + DrawTasks.RemoveAt(i); + continue; + } + + if (task.GetDrawMode() != DrawMode.Gizmo) + continue; + + if (task.CanDraw(i)) + task.Draw(i); + } + } +#endif + + + + /// + /// Called once when game opend in currect platform + /// Implement anything you want initiate befor realmethod initiate + /// Invoked when starting up the runtime. Called before the first scene is loaded. + /// + protected abstract void OnGameOpen(); + /// + /// Called once when the game framework has finished initial initialization. + /// Implement this to perform game-specific initialization logic. + /// Invoked when the first scene's objects are loaded into memory but before Awake has been called. + /// + protected abstract void OnGameInitialized(); + /// + /// Called after the first scene has been loaded and the game has started. + /// Implement this to perform logic that should run once the first scene is active. + /// Right after all Awake() and OnEnable() calls but befor Start() + /// Invoked when the first scene's objects are loaded into memory but before Awake has been called. + /// + protected abstract void OnGameStart(); + /// + /// Called when the current reference changes. + /// Implement to react to world switches. + /// + /// The new active world. + protected abstract void OnWorldChanged(World NewWorld); + /// + /// Called when the game is closing. Implement to perform cleanup logic. + /// + protected abstract void OnGameClosed(); } + } \ No newline at end of file diff --git a/Runtime/Core/Architecture/GameBridge.cs b/Runtime/Core/Architecture/GameBridge.cs new file mode 100644 index 00000000..b22aaad3 --- /dev/null +++ b/Runtime/Core/Architecture/GameBridge.cs @@ -0,0 +1,506 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace RealMethod +{ + + /// + /// Defines synchronization hooks used internally to coordinate + /// worlds and Game during runtime initialization. + /// + public interface IWorldBridge + { + /// + /// Introduces a newly created world to the system. + /// + /// The world instance being introduced. + /// + /// True if the world is treated as the main world; + /// false if it is considered a side/additive world. + /// + bool RegisterWorld(World world); + } + + + /// + /// A bridge that receives notifications before and after the global world changes. + /// + public interface IBridge + { + /// + /// Called after the new world has been set as the active global world. + /// + void OnWorldChanged(World world); + } + + + /// + /// Base class for any gamebridge in the framework. + /// Provides core functionality for: + /// + /// World synchronization (main and additive worlds) + /// world check for single remove new version + /// Load & Unload Scene reporting + /// + /// + public abstract class GameBridge : IDisposable, IWorldBridge, IInspectorInfo + { + /// + /// Indicates whether a scene or world load operation is currently in progress. + /// + public bool IsLoading { get; private set; } = false; + public bool SceneWillUnload { get; private set; } + /// + /// This represents the persistent scene reference used for managing components across the game lifecycle. + /// + public Scene CurrrentScene { get; private set; } + /// + /// Event invoked when a scene or world starts or finishes loading. + /// The boolean parameter is true when loading starts and false when loading ends. + /// + public event Action OnSceneLoading; + /// + /// Event invoked during scene or world loading to report progress. + /// The float parameter represents the loading progress from 0 (start) to 1 (complete). + /// + public event Action OnSceneLoadingProcess; + + protected float FadeTime = 0; + + private Scene LastActiveScene; + private readonly Action OnNextWorld; + private readonly List> bridges = new(); + + + + public GameBridge(Action method) + { + OnNextWorld = method ?? throw new ArgumentNullException(nameof(method)); + SceneManager.activeSceneChanged += OnActiveSceneChanged; + } + + + + // Implement IDisposable Interface + void IDisposable.Dispose() + { + SceneManager.activeSceneChanged -= OnActiveSceneChanged; + } + // Implement IRelationBridge Interface + bool IWorldBridge.RegisterWorld(World world) + { + return TryToRegisterWorld(world); + } + + + + + + /// + /// Registers a bridge provider using a weak reference. + /// Prevents duplicate bindings and ignores null providers. + /// + /// The bridge instance to bind. + /// Thrown when provider is null. + public void Bind(IBridge provider) + { + if (provider == null) + throw new ArgumentNullException(nameof(provider)); + + // Prevent duplicates + foreach (var weak in bridges) + { + if (weak.TryGetTarget(out IBridge existing) && existing == provider) + return; // Already stored + } + + bridges.Add(new WeakReference(provider)); + } + /// + /// Removes the specified bridge instance from the registry. + /// + /// The object to unbind (must implement IBridge). + /// + /// True if the bridge was found and removed; otherwise false. + /// + public bool Unbind(object obj) + { + if (obj is not IBridge provider) + return false; + + for (int i = bridges.Count - 1; i >= 0; i--) // reverse-safe removal + { + var weak = bridges[i]; + + if (!weak.TryGetTarget(out IBridge bridge) || bridge == provider) + { + bridges.RemoveAt(i); + return true; + } + } + + return false; + } + /// + /// Starts loading a scene by name using a coroutine. + /// + /// The name of the scene to load. + /// + /// An IEnumerator coroutine for loading the scene, + /// or null if a load operation is already in progress. + /// + public virtual IEnumerator GetLoadScneCorotine(string sceneName) + { + if (IsLoading == true) + { + Debug.LogWarning($"Can't load Scene:{sceneName} The Bridge is in loading target scene"); + return null; + } + return LoadSceneAsync(sceneName); + } + /// + /// Starts Adding a scene by name using a coroutine. + /// + /// The name of the scene to load. + /// + /// An IEnumerator coroutine for Adding the scene, + /// or null if a load operation is already in progress. + /// + public virtual IEnumerator GetAddScneCorotine(string sceneName, Action callback) + { + if (IsLoading == true) + { + Debug.LogWarning($"Can't load Scene:{sceneName} The Bridge is in loading target scene"); + return null; + } + return AddSceneAsync(callback, sceneName); + } + /// + /// Starts loading a scene by build index using a coroutine. + /// + /// The build index of the scene to load. + /// + /// An IEnumerator coroutine for loading the scene, + /// or null if a load operation is already in progress. + /// + public virtual IEnumerator GetLoadScneCorotine(int sceneIndex) + { + if (IsLoading == true) + { + Debug.LogWarning($"Can't load Index:{sceneIndex} The Bridge is in loading target scene"); + return null; + } + return LoadSceneAsync(string.Empty, sceneIndex); + } + /// + /// Starts Adding a scene by build index using a coroutine. + /// + /// The build index of the scene to load. + /// + /// An IEnumerator coroutine for Adding the scene, + /// or null if a load operation is already in progress. + /// + public virtual IEnumerator GetAddScneCorotine(int sceneIndex, Action callback) + { + if (IsLoading == true) + { + Debug.LogWarning($"Can't load Index:{sceneIndex} The Bridge is in loading target scene"); + return null; + } + return AddSceneAsync(callback, string.Empty, sceneIndex); + } + /// + /// Starts loading a world configuration using a coroutine. + /// + /// The worldAsset to load. + /// + /// An IEnumerator coroutine for loading the world, + /// or null if a load operation is already in progress. + /// + public virtual IEnumerator GetLoadWorldCorotine(WorldAsset WorldScene) + { + if (IsLoading == true) + { + Debug.LogWarning($"Can't load World:{WorldScene} The Bridge is in loading target scene"); + return null; + } + return LoadWorldAsync(WorldScene); + } + + + + + + + /// + /// Call this when you want to define new World class to game + /// + /// The world instance will set as main world for game. + protected void SetMianWorld(World world) + { + CurrrentScene = world.gameObject.scene; + OnNextWorld.Invoke(world); + NotifyBridges(world); + SceneWillUnload = false; + } + /// + /// Call this when you want to define new World class that created and should not be main world (probably deleted) + /// + /// The world instance will not set to main world for game. + protected void SetAdditiveWorld(World world) + { + world.enabled = false; + OnAdditiveWorldDetected(world); + } + /// + /// Request for this NewWorld to set for Main World in Scene + /// + /// The New WorldClass Refrence in Scene + /// + /// If this request is valid return true that mean this world set as main world. + /// If this request false means this world import from scen that is additive and should deactive. + /// Additive load + if (NewScene != CurrrentScene) + { + SetAdditiveWorld(NewWorld); + return false; ; + } + else + { + Debug.LogError($"[WorldRegistry] Duplicate world in SAME scene : {NewWorld.gameObject.name} / {Game.World.gameObject}"); + return false; + } + } + /// + /// Called when new scene loaded and during base world valid new world created. + /// + /// The New WorldClass Refrence in AdditiveScene + protected virtual void OnAdditiveWorldDetected(World AdditiveWorld) + { + UnityEngine.Object.Destroy(AdditiveWorld.gameObject); + } + + + + + private void OnActiveSceneChanged(Scene oldScene, Scene newScene) + { + LastActiveScene = newScene; + SceneWillUnload = true; // old scene will be destroyed next frame + } + /// + /// Calls the bridge method on all active bridge instances. + /// Invalid or collected references are removed automatically. + /// + private void NotifyBridges(World Newworld) + { + for (int i = bridges.Count - 1; i >= 0; i--) + { + if (bridges[i].TryGetTarget(out IBridge bridge)) + { + bridge.OnWorldChanged(Newworld); + } + else + { + bridges.RemoveAt(i); + } + } + } + private float RemapClamped(float value, float inMin, float inMax, float outMin, float outMax) + { + // Prevent divide by zero + if (Mathf.Approximately(inMax, inMin)) + { + Debug.LogWarning("Input range is zero. Returning outMin."); + return outMin; + } + + // Normalize the input value to 0–1 within the input range + float t = (value - inMin) / (inMax - inMin); + + // Scale and offset to target range + float mappedValue = t * (outMax - outMin) + outMin; + + // Clamp result to the output range + return Mathf.Clamp(mappedValue, Mathf.Min(outMin, outMax), Mathf.Max(outMin, outMax)); + } + + + + // Corotine + private IEnumerator LoadSceneAsync(string scene, int scneIndex = -1) + { + //StartLoading + IsLoading = true; + OnSceneLoading?.Invoke(true); + float fadingtime = FadeTime; + + //Fading Screen + if (fadingtime != 0) + { + yield return new WaitForSeconds(fadingtime); + } + + //Loading Scene + AsyncOperation Load_opertation; + if (scneIndex > -1) + { + Load_opertation = SceneManager.LoadSceneAsync(scneIndex, LoadSceneMode.Single); + } + else + { + Load_opertation = SceneManager.LoadSceneAsync(scene, LoadSceneMode.Single); + } + if (Load_opertation == null) + { + Debug.LogError("Failed to load scene. AsyncOperation is null."); + OnSceneLoading?.Invoke(false); + IsLoading = false; + yield break; + } + while (!Load_opertation.isDone) + { + OnSceneLoadingProcess?.Invoke(Load_opertation.progress); + yield return null; + } + OnSceneLoadingProcess?.Invoke(1); + + //Fading Screen + if (fadingtime != 0) + { + yield return new WaitForSeconds(fadingtime); + } + + //FinishLoading + OnSceneLoading?.Invoke(false); + IsLoading = false; + } + private IEnumerator AddSceneAsync(Action callback, string scene, int scneIndex = -1) + { + //Loading Scene + AsyncOperation Load_opertation; + if (scneIndex > -1) + { + Load_opertation = SceneManager.LoadSceneAsync(scneIndex, LoadSceneMode.Additive); + } + else + { + Load_opertation = SceneManager.LoadSceneAsync(scene, LoadSceneMode.Additive); + } + if (Load_opertation == null) + { + Debug.LogError("Failed to Add scene. AsyncOperation is null."); + yield break; + } + while (!Load_opertation.isDone) + { + // Processing + yield return null; + } + // Process = 1; + callback?.Invoke(); + } + private IEnumerator LoadWorldAsync(WorldAsset WS) + { + //StartLoading + IsLoading = true; + OnSceneLoading?.Invoke(true); + float fadingtime = FadeTime; + + //Fading Screen + if (fadingtime != 0) + { + yield return new WaitForSeconds(fadingtime); + } + + + //load Persistance Levels + AsyncOperation Load_opertation = SceneManager.LoadSceneAsync(WS.Persistent, LoadSceneMode.Single); + if (Load_opertation == null) + { + Debug.LogError("Failed to load scene. AsyncOperation is null."); + OnSceneLoading?.Invoke(false); + IsLoading = false; + yield break; + } + while (!Load_opertation.isDone) + { + OnSceneLoadingProcess?.Invoke(RemapClamped(Load_opertation.progress, 0, 1, 0, 1 / WS.Count + 1)); + OnSceneLoading?.Invoke(false); + IsLoading = false; + yield return null; + } + + // Load Additive Levels + for (int i = 0; i < WS.Count; i++) + { + AsyncOperation Additive_Load_opertation = SceneManager.LoadSceneAsync(WS[i], LoadSceneMode.Additive); + if (Additive_Load_opertation == null) + { + Debug.LogError("Failed to load scene. AsyncOperation is null."); + OnSceneLoading?.Invoke(false); + IsLoading = false; + yield break; + } + while (!Additive_Load_opertation.isDone) + { + OnSceneLoadingProcess?.Invoke(RemapClamped(Load_opertation.progress, 0, 1, 0, 1 / WS.Count + 1 - (i + 1))); + yield return null; + } + } + OnSceneLoadingProcess?.Invoke(1); + + //Fading Screen + if (fadingtime != 0) + { + yield return new WaitForSeconds(fadingtime); + } + + //FinishLoading + OnSceneLoading?.Invoke(false); + IsLoading = false; + } + + + + + +#if UNITY_EDITOR + // Implement IInspectorInfo Interface + string IInspectorInfo.GetInfo() + { + return $"IsLoading ({IsLoading}) , FadeTime ({FadeTime}) , BridgeConnect ({bridges.Count}) , {GetInspectorInfo()}"; + } + protected virtual string GetInspectorInfo() + { + return null; + } +#endif + + + + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/DefaultsClass/DefaultWorld.cs.meta b/Runtime/Core/Architecture/GameBridge.cs.meta similarity index 75% rename from Runtime/ReadySet/DefaultsClass/DefaultWorld.cs.meta rename to Runtime/Core/Architecture/GameBridge.cs.meta index bd198da7..e321001c 100644 --- a/Runtime/ReadySet/DefaultsClass/DefaultWorld.cs.meta +++ b/Runtime/Core/Architecture/GameBridge.cs.meta @@ -1,10 +1,10 @@ fileFormatVersion: 2 -guid: 45f6c9bddd831b14093e7ed8e1414a72 +guid: 988916d2da595cd46a9653f6fe26c9f9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] - executionOrder: -18 + executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: diff --git a/Runtime/Core/Architecture/GameConfig.cs b/Runtime/Core/Architecture/GameConfig.cs index 109059d1..33716b42 100644 --- a/Runtime/Core/Architecture/GameConfig.cs +++ b/Runtime/Core/Architecture/GameConfig.cs @@ -1,16 +1,19 @@ - -using UnityEngine; - namespace RealMethod { - public abstract class GameConfig : ConfigAsset + /// + /// Base configuration asset for game-wide settings and initialization logic. + /// + public abstract class GameConfig : ConfigAsset, IInspectorInfo { - [Header("Game")] - [SerializeField] - private float fadeTime = 0; - public float FadeTime => fadeTime; - - public abstract void Initialized(Game Author); +#if UNITY_EDITOR + string IInspectorInfo.GetInfo() + { + return GetInspectorInfo(); + } + protected virtual string GetInspectorInfo() + { + return null; + } +#endif } - } \ No newline at end of file diff --git a/Runtime/Core/Architecture/GameManager.cs b/Runtime/Core/Architecture/GameManager.cs index bf5c6e71..44e5c68d 100644 --- a/Runtime/Core/Architecture/GameManager.cs +++ b/Runtime/Core/Architecture/GameManager.cs @@ -2,42 +2,43 @@ namespace RealMethod { + /// + /// Defines the core behavior required for all game manager classes. + /// public interface IGameManager { - MonoBehaviour GetManagerClass(); - void InitiateManager(bool AlwaysLoaded); - void ResolveService(Service service, bool active); - } + /// + /// Gets the Unity instance that implements this interface. + /// + /// + /// This allows systems interacting with the interface to access the underlying + /// Unity component and its associated GameObject and Transform. + /// + Component Component => (Component)this; - public interface IService - { - void Created(object author); - void WorldUpdated(); - void Deleted(object author); + /// + /// Initializes the manager and prepares it for use in the game lifecycle. + /// + /// + /// Whitch owner class Initiation the manager + /// + void InitiateManager(Scope owner); } - public abstract class Service : IService + public class GameManager : MonoBehaviour, IGameManager { - public IService provider => this; - - // Implement IService Interface - void IService.Created(object author) - { - OnStart(author); - } - void IService.WorldUpdated() + // Implement IGameManager Interface + public void InitiateManager(Scope owner) { - OnNewWorld(); + OnInitiateManager(owner); } - void IService.Deleted(object author) + + + + protected virtual void OnInitiateManager(Scope owner) { - OnEnd(author); + } - - // Abstract Method - protected abstract void OnStart(object Author); - protected abstract void OnNewWorld(); - protected abstract void OnEnd(object Author); } } \ No newline at end of file diff --git a/Runtime/Core/Architecture/GameManager.cs.meta b/Runtime/Core/Architecture/GameManager.cs.meta index 2076019d..66608a96 100644 --- a/Runtime/Core/Architecture/GameManager.cs.meta +++ b/Runtime/Core/Architecture/GameManager.cs.meta @@ -1,11 +1,2 @@ fileFormatVersion: 2 -guid: 127dbea1049718c4684febe56e2000cc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +guid: d4832fe965ec2e242a7b04504a965182 \ No newline at end of file diff --git a/Runtime/Core/Architecture/GameService.cs b/Runtime/Core/Architecture/GameService.cs index 69717e51..e5d464f3 100644 --- a/Runtime/Core/Architecture/GameService.cs +++ b/Runtime/Core/Architecture/GameService.cs @@ -1,206 +1,31 @@ -using System; -using System.Collections; using UnityEngine; -using UnityEngine.SceneManagement; -#if UNITY_EDITOR -using UnityEditor; -#endif namespace RealMethod { - public interface IWorldSync + /// + /// Defines a contract for services in the game architecture. + /// Extends the IIdentifier interface. + /// + public interface IService : IIdentifier { - bool IntroduceWorld(World world); + } - public abstract class GameService : Service, IWorldSync + /// + /// Represents a service in the game architecture, extending the functionality of GameModule. + /// Ensures that all derived services implement the IService interface. + /// + public abstract class GameService : GameModule { - public IWorldSync Worldprovider => this; - // Game Structure - public Action OnWorldUpdate; - public Action OnAdditiveWorld; - public Action OnServiceCreated; - public Action OnServiceRemoved; - // Load Scene - public Action OnSceneLoading; - public Action OnSceneLoadingProcess; - public bool IsLoading { get; protected set; } - - - // Implement IWorldSync Interface - // Any World in Awake time call this method - bool IWorldSync.IntroduceWorld(World world) - { - if (Game.World == null) - { - OnWorldUpdate?.Invoke(world); - return true; - } - else - { - OnNewAdditiveWorld(world); - OnAdditiveWorld?.Invoke(world); - return false; - } - } - - // public Methods - public virtual IEnumerator GetLoadScneCorotine(string sceneName) - { - if (IsLoading == true) - { - Debug.LogWarning($"Can't load Scene:{sceneName} The Service is in Loading"); - return null; - } - return LoadSceneAsync(sceneName); - } - public virtual IEnumerator GetLoadScneCorotine(int sceneIndex) + /// + /// Initializes a new instance of the GameService class. + /// Validates that the derived class implements the IService interface. + /// Logs an error if the IService interface is not implemented. + /// + public GameService() : base() { - if (IsLoading == true) - { - Debug.LogWarning($"Can't load Index:{sceneIndex} The Service is in Loading"); - return null; - } - return LoadSceneAsync(string.Empty, sceneIndex); + if (this is not IService) + Debug.LogError($"Service of type {GetType().Name} should implement one of tye {typeof(IService).Name} interface"); } - public virtual IEnumerator GetLoadWorldCorotine(WorldSceneConfig WorldScene) - { - if (IsLoading == true) - { - Debug.LogWarning($"Can't load World:{WorldScene} The Service is in Loading"); - return null; - } - return LoadWorldAsync(WorldScene); - } - - // Abstract Methods - protected abstract void OnNewAdditiveWorld(World target); - - // Corotine - private IEnumerator LoadSceneAsync(string scene, int scneIndex = -1) - { - //StartLoading - IsLoading = true; - OnSceneLoading?.Invoke(true); - float fadingtime = Game.Config.FadeTime; - - //Fading Screen - if (fadingtime != 0) - { - yield return new WaitForSeconds(fadingtime); - } - - //Loading Scene - AsyncOperation Load_opertation; - if (scneIndex > -1) - { - Load_opertation = SceneManager.LoadSceneAsync(scneIndex, LoadSceneMode.Single); - } - else - { - Load_opertation = SceneManager.LoadSceneAsync(scene, LoadSceneMode.Single); - } - if (Load_opertation == null) - { - Debug.LogError("Failed to load scene. AsyncOperation is null."); - OnSceneLoading?.Invoke(false); - IsLoading = false; - yield break; - } - while (!Load_opertation.isDone) - { - OnSceneLoadingProcess?.Invoke(Load_opertation.progress); - yield return null; - } - OnSceneLoadingProcess?.Invoke(1); - - //Fading Screen - if (fadingtime != 0) - { - yield return new WaitForSeconds(fadingtime); - } - - //FinishLoading - OnSceneLoading?.Invoke(false); - IsLoading = false; - } - private IEnumerator LoadWorldAsync(WorldSceneConfig WS) - { - //StartLoading - IsLoading = true; - OnSceneLoading?.Invoke(true); - float fadingtime = Game.Config.FadeTime; - - //Fading Screen - if (fadingtime != 0) - { - yield return new WaitForSeconds(fadingtime); - } - - - //load Persistance Levels - AsyncOperation Load_opertation = SceneManager.LoadSceneAsync(WS.Persistent, LoadSceneMode.Single); - if (Load_opertation == null) - { - Debug.LogError("Failed to load scene. AsyncOperation is null."); - OnSceneLoading?.Invoke(false); - IsLoading = false; - yield break; - } - while (!Load_opertation.isDone) - { - OnSceneLoadingProcess?.Invoke(RM_Math.Map.RemapClamped(Load_opertation.progress, 0, 1, 0, 1 / WS.Count + 1)); - OnSceneLoading?.Invoke(false); - IsLoading = false; - yield return null; - } - - // Load Additive Levels - for (int i = 0; i < WS.Count; i++) - { - AsyncOperation Additive_Load_opertation = SceneManager.LoadSceneAsync(WS[i], LoadSceneMode.Additive); - if (Additive_Load_opertation == null) - { - Debug.LogError("Failed to load scene. AsyncOperation is null."); - OnSceneLoading?.Invoke(false); - IsLoading = false; - yield break; - } - while (!Additive_Load_opertation.isDone) - { - OnSceneLoadingProcess?.Invoke(RM_Math.Map.RemapClamped(Load_opertation.progress, 0, 1, 0, 1 / WS.Count + 1 - (i + 1))); - yield return null; - } - } - OnSceneLoadingProcess?.Invoke(1); - - //Fading Screen - if (fadingtime != 0) - { - yield return new WaitForSeconds(fadingtime); - } - - //FinishLoading - OnSceneLoading?.Invoke(false); - IsLoading = false; - } - - -#if UNITY_EDITOR - // Runs when entering Play Mode in Editor - [InitializeOnEnterPlayMode] - private static void EditorPlayModeInit() - { - var assets = Resources.FindObjectsOfTypeAll(); - foreach (var asset in assets) - { - if (asset.IsProjectAsset()) - { - asset.OnEditorPlay(); - } - } - } -#endif - } } \ No newline at end of file diff --git a/Runtime/Core/Architecture/GameService.cs.meta b/Runtime/Core/Architecture/GameService.cs.meta index e321001c..298e5ddb 100644 --- a/Runtime/Core/Architecture/GameService.cs.meta +++ b/Runtime/Core/Architecture/GameService.cs.meta @@ -1,11 +1,2 @@ fileFormatVersion: 2 -guid: 988916d2da595cd46a9653f6fe26c9f9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +guid: 7252e9f27b21b194ab50679f8b4e4be2 \ No newline at end of file diff --git a/Runtime/Core/Architecture/SceneReference.cs b/Runtime/Core/Architecture/SceneReference.cs deleted file mode 100644 index c27efe8f..00000000 --- a/Runtime/Core/Architecture/SceneReference.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.SceneManagement; -#if UNITY_EDITOR -using UnityEditor; -#endif - -[Serializable] -public class SceneReference : ISerializationCallbackReceiver -{ -#if UNITY_EDITOR - public SceneAsset SceneAsset; // Only in editor -#endif - public string ScenePath; - public string ScneName => System.IO.Path.GetFileNameWithoutExtension(ScenePath); - - public void OnBeforeSerialize() - { -#if UNITY_EDITOR - UpdateScenePath(); -#endif - } - - public void OnAfterDeserialize() { } - -#if UNITY_EDITOR - private void UpdateScenePath() - { - if (SceneAsset != null) - { - string newPath = AssetDatabase.GetAssetPath(SceneAsset); - if (ScenePath != newPath) - { - ScenePath = newPath; - EditorUtility.SetDirty(Selection.activeObject); - } - } - else - { - ScenePath = string.Empty; - } - } -#endif - - // Implicit conversion to string - public static implicit operator string(SceneReference sceneReference) - { - return sceneReference?.ScenePath; - } -} - -#if UNITY_EDITOR -[CustomPropertyDrawer(typeof(SceneReference), true)] -public class CustomSceneReferencePropertyDrawer : PropertyDrawer -{ - private Texture2D checkIcon; - private Texture2D warningIcon; - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - // Load icons once - if (checkIcon == null) checkIcon = EditorGUIUtility.IconContent("TestPassed").image as Texture2D; - if (warningIcon == null) warningIcon = EditorGUIUtility.IconContent("console.warnicon").image as Texture2D; - - SerializedProperty sceneAssetProp = property.FindPropertyRelative("SceneAsset"); - SerializedProperty scenePathProp = property.FindPropertyRelative("ScenePath"); - - EditorGUI.BeginProperty(position, label, property); - - // Restrict to SceneAsset type - Rect objectFieldRect = new Rect(position.x, position.y, position.width - 20, position.height); - EditorGUI.PropertyField(objectFieldRect, sceneAssetProp, label); - - if (sceneAssetProp.objectReferenceValue != null) - { - string path = AssetDatabase.GetAssetPath(sceneAssetProp.objectReferenceValue); - scenePathProp.stringValue = path; - - bool isInBuild = IsSceneInBuild(path); - - // Icon display - Rect iconRect = new Rect(position.x + position.width - 16, position.y + 2, 16, 16); - GUI.DrawTexture(iconRect, isInBuild ? checkIcon : warningIcon); - - // Tooltip if not included - if (!isInBuild) - { - GUIContent warningContent = new GUIContent("", "Scene is NOT in the active Build Profile.\nAdd it via File > Build Profiles."); - EditorGUI.LabelField(iconRect, warningContent); - } - } - else - { - scenePathProp.stringValue = string.Empty; - } - - EditorGUI.EndProperty(); - } - - private bool IsSceneInBuild(string scenePath) - { - for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++) - { - string listedScenePath = SceneUtility.GetScenePathByBuildIndex(i); - if (listedScenePath == scenePath) - return true; - } - return false; - } -} -#endif - - - - - diff --git a/Runtime/Core/Architecture/World.cs b/Runtime/Core/Architecture/World.cs index a4470565..479a2ce0 100644 --- a/Runtime/Core/Architecture/World.cs +++ b/Runtime/Core/Architecture/World.cs @@ -1,98 +1,216 @@ -using System.Collections.Generic; using UnityEngine; namespace RealMethod { - public abstract class World : MonoBehaviour + /// + /// Base class representing a locatioon for spawn player in scene + /// some virtual function in world calls can find all of object that has this class and with these spawing to location + /// + public abstract class PlayerStarter : MonoBehaviour { - [Header("Player")] + [Header("Details")] [SerializeField] - private bool IsPlayerInScene = true; - [SerializeField, ConditionalHide("IsPlayerInScene", true, false), TagSelector] - private string PlayerTag = "Player"; - [SerializeField, ConditionalHide("IsPlayerInScene", true, true)] - private GameObject DefualtPlayer; - [SerializeField, ConditionalHide("IsPlayerInScene", true, true)] - private Transform SpawnPoint; - - // Private Variable - private IGameManager[] Managers; + private string posName = "None"; + public string PosName => posName; + +#if UNITY_EDITOR + [Header("Gizmo")] + [SerializeField] + private float height = 2f; + [SerializeField] + private float radius = 0.5f; +#endif + + private bool hasPlayer = false; + + // Unity Method + private void Awake() + { + Destroy(gameObject); + } + + /// + /// Attempts to mark this spawn point as occupied by a player. + /// + /// + /// True if the spawn point was successfully marked as occupied; false if it is already occupied. + /// + public bool TryStartHere() + { + if (hasPlayer) + return false; + + hasPlayer = true; + return true; + } + /// + /// Check is player Spawn on this location. + /// + /// + /// True is already occupied. + /// + public bool CanStartHere() + { + return hasPlayer; + } + + +#if UNITY_EDITOR + protected virtual void OnDrawGizmos() + { + bool blocked = Physics.CheckCapsule(transform.position, transform.position + Vector3.up * height, radius); + + Color c = blocked ? Color.red : Color.cyan; + + RM_Gizmos.Capsule(transform.position, c, height, radius); + RM_Gizmos.Arrow(transform.position, transform.forward, Color.red); + RM_Gizmos.Text(PosName, transform.position + (transform.up * (height / 2)) + (Vector3.up * 0.1f), Color.black); + } +#endif + } + + /// + /// Base class representing a game world / scene context. + /// Manages the player GameObject, locates and initializes child game managers, + /// Concrete worlds should implement + /// and to perform + /// world-specific initialization and cleanup. + /// + public abstract class World : Scope + { + [Header("Setting")] + [SerializeField] + private Prefab DefaultPlayer; + /// + /// This action called every time your game ready to play after load Scene & setup RealMethod + /// you can enshure that your game and world do anything and player can ready to play game + /// when you change scene after world initiate this evet invoke again. + /// + public static event System.Action OnReady; + + private GameObject PlayerObject; - // Base Method + + /// + /// Unity callback invoked when the script instance is being loaded. + /// initializes child managers and locates or creates the player object, + /// then calls for world-specific initialization. + /// private void Awake() { - //Connect to Game Service - if (Game.Service.Worldprovider.IntroduceWorld(this)) - { - Game.Service.OnAdditiveWorld += AdditiveWorld; - Game.Service.OnServiceCreated += NotifyServiceCreated; - Game.Service.OnServiceRemoved += NotifyServiceRemoved; - } - else + //Connect to Game With Bridge + IWorldBridge SyncProvider = Game.Bridge; + if (!SyncProvider.RegisterWorld(this)) { return; } // Get All Managers - List CashManagers = new List(10); - foreach (var manager in GetComponentsInChildren()) // Self Mangers + OpenScope(new GameObject[1] { gameObject }); + + // Find Player or Create newone + var scneplayer = GetPlayerInScene(); + if (scneplayer == null) { - manager.InitiateManager(false); - CashManagers.Add(manager); + var starters = FindObjectsByType(FindObjectsSortMode.InstanceID); + Transform SpawnPoint = SelectSpawnPoint(starters); + PlayerObject = SpawnPlayer(DefaultPlayer, SpawnPoint); } - Managers = new IGameManager[CashManagers.Count]; - Managers = CashManagers.ToArray(); - - //Find Player or Create newone - if (!InitiatePlayer(ref PlayerObject)) + else { - return; + PlayerObject = scneplayer; } - AwakeWorld(); + // Reset Location of World + transform.position = Vector3.zero; + transform.rotation = Quaternion.identity; + + WorldBegin(); + OnReady?.Invoke(); } - private void OnDestroy() +#if UNITY_EDITOR + private void OnEnable() { - Game.Service.OnAdditiveWorld -= AdditiveWorld; - Game.Service.OnServiceCreated -= NotifyServiceCreated; - Game.Service.OnServiceRemoved -= NotifyServiceRemoved; + } - // Public Metthods - public T GetManager() where T : class + private void OnDisable() { - foreach (var manager in Managers) - { - if (manager.GetManagerClass() is T Result) - { - return Result; - } - } - return null; } - public IGameManager GetManager(string ObjectName) + private void LateUpdate() { - foreach (var manger in Managers) + if (transform.position != Vector3.zero) { - if (manger.GetManagerClass().gameObject.name == ObjectName) - { - return manger; - } + Debug.LogWarning($"{gameObject.name} position should not be changed!"); + transform.position = Vector3.zero; + } + if (transform.rotation != Quaternion.identity) + { + Debug.LogWarning($"{gameObject.name} rotation should not be changed!"); + transform.rotation = Quaternion.identity; } + } + private void Update() + { + + } + private void FixedUpdate() + { + + } + public sealed override IInspectorInfo[] GetAllInfo() + { return null; } +#endif + /// + /// Unity callback invoked when the object is being destroyed. + /// + private void OnDestroy() + { + CloseScope(); + WorldEnd(); + } + + + + /// + /// Returns the primary player for this world. + /// + /// Player index when supporting multiple players (currently unused). + /// The player GameObject reference, or null if none is present. public GameObject GetPlayerObject(byte index = 0) { return PlayerObject; } + /// + /// Gets a component of type from the player GameObject. + /// + /// Component type to retrieve (must derive from ). + /// Player index when supporting multiple players (currently unused). + /// The component instance if found; otherwise null. public T GetPlayerComponent(byte index = 0) where T : MonoBehaviour { return PlayerObject.GetComponent(); } + /// + /// Gets a component or class of type from the player GameObject. + /// This is a generic helper that uses Unity's GetComponent and returns the result + /// as a reference type. + /// + /// The class type to retrieve. + /// Player index when supporting multiple players (currently unused). + /// The requested class instance, or null if not found. public T GetPlayerClass(byte index = 0) where T : class { return PlayerObject.GetComponent(); } + /// + /// Retrieves all components of type attached to the player GameObject. + /// + /// Component type to retrieve. + /// Player index when supporting multiple players (currently unused). + /// Array of components if found; otherwise null and a warning is logged. public T[] GetPlayerComponents(byte index = 0) where T : MonoBehaviour { T[] components = PlayerObject.GetComponents(); @@ -103,6 +221,12 @@ public T[] GetPlayerComponents(byte index = 0) where T : MonoBehaviour Debug.LogWarning($"No components of type {typeof(T).Name} found on {PlayerObject.name} or its children."); return null; } + /// + /// Retrieves all components of type from the player GameObject and its children. + /// + /// Component type to retrieve. + /// Player index when supporting multiple players (currently unused). + /// Array of components if found; otherwise null and a warning is logged. public T[] GetPlayerComponentsInChilderen(byte index = 0) where T : MonoBehaviour { T[] components = PlayerObject.GetComponentsInChildren(); @@ -113,74 +237,111 @@ public T[] GetPlayerComponentsInChilderen(byte index = 0) where T : MonoBehav Debug.LogWarning($"No components of type {typeof(T).Name} found on {PlayerObject.name} or its children."); return null; } + /// + /// Retrieves the first component of type found on the player GameObject or its children. + /// + /// Component type to retrieve. + /// Player index when supporting multiple players (currently unused). + /// The component instance if found; otherwise null. public T GetPlayerComponentsInChildren(byte index = 0) where T : MonoBehaviour { return PlayerObject.GetComponentInChildren(); } - // Virtual Methods - protected virtual bool InitiatePlayer(ref GameObject player) + + + /// + /// Spawns the player character at the specified spawn point. + /// + /// + /// The player prefab to instantiate. If invalid, a fallback empty Player GameObject is created. + /// + /// + /// The transform representing the position and rotation where the player should spawn. + /// + /// + /// The spawned player GameObject. + /// + protected virtual GameObject SpawnPlayer(Prefab playerPrefab, Transform spawnPoint) { - if (IsPlayerInScene) + if (playerPrefab.IsValid()) { - player = GameObject.FindGameObjectWithTag(PlayerTag); - if (!player) - { - Debug.LogError("PlayerGameObject Cant Find in Scene"); - return false; - } - return true; + Transform player = Instantiate(playerPrefab.GetMainComponent(), spawnPoint.position, spawnPoint.rotation); + player.SendMessage("OnSpawn", this, SendMessageOptions.DontRequireReceiver); + return player.gameObject; } else { - if (DefualtPlayer != null) - { - if (SpawnPoint) - { - player = Instantiate(DefualtPlayer, SpawnPoint.position, SpawnPoint.rotation); - } - else - { - player = Instantiate(DefualtPlayer, transform.position, Quaternion.identity); - } - return true; - } - else - { - player = new GameObject("Player"); - player.tag = "Player"; - return true; - } - + GameObject player = new GameObject("Player"); + player.tag = "Player"; + player.transform.SetPositionAndRotation(spawnPoint.position, spawnPoint.rotation); + return player; } } - protected virtual void AdditiveWorld(World TargetWorld) + /// + /// Searches the current scene for an existing player GameObject. + /// + /// + /// The first GameObject found with the "Player" tag, or null if none exists. + /// + protected virtual GameObject GetPlayerInScene() { - Debug.LogWarning($"This World Class ({TargetWorld}) Deleted"); - Destroy(TargetWorld); + return GameObject.FindGameObjectWithTag("Player"); } - // Private Methods - private void NotifyServiceCreated(Service NewService) + /// + /// Selects a spawn point from the available PlayerStarter components. + /// + /// + /// An array of PlayerStarter objects that define possible spawn locations. + /// + /// + /// The transform of the selected spawn point. If none are available, + /// the current object's transform at the world origin is used. + /// + protected virtual Transform SelectSpawnPoint(PlayerStarter[] starters) { - if (Managers != null) + if (starters.Length > 0) { - foreach (var manager in Managers) + int index = Random.Range(0, starters.Length); + if (!starters[index].CanStartHere()) { - manager.ResolveService(NewService, true); + return starters[index].transform; } - } - } - private void NotifyServiceRemoved(Service NewService) - { - if (Managers != null) - { - foreach (var manager in Managers) + foreach (var start in starters) { - manager.ResolveService(NewService, false); + if (!start.CanStartHere()) + { + if (start.TryStartHere()) + { + return start.transform; + } + else + { + continue; + } + } + else + { + continue; + } } } + + transform.position = Vector3.zero; + return transform; } - // Abstract Methods - protected abstract void AwakeWorld(); - protected abstract void DestroyWorld(); + + + /// + /// Called after the world is initialized in the context of this scene. + /// If this world is the main world, this runs normally. + /// If this world is loaded additively, it runs in additive context. + /// Use this to set up scene-specific systems, not global main-world logic. + /// + protected abstract void WorldBegin(); + /// + /// Called when the world is being destroyed to perform cleanup of world-specific state. + /// Implementations should release resources and unregister any world-specific hooks here. + /// + protected abstract void WorldEnd(); } } \ No newline at end of file diff --git a/Runtime/Core/Architecture/WorldSceneConfig.cs b/Runtime/Core/Architecture/WorldSceneConfig.cs deleted file mode 100644 index dda47d11..00000000 --- a/Runtime/Core/Architecture/WorldSceneConfig.cs +++ /dev/null @@ -1,40 +0,0 @@ - -using UnityEngine; -#if UNITY_EDITOR -using UnityEditor.SceneManagement; -#endif - - -namespace RealMethod -{ - [CreateAssetMenu(fileName = "WorldScene", menuName = "Scene/WorldScene", order = 1)] - public class WorldSceneConfig : ConfigAsset - { - [Header("Scenes")] - [SerializeField] - private SceneReference persistent; - public SceneReference Persistent => persistent; - [SerializeField] - private SceneReference[] Layers; - public int Count => Layers.Length; - - public SceneReference this[int index] - { - get => Layers[index]; - } - -#if UNITY_EDITOR - public void OnAssetClick() - { - EditorSceneManager.OpenScene(Persistent, OpenSceneMode.Single); - foreach (var item in Layers) - { - EditorSceneManager.OpenScene(item, OpenSceneMode.Additive); - } - } -#endif - - - - } -} \ No newline at end of file diff --git a/Runtime/Core/Attributes/AssetInlinAttribute.cs b/Runtime/Core/Attributes/AssetInlinAttribute.cs new file mode 100644 index 00000000..a4d22db4 --- /dev/null +++ b/Runtime/Core/Attributes/AssetInlinAttribute.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +namespace RealMethod +{ + /// + /// Use this property on a ScriptableObject type to allow the editors drawing the field to draw an expandable + /// area that allows for changing the values on the object without having to change editor. + /// + /// [Expandable] + /// public ScriptableObject TEST; + /// + /// + public sealed class AssetInlinAttribute : PropertyAttribute + { + public AssetInlinAttribute() + { + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/ExpandableAttribute.cs.meta b/Runtime/Core/Attributes/AssetInlinAttribute.cs.meta similarity index 100% rename from Runtime/Core/Attributes/ExpandableAttribute.cs.meta rename to Runtime/Core/Attributes/AssetInlinAttribute.cs.meta diff --git a/Runtime/Core/Attributes/ButtonAttribute.cs b/Runtime/Core/Attributes/ButtonAttribute.cs index 5d5ced0e..cde42afd 100644 --- a/Runtime/Core/Attributes/ButtonAttribute.cs +++ b/Runtime/Core/Attributes/ButtonAttribute.cs @@ -1,45 +1,18 @@ using System; -using System.Linq; -using System.Reflection; -using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif namespace RealMethod { + /// + /// + /// [Button] + /// private void DoSomething() + /// { + /// Debug.Log("DoSomething called from Inspector!"); + /// } + /// + /// [AttributeUsage(AttributeTargets.Method, Inherited = true)] - public class ButtonAttribute : Attribute { } - -#if UNITY_EDITOR - [CustomEditor(typeof(MonoBehaviour), true)] - public class ButtonDrawer : Editor - { - public override void OnInspectorGUI() - { - base.OnInspectorGUI(); - - var targetType = target.GetType(); - var methods = targetType - .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - .Where(m => m.GetCustomAttribute() != null && m.GetParameters().Length == 0); - - foreach (var method in methods) - { - if (GUILayout.Button(method.Name)) - { - method.Invoke(target, null); - } - } - } - } -#endif - + public sealed class ButtonAttribute : Attribute { } } -// [Button] -// private void DoSomething() -// { -// Debug.Log("DoSomething called from Inspector!"); -// } \ No newline at end of file diff --git a/Runtime/Core/Attributes/ColorFieldAttribute.cs b/Runtime/Core/Attributes/ColorFieldAttribute.cs index 6b628bc6..99c7527b 100644 --- a/Runtime/Core/Attributes/ColorFieldAttribute.cs +++ b/Runtime/Core/Attributes/ColorFieldAttribute.cs @@ -1,78 +1,19 @@ using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif - namespace RealMethod { - public enum FieldColor - { - Red, - Green, - Blue, - Yellow, - Black, - White, - Gray - } - public class ColorFieldAttribute : PropertyAttribute + /// + /// + /// [ColorFieldAttribute(R,G,B)] + /// public GameObject Target; + /// + /// + public sealed class ColorFieldAttribute : PropertyAttribute { - public Color color; + public Color color = Color.blue; - public ColorFieldAttribute(FieldColor _color = FieldColor.Red) + public ColorFieldAttribute(float r, float g, float b) { - switch (_color) - { - case FieldColor.Red: - color = Color.red; - break; - case FieldColor.Green: - color = Color.green; - break; - case FieldColor.Blue: - color = Color.blue; - break; - case FieldColor.Yellow: - color = Color.yellow; - break; - case FieldColor.Black: - color = Color.black; - break; - case FieldColor.White: - color = Color.white; - break; - case FieldColor.Gray: - color = Color.gray; - break; - default: - color = Color.red; - break; - } + color = new Color(r, g, b); } } - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(ColorFieldAttribute))] - public class RequiredFieldDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - ColorFieldAttribute field = attribute as ColorFieldAttribute; - - if (property.objectReferenceValue == null) - { - GUI.color = field.color; //Set the color of the GUI - EditorGUI.PropertyField(position, property, label); //Draw the GUI - GUI.color = Color.white; //Reset the color of the GUI to white - } - else - EditorGUI.PropertyField(position, property, label); - } - } -#endif -} - -///Use -///[ColorFieldAttribute(FieldColor.Blue)] -///public GameObject Test; \ No newline at end of file +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/ConditionalHideAttribute.cs b/Runtime/Core/Attributes/ConditionalHideAttribute.cs index 36c36a6b..0955a31a 100644 --- a/Runtime/Core/Attributes/ConditionalHideAttribute.cs +++ b/Runtime/Core/Attributes/ConditionalHideAttribute.cs @@ -1,11 +1,16 @@ using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif namespace RealMethod { - public class ConditionalHideAttribute : PropertyAttribute + /// + /// + /// public bool Variable; + /// [ConditionalHide("Variable", true, false)] + /// public String TargetName; + /// + /// conditionalSourceField,hideInInspector, reverceCondition + /// + public sealed class ConditionalHideAttribute : PropertyAttribute { public string ConditionalSourceField; public bool HideInInspector; @@ -18,78 +23,4 @@ public ConditionalHideAttribute(string conditionalSourceField, bool hideInInspec ReverceCondition = reverceCondition; } } - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(ConditionalHideAttribute))] - public class ConditionalHidePropertyDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - ConditionalHideAttribute condHAtt = (ConditionalHideAttribute)attribute; - bool enabled = GetConditionalHideAttributeResult(condHAtt, property); - - bool wasEnabled = GUI.enabled; - GUI.enabled = enabled; - - if (!condHAtt.HideInInspector || enabled) - { - EditorGUI.PropertyField(position, property, label, true); - } - - GUI.enabled = wasEnabled; - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - ConditionalHideAttribute condHAtt = (ConditionalHideAttribute)attribute; - bool enabled = GetConditionalHideAttributeResult(condHAtt, property); - - if (!condHAtt.HideInInspector || enabled) - { - return EditorGUI.GetPropertyHeight(property, label); - } - else - { - return -EditorGUIUtility.standardVerticalSpacing; - } - } - - private bool GetConditionalHideAttributeResult(ConditionalHideAttribute condHAtt, SerializedProperty property) - { - bool enabled = true; - - string propertyPath = property.propertyPath; // returns the property path of the property we want to apply the attribute to - string conditionPath = propertyPath.Replace(property.name, condHAtt.ConditionalSourceField); // changes the path to the conditionalsource property path - SerializedProperty sourcePropertyValue = property.serializedObject.FindProperty(conditionPath); - - if (sourcePropertyValue != null) - { - if (!condHAtt.ReverceCondition) - { - enabled = sourcePropertyValue.boolValue; - } - else - { - enabled = !sourcePropertyValue.boolValue; - } - - } - else - { - Debug.LogWarning("Attempting to use a ConditionalHideAttribute but no matching SourcePropertyValue found in object: " + condHAtt.ConditionalSourceField); - } - - return enabled; - } - } - -#endif - -} - -//Use -// [ConditionalHide("IsPlayerInScene", true, false)] -// First variable : Your boolean variable Name -// Second variable : if true= Show/Hide false= Visible/Invisible -// Third variable : if true= revert functionality +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/ConditionalHideByEnumAttribute.cs b/Runtime/Core/Attributes/ConditionalHideByEnumAttribute.cs new file mode 100644 index 00000000..dce0594c --- /dev/null +++ b/Runtime/Core/Attributes/ConditionalHideByEnumAttribute.cs @@ -0,0 +1,33 @@ +using UnityEngine; + + +namespace RealMethod +{ + /// + /// + /// public enum ExampleEnum + /// { + /// Option1, + /// Option2, + /// Option3 + /// } + /// + /// public ExampleEnum exampleEnum; + /// [ConditionalHideByEnum("exampleEnum", ExampleEnum.Option1, ExampleEnum.Option3)] + /// public string hideOnlyForOption1And3; + /// [ConditionalHideByEnum("exampleEnum", ExampleEnum.Option2)] + /// public int hideOnlyForOption2; + /// + /// + public sealed class ConditionalHideByEnumAttribute : PropertyAttribute + { + public string EnumFieldName; + public object[] HideValues; + + public ConditionalHideByEnumAttribute(string enumFieldName, params object[] hideValues) + { + EnumFieldName = enumFieldName; + HideValues = hideValues; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/HideInInspectorByEnumAttribute.cs.meta b/Runtime/Core/Attributes/ConditionalHideByEnumAttribute.cs.meta similarity index 100% rename from Runtime/Core/Attributes/HideInInspectorByEnumAttribute.cs.meta rename to Runtime/Core/Attributes/ConditionalHideByEnumAttribute.cs.meta diff --git a/Runtime/Core/Attributes/ConditionalShowByEnumAttribute.cs b/Runtime/Core/Attributes/ConditionalShowByEnumAttribute.cs new file mode 100644 index 00000000..304d1b63 --- /dev/null +++ b/Runtime/Core/Attributes/ConditionalShowByEnumAttribute.cs @@ -0,0 +1,34 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + /// + /// + /// public enum ExampleEnum + /// { + /// Option1, + /// Option2, + /// Option3 + /// } + /// + /// public ExampleEnum exampleEnum; + /// [ConditionalShowByEnum("exampleEnum", ExampleEnum.Option1, ExampleEnum.Option3)] + /// public string visibleOnlyForOption1And3; + /// [ConditionalShowByEnum("exampleEnum", ExampleEnum.Option2)] + /// public int visibleOnlyForOption2; + /// + /// + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] + public sealed class ConditionalShowByEnumAttribute : PropertyAttribute + { + public string EnumFieldName { get; } + public object[] ShowValues { get; } + + public ConditionalShowByEnumAttribute(string enumFieldName, params object[] showValues) + { + EnumFieldName = enumFieldName; + ShowValues = showValues; + } + } +} diff --git a/Runtime/Core/Attributes/ShowInInspectorByEnumAttribute.cs.meta b/Runtime/Core/Attributes/ConditionalShowByEnumAttribute.cs.meta similarity index 100% rename from Runtime/Core/Attributes/ShowInInspectorByEnumAttribute.cs.meta rename to Runtime/Core/Attributes/ConditionalShowByEnumAttribute.cs.meta diff --git a/Runtime/Core/Attributes/DescriptionEnumAttribute.cs b/Runtime/Core/Attributes/DescriptionEnumAttribute.cs new file mode 100644 index 00000000..a545a238 --- /dev/null +++ b/Runtime/Core/Attributes/DescriptionEnumAttribute.cs @@ -0,0 +1,30 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + /// + /// Example: + /// + /// public enum MyEnumWithDescriptions + /// { + /// [EnumDescription("This is the first option.")] + /// Option1, + /// [EnumDescription("This is the second option.")] + /// Option2, + /// [EnumDescription("This is the third option.")] + /// Option3 + /// } + /// + /// + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] + public sealed class DescriptionEnumAttribute : PropertyAttribute + { + public string Description { get; } + public DescriptionEnumAttribute(string description) + { + Description = description; + } + } +} + diff --git a/Runtime/Core/Attributes/EnumDescriptionAttribute.cs.meta b/Runtime/Core/Attributes/DescriptionEnumAttribute.cs.meta similarity index 100% rename from Runtime/Core/Attributes/EnumDescriptionAttribute.cs.meta rename to Runtime/Core/Attributes/DescriptionEnumAttribute.cs.meta diff --git a/Runtime/Core/Attributes/DropdownAttribute.cs b/Runtime/Core/Attributes/DropdownAttribute.cs index 08ce7e8b..62ca5293 100644 --- a/Runtime/Core/Attributes/DropdownAttribute.cs +++ b/Runtime/Core/Attributes/DropdownAttribute.cs @@ -1,12 +1,18 @@ -#if UNITY_EDITOR -using UnityEditor; -#endif using UnityEngine; namespace RealMethod { - - public class DropdownAttribute : PropertyAttribute + /// + /// + /// Exaple_1: + /// [Dropdown("Option1", "Option2", "Option3")] + /// public string selectedOption; + /// Example_2: + /// [Dropdown("Option1", "Option2", "Option3")] + /// public int selectedOptionIndex; + /// + /// + public sealed class DropdownAttribute : PropertyAttribute { public string[] options; @@ -15,41 +21,4 @@ public DropdownAttribute(params string[] options) this.options = options; } } - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(DropdownAttribute))] - public class DropdownDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - DropdownAttribute dropdownAttribute = (DropdownAttribute)attribute; - - if (property.propertyType == SerializedPropertyType.String) - { - int index = Mathf.Max(0, System.Array.IndexOf(dropdownAttribute.options, property.stringValue)); - index = EditorGUI.Popup(position, label.text, index, dropdownAttribute.options); - property.stringValue = dropdownAttribute.options[index]; - } - else if (property.propertyType == SerializedPropertyType.Integer) - { - int index = Mathf.Clamp(property.intValue, 0, dropdownAttribute.options.Length - 1); - index = EditorGUI.Popup(position, label.text, index, dropdownAttribute.options); - property.intValue = index; - } - else - { - EditorGUI.LabelField(position, label.text, "Use Dropdown with string or int."); - } - } - } - -#endif -} - -// ----Use -// [Dropdown("Option1", "Option2", "Option3")] -// public string selectedOption; - -// [Dropdown("Option1", "Option2", "Option3")] -// public int selectedOptionIndex; +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/DropdownFromArrayAttribute.cs b/Runtime/Core/Attributes/DropdownFromArrayAttribute.cs index eb76093e..55c5be06 100644 --- a/Runtime/Core/Attributes/DropdownFromArrayAttribute.cs +++ b/Runtime/Core/Attributes/DropdownFromArrayAttribute.cs @@ -1,74 +1,21 @@ -#if UNITY_EDITOR -using UnityEditor; -#endif using UnityEngine; namespace RealMethod { - public class DropdownFromArrayAttribute : PropertyAttribute + /// + /// + /// public string[] options = new string[] { "Option1", "Option2", "Option3" }; + /// + /// [StaticDropdown("options")] + /// public string selectedOption; + /// + /// + public sealed class DropdownFromArrayAttribute : PropertyAttribute { - public string arrayFieldName; - - public DropdownFromArrayAttribute(string arrayFieldName) - { - this.arrayFieldName = arrayFieldName; - } - } - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(DropdownFromArrayAttribute))] - public class DropdownFromArrayDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - DropdownFromArrayAttribute dropdownAttribute = (DropdownFromArrayAttribute)attribute; - string[] options = GetOptions(property, dropdownAttribute.arrayFieldName); - - if (options != null && options.Length > 0) - { - if (property.propertyType == SerializedPropertyType.String) - { - int index = Mathf.Max(0, System.Array.IndexOf(options, property.stringValue)); - index = EditorGUI.Popup(position, label.text, index, options); - property.stringValue = options[index]; - } - else - { - EditorGUI.LabelField(position, label.text, "Use DropdownFromArray with string."); - } - } - else - { - EditorGUI.LabelField(position, label.text, "Array not found or empty."); - } - } - - private string[] GetOptions(SerializedProperty property, string arrayFieldName) + public string TargetArray; + public DropdownFromArrayAttribute(string array) { - string[] options = null; - Object targetObject = property.serializedObject.targetObject; - System.Type targetType = targetObject.GetType(); - System.Reflection.FieldInfo fieldInfo = targetType.GetField(arrayFieldName); - - if (fieldInfo != null) - { - options = fieldInfo.GetValue(targetObject) as string[]; - } - - return options; - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - return EditorGUI.GetPropertyHeight(property, label, true); + TargetArray = array; } } - -#endif } -// ---Use -// public string[] options = new string[] { "Option1", "Option2", "Option3" }; - -// [DropdownFromArray("options")] -// public string selectedOption; diff --git a/Runtime/Core/Attributes/DropdownFromDictionaryAttribute.cs b/Runtime/Core/Attributes/DropdownFromDictionaryAttribute.cs index b564ee7f..4b3794bc 100644 --- a/Runtime/Core/Attributes/DropdownFromDictionaryAttribute.cs +++ b/Runtime/Core/Attributes/DropdownFromDictionaryAttribute.cs @@ -1,86 +1,26 @@ -using System.Collections.Generic; -#if UNITY_EDITOR -using UnityEditor; -#endif using UnityEngine; namespace RealMethod { - public class DropdownFromDictionaryAttribute : PropertyAttribute + /// + /// + /// public Dictionary options = new Dictionary + /// { + /// { "Key1", "Value1" }, + /// { "Key2", "Value2" }, + /// { "Key3", "Value3" } + /// }; + /// + /// [DropdownFromDictionary("options")] + /// public string selectedOption; + /// + /// + public sealed class DropdownFromDictionaryAttribute : PropertyAttribute { public string dictionaryFieldName; - public DropdownFromDictionaryAttribute(string dictionaryFieldName) { this.dictionaryFieldName = dictionaryFieldName; } } - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(DropdownFromDictionaryAttribute))] - public class DropdownFromDictionaryDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - DropdownFromDictionaryAttribute dropdownAttribute = (DropdownFromDictionaryAttribute)attribute; - string[] options = GetOptions(property, dropdownAttribute.dictionaryFieldName); - - if (options != null && options.Length > 0) - { - if (property.propertyType == SerializedPropertyType.String) - { - int index = Mathf.Max(0, System.Array.IndexOf(options, property.stringValue)); - index = EditorGUI.Popup(position, label.text, index, options); - property.stringValue = options[index]; - } - else - { - EditorGUI.LabelField(position, label.text, "Use DropdownFromDictionary with string."); - } - } - else - { - EditorGUI.LabelField(position, label.text, "Dictionary not found or empty."); - } - } - - private string[] GetOptions(SerializedProperty property, string dictionaryFieldName) - { - string[] options = null; - Object targetObject = property.serializedObject.targetObject; - System.Type targetType = targetObject.GetType(); - System.Reflection.FieldInfo fieldInfo = targetType.GetField(dictionaryFieldName); - - if (fieldInfo != null) - { - var dictionary = fieldInfo.GetValue(targetObject) as Dictionary; - if (dictionary != null) - { - options = new string[dictionary.Count]; - dictionary.Keys.CopyTo(options, 0); - } - } - - return options; - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - return EditorGUI.GetPropertyHeight(property, label, true); - } - } - -#endif } - -// ----Use -// public Dictionary options = new Dictionary -// { -// { "Key1", "Value1" }, -// { "Key2", "Value2" }, -// { "Key3", "Value3" } -// }; - -// [DropdownFromDictionary("options")] -// public string selectedOption; diff --git a/Runtime/Core/Attributes/HelpBoxAttribute.cs b/Runtime/Core/Attributes/HelpBoxAttribute.cs index c924cd72..6c541598 100644 --- a/Runtime/Core/Attributes/HelpBoxAttribute.cs +++ b/Runtime/Core/Attributes/HelpBoxAttribute.cs @@ -1,63 +1,26 @@ using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif namespace RealMethod { - public enum HelpBoxMessageType { None, Info, Warning, Error } - - public class HelpBoxAttribute : PropertyAttribute + /// + /// + /// [HelpBox("This is the first line of the help box.\nThis is the second line of the help box.", {0,1,2,3} )] + /// [TextArea(3, 10)] + /// public string Variable; + /// + /// {0:None,1:Info,2:Warning,3:Error} + /// + public sealed class HelpBoxAttribute : PropertyAttribute { - public string text; - public HelpBoxMessageType messageType; + public int messageType; public int height; - public HelpBoxAttribute(string text, HelpBoxMessageType messageType = HelpBoxMessageType.None, int Boxheight = 2) + public HelpBoxAttribute(string text, int messageType = 0, int Boxheight = 2) { this.text = text; this.messageType = messageType; height = Boxheight; } } - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(HelpBoxAttribute))] - public class HelpBoxDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - HelpBoxAttribute helpBoxAttribute = (HelpBoxAttribute)attribute; - - EditorGUI.BeginProperty(position, label, property); - - // Calculate the height of the help box - var helpBoxHeight = EditorGUIUtility.singleLineHeight * helpBoxAttribute.height; - var helpBoxRect = new Rect(position.x, position.y, position.width, helpBoxHeight); - EditorGUI.HelpBox(helpBoxRect, helpBoxAttribute.text, (MessageType)helpBoxAttribute.messageType); - - // Calculate the position of the property field - var propertyRect = new Rect(position.x, position.y + helpBoxHeight + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); - EditorGUI.PropertyField(propertyRect, property, label); - - EditorGUI.EndProperty(); - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - HelpBoxAttribute helpBoxAttribute = (HelpBoxAttribute)attribute; - var helpBoxHeight = EditorGUIUtility.singleLineHeight * 2; - return helpBoxHeight + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; - } - } - -#endif - - } -// ----Use -// [HelpBox("This is the first line of the help box.\nThis is the second line of the help box.", HelpBoxMessageType.Info)] -// [TextArea(3, 10)] -// public string myMultiLineText; diff --git a/Runtime/Core/Attributes/HideInInspectorByEnumAttribute.cs b/Runtime/Core/Attributes/HideInInspectorByEnumAttribute.cs deleted file mode 100644 index 719a7097..00000000 --- a/Runtime/Core/Attributes/HideInInspectorByEnumAttribute.cs +++ /dev/null @@ -1,68 +0,0 @@ -#if UNITY_EDITOR -using UnityEditor; -#endif -using UnityEngine; - - -namespace RealMethod -{ - public class HideInInspectorByEnumAttribute : PropertyAttribute - { - public string EnumFieldName { get; private set; } - public int EnumValue { get; private set; } - - public HideInInspectorByEnumAttribute(string enumFieldName, int enumValue) - { - EnumFieldName = enumFieldName; - EnumValue = enumValue; - } - } - - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(HideInInspectorByEnumAttribute))] - public class HideInInspectorByEnumDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - HideInInspectorByEnumAttribute hideAttribute = (HideInInspectorByEnumAttribute)attribute; - SerializedProperty enumField = property.serializedObject.FindProperty(hideAttribute.EnumFieldName); - - if (enumField != null && enumField.enumValueIndex == hideAttribute.EnumValue) - { - return; // Do not draw the property if the condition matches. - } - - EditorGUI.PropertyField(position, property, label, true); - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - HideInInspectorByEnumAttribute hideAttribute = (HideInInspectorByEnumAttribute)attribute; - SerializedProperty enumField = property.serializedObject.FindProperty(hideAttribute.EnumFieldName); - - if (enumField != null && enumField.enumValueIndex == hideAttribute.EnumValue) - { - return 0; // Hides the property by returning 0 height. - } - - return EditorGUI.GetPropertyHeight(property, label, true); - } - } -#endif -} - - -///////////Use -// public enum DisplayMode -// { -// Mode1, -// Mode2, -// Mode3 -// } - -// [SerializeField] private DisplayMode displayMode; - -// [HideInInspectorByEnum("displayMode", 0)] // Hide when DisplayMode is Mode1 -// public int mode2SpecificValue; diff --git a/Runtime/Core/Attributes/InjectAttribute.cs b/Runtime/Core/Attributes/InjectAttribute.cs new file mode 100644 index 00000000..3b1f9093 --- /dev/null +++ b/Runtime/Core/Attributes/InjectAttribute.cs @@ -0,0 +1,14 @@ +namespace RealMethod +{ + using System; + + [AttributeUsage( + AttributeTargets.Field | + AttributeTargets.Property | + AttributeTargets.Method | + AttributeTargets.Constructor)] + public sealed class InjectAttribute : Attribute + { + } + +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/InjectAttribute.cs.meta b/Runtime/Core/Attributes/InjectAttribute.cs.meta new file mode 100644 index 00000000..11c4873b --- /dev/null +++ b/Runtime/Core/Attributes/InjectAttribute.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 60e011c06b2fa0642a6b6c0dcc2a74f0 \ No newline at end of file diff --git a/Runtime/Core/Attributes/InterfaceValidationDrawer.cs b/Runtime/Core/Attributes/InterfaceValidationDrawer.cs deleted file mode 100644 index 00b01f31..00000000 --- a/Runtime/Core/Attributes/InterfaceValidationDrawer.cs +++ /dev/null @@ -1,33 +0,0 @@ -#if UNITY_EDITOR - -// public interface IMotion -// { -// void StartMotion(); -// void StopMotion(); -// } - - - -// [CustomPropertyDrawer(typeof(ScriptableObject), true)] -// public class InterfaceValidationDrawer : PropertyDrawer -// { -// public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) -// { -// EditorGUI.BeginProperty(position, label, property); - -// var obj = property.objectReferenceValue; - -// // Ensure the assigned object implements the desired interface -// if (obj != null && !(obj is IMotion)) -// { -// property.objectReferenceValue = null; -// Debug.LogError("Assigned object must implement the IMotion interface."); -// } - -// EditorGUI.PropertyField(position, property, label); - -// EditorGUI.EndProperty(); -// } -// } - -#endif diff --git a/Runtime/Core/Attributes/InterfaceValidationDrawer.cs.meta b/Runtime/Core/Attributes/InterfaceValidationDrawer.cs.meta deleted file mode 100644 index 34144b28..00000000 --- a/Runtime/Core/Attributes/InterfaceValidationDrawer.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: da7b638a07bb1ce4cad9aa63e8fe6057 \ No newline at end of file diff --git a/Runtime/Core/Attributes/LayerAttribute.cs b/Runtime/Core/Attributes/LayerAttribute.cs index 2d16caf6..01b8b6b4 100644 --- a/Runtime/Core/Attributes/LayerAttribute.cs +++ b/Runtime/Core/Attributes/LayerAttribute.cs @@ -1,36 +1,16 @@ -#if UNITY_EDITOR -using UnityEditor; -#endif using UnityEngine; namespace RealMethod { - public class LayerAttribute : PropertyAttribute { } - - -#if UNITY_EDITOR - [CustomPropertyDrawer(typeof(LayerAttribute))] - public class LayerDrawer : PropertyDrawer + /// + /// + /// [DropdownFromStrings("Option1", "Option2", "Option3")] + /// [Layer] + /// public int layer; + /// + /// + public sealed class LayerAttribute : PropertyAttribute { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - if (property.propertyType == SerializedPropertyType.Integer) - { - property.intValue = EditorGUI.LayerField(position, label, property.intValue); - } - else - { - EditorGUI.LabelField(position, label.text, "Use [Layer] with int."); - } - } - } -#endif - - - - // ----Use - // [Dropdown("Option1", "Option2", "Option3")] - // [Layer] - // public int layer; + } } \ No newline at end of file diff --git a/Runtime/Core/Attributes/LineAttribute.cs b/Runtime/Core/Attributes/LineAttribute.cs new file mode 100644 index 00000000..d3c3df29 --- /dev/null +++ b/Runtime/Core/Attributes/LineAttribute.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +namespace RealMethod +{ + [System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = true)] + public sealed class LineAttribute : PropertyAttribute + { + public readonly float Height; + public readonly float Spacing; + + public LineAttribute(float height = 1, float spacing = 10) + { + Height = height; + Spacing = spacing; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/SeparatorAttribute.cs.meta b/Runtime/Core/Attributes/LineAttribute.cs.meta similarity index 100% rename from Runtime/Core/Attributes/SeparatorAttribute.cs.meta rename to Runtime/Core/Attributes/LineAttribute.cs.meta diff --git a/Runtime/Core/Attributes/MinMaxRangeAttribute.cs b/Runtime/Core/Attributes/MinMaxRangeAttribute.cs index 05692f45..312cb44f 100644 --- a/Runtime/Core/Attributes/MinMaxRangeAttribute.cs +++ b/Runtime/Core/Attributes/MinMaxRangeAttribute.cs @@ -1,11 +1,14 @@ using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif namespace RealMethod { - public class MinMaxRangeAttribute : PropertyAttribute + /// + /// + /// [MinMaxRange(0f, 100f)] + /// public Vector2 myRange; + /// + /// + public sealed class MinMaxRangeAttribute : PropertyAttribute { public float minLimit; public float maxLimit; @@ -16,57 +19,4 @@ public MinMaxRangeAttribute(float minLimit, float maxLimit) this.maxLimit = maxLimit; } } - -#if UNITY_EDITOR - [CustomPropertyDrawer(typeof(MinMaxRangeAttribute))] - public class MinMaxRangeDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - if (property.propertyType == SerializedPropertyType.Vector2) - { - MinMaxRangeAttribute range = (MinMaxRangeAttribute)attribute; - - Vector2 value = property.vector2Value; - - EditorGUI.BeginProperty(position, label, property); - - // Draw label - position = EditorGUI.PrefixLabel(position, label); - - // Draw min-max slider - float min = value.x; - float max = value.y; - - float sliderWidth = position.width * 0.6f; - float fieldWidth = (position.width - sliderWidth) / 2f; - - Rect minFieldRect = new Rect(position.x, position.y, fieldWidth - 2, position.height); - Rect sliderRect = new Rect(position.x + fieldWidth, position.y, sliderWidth, position.height); - Rect maxFieldRect = new Rect(position.x + fieldWidth + sliderWidth + 2, position.y, fieldWidth - 2, position.height); - - min = EditorGUI.FloatField(minFieldRect, min); - EditorGUI.MinMaxSlider(sliderRect, ref min, ref max, range.minLimit, range.maxLimit); - max = EditorGUI.FloatField(maxFieldRect, max); - - // Clamp values - min = Mathf.Clamp(min, range.minLimit, max); - max = Mathf.Clamp(max, min, range.maxLimit); - - property.vector2Value = new Vector2(min, max); - - EditorGUI.EndProperty(); - } - else - { - EditorGUI.LabelField(position, label.text, "Use MinMaxRange with Vector2"); - } - } - } -#endif - -} - - -// [MinMaxRange(0f, 100f)] -// public MinMaxFloat myRange; \ No newline at end of file +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/PopupListAttribute.cs b/Runtime/Core/Attributes/PopupListAttribute.cs new file mode 100644 index 00000000..c41c20e5 --- /dev/null +++ b/Runtime/Core/Attributes/PopupListAttribute.cs @@ -0,0 +1,27 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + /// + /// + /// ExampleClass{ + /// public static List options = new List { "Option1", "Option2", "Option3" }; + /// } + /// + /// [ListToPopup(typeof(ExampleClass), "options")] + /// public string selectedOption; + /// + /// + public sealed class PopupListAttribute : PropertyAttribute + { + public Type myType; + public string propertyName; + + public PopupListAttribute(Type _myType, string _propertyName) + { + myType = _myType; + propertyName = _propertyName; + } + } +} diff --git a/Runtime/Core/Attributes/ListToPopupAttribute.cs.meta b/Runtime/Core/Attributes/PopupListAttribute.cs.meta similarity index 100% rename from Runtime/Core/Attributes/ListToPopupAttribute.cs.meta rename to Runtime/Core/Attributes/PopupListAttribute.cs.meta diff --git a/Runtime/Core/Attributes/PureAttribute.cs b/Runtime/Core/Attributes/PureAttribute.cs new file mode 100644 index 00000000..e5b9649b --- /dev/null +++ b/Runtime/Core/Attributes/PureAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace RealMethod +{ + /// + /// + /// [Pure] + /// float A() => 1; + /// [Pure] + /// float B() => A(); // allowed + /// ///////////// + /// float Helper() => 10; // NOT PURE + /// [Pure] + /// float C() => Helper(); // ❌ violation! + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class PureAttribute : Attribute + { + // Empty: marker attribute only + } +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/PureAttribute.cs.meta b/Runtime/Core/Attributes/PureAttribute.cs.meta new file mode 100644 index 00000000..4bc89b08 --- /dev/null +++ b/Runtime/Core/Attributes/PureAttribute.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: dde25feea08c3a947be547bebf7cc6f0 \ No newline at end of file diff --git a/Runtime/Core/Attributes/ReadOnlyAttribute.cs b/Runtime/Core/Attributes/ReadOnlyAttribute.cs index 1ffcbb48..66b001c1 100644 --- a/Runtime/Core/Attributes/ReadOnlyAttribute.cs +++ b/Runtime/Core/Attributes/ReadOnlyAttribute.cs @@ -1,33 +1,12 @@ -#if UNITY_EDITOR -using UnityEditor; -#endif using UnityEngine; namespace RealMethod { - - public class ReadOnlyAttribute : PropertyAttribute { } - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] - public class ReadOnlyDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - GUI.enabled = false; // Disable the GUI - EditorGUI.PropertyField(position, property, label, true); - GUI.enabled = true; // Enable the GUI - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - return EditorGUI.GetPropertyHeight(property, label, true); - } - } - -#endif -} - -// --------Use -// [ReadOnly] public int readOnlyValue = 42; + /// + /// + /// [ReadOnly] + /// public int readOnlyValue = 42; + /// + /// + public sealed class ReadOnlyAttribute : PropertyAttribute { } +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/SeparatorAttribute.cs b/Runtime/Core/Attributes/SeparatorAttribute.cs deleted file mode 100644 index ddf1c30d..00000000 --- a/Runtime/Core/Attributes/SeparatorAttribute.cs +++ /dev/null @@ -1,53 +0,0 @@ -using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif - -namespace Name -{ - - [System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = true)] - public class SeparatorAttribute : PropertyAttribute - { - public readonly float Height; - public readonly float Spacing; - - public SeparatorAttribute(float height = 1, float spacing = 10) - { - Height = height; - Spacing = spacing; - } - } - -#if UNITY_EDITOR - [CustomPropertyDrawer(typeof(SeparatorAttribute))] - public class SeparatorDrawer : DecoratorDrawer - { - public override void OnGUI(Rect position) - { - // get a reference to the attribute - SeparatorAttribute separatorAttribute - = attribute as SeparatorAttribute; - // define the line to draw - Rect separatorRect = new Rect(position.xMin, - position.yMin + separatorAttribute.Spacing, - position.width, - separatorAttribute.Height); - // draw it - EditorGUI.DrawRect(separatorRect, Color.white); - } - - public override float GetHeight() - { - SeparatorAttribute separatorAttribute - = attribute as SeparatorAttribute; - - float totalSpacing = separatorAttribute.Spacing - + separatorAttribute.Height - + separatorAttribute.Spacing; - - return totalSpacing; - } - } -#endif -} \ No newline at end of file diff --git a/Runtime/Core/Attributes/ShowInInspectorByEnumAttribute.cs b/Runtime/Core/Attributes/ShowInInspectorByEnumAttribute.cs deleted file mode 100644 index a7c81dbd..00000000 --- a/Runtime/Core/Attributes/ShowInInspectorByEnumAttribute.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif - -[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] -public class ShowInInspectorByEnumAttribute : PropertyAttribute -{ - public string EnumFieldName { get; } - public object[] ShowValues { get; } - - public ShowInInspectorByEnumAttribute(string enumFieldName, params object[] showValues) - { - EnumFieldName = enumFieldName; - ShowValues = showValues; - } -} - - -#if UNITY_EDITOR - -[CustomPropertyDrawer(typeof(ShowInInspectorByEnumAttribute))] -public class ShowInInspectorByEnumDrawer : PropertyDrawer -{ - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - ShowInInspectorByEnumAttribute showInInspector = (ShowInInspectorByEnumAttribute)attribute; - SerializedProperty enumField = property.serializedObject.FindProperty(showInInspector.EnumFieldName); - - if (enumField != null && IsVisible(enumField, showInInspector.ShowValues)) - { - EditorGUI.PropertyField(position, property, label); - } - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - ShowInInspectorByEnumAttribute showInInspector = (ShowInInspectorByEnumAttribute)attribute; - SerializedProperty enumField = property.serializedObject.FindProperty(showInInspector.EnumFieldName); - - if (enumField != null && IsVisible(enumField, showInInspector.ShowValues)) - { - return EditorGUI.GetPropertyHeight(property, label, true); - } - - return 0; // Hides the property - } - - private bool IsVisible(SerializedProperty enumField, object[] showValues) - { - foreach (var value in showValues) - { - if (enumField.propertyType == SerializedPropertyType.Enum && enumField.enumValueIndex == (int)value) - { - return true; - } - } - - return false; - } -} -#endif - - - - -////Use -// public enum ExampleEnum -// { -// Option1, -// Option2, -// Option3 -// } -// public ExampleEnum exampleEnum; - -// [ShowInInspectorByEnum("exampleEnum", ExampleEnum.Option1, ExampleEnum.Option3)] -// public string visibleOnlyForOption1And3; - -// [ShowInInspectorByEnum("exampleEnum", ExampleEnum.Option2)] -// public int visibleOnlyForOption2; \ No newline at end of file diff --git a/Runtime/Core/Attributes/ShowOnlyAttribute.cs b/Runtime/Core/Attributes/ShowOnlyAttribute.cs index dd988b58..03fa8e7b 100644 --- a/Runtime/Core/Attributes/ShowOnlyAttribute.cs +++ b/Runtime/Core/Attributes/ShowOnlyAttribute.cs @@ -5,48 +5,19 @@ namespace RealMethod { - public class ShowOnlyAttribute : PropertyAttribute + /// + /// + /// [ShowOnly] + /// public float aaa = 123.45678f; + /// [ShowOnly] + /// public int bbb = 234; + /// [ShowOnly] + /// public bool ccc = false; + /// [ShowOnly] + /// bool ddd = true; + /// + /// + public sealed class ShowOnlyAttribute : PropertyAttribute { } - -#if UNITY_EDITOR - [CustomPropertyDrawer(typeof(ShowOnlyAttribute))] - public class ShowOnlyDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) - { - string valueStr; - - switch (prop.propertyType) - { - case SerializedPropertyType.Integer: - valueStr = prop.intValue.ToString(); - break; - case SerializedPropertyType.Boolean: - valueStr = prop.boolValue.ToString(); - break; - case SerializedPropertyType.Float: - valueStr = prop.floatValue.ToString("0.00000"); - break; - case SerializedPropertyType.String: - valueStr = prop.stringValue; - break; - default: - valueStr = "(not supported)"; - break; - } - - EditorGUI.LabelField(position, label.text, valueStr); - } - } -#endif -} - -// Use -// public class MyClass : MonoBehaviour -// { -// [ShowOnly] public float aaa = 123.45678f; -// [ShowOnly] public int bbb = 234; -// [ShowOnly] public bool ccc = false; -// [ShowOnly] [SerializeField] bool ddd = true; -// } \ No newline at end of file +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/ShowTypeAttribute.cs b/Runtime/Core/Attributes/ShowTypeAttribute.cs deleted file mode 100644 index 8417bb7b..00000000 --- a/Runtime/Core/Attributes/ShowTypeAttribute.cs +++ /dev/null @@ -1,88 +0,0 @@ - -using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif -using System; -using System.Linq; - - - -namespace RealMethod -{ - [Serializable] - public class TypeReference - { - public string typeName; - - public Type Type - { - get { return string.IsNullOrEmpty(typeName) ? null : Type.GetType(typeName); } - set { typeName = value == null ? string.Empty : value.AssemblyQualifiedName; } - } - - public TypeReference() { } - - public TypeReference(Type type) - { - Type = type; - } - } - - public class TypeSelectorAttribute : PropertyAttribute - { - public Type BaseType { get; private set; } - - public TypeSelectorAttribute(Type baseType = null) - { - BaseType = baseType ?? typeof(object); - } - } - - -#if UNITY_EDITOR - [CustomPropertyDrawer(typeof(TypeSelectorAttribute))] - public class TypeReferenceDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - TypeSelectorAttribute typeSelector = (TypeSelectorAttribute)attribute; - - // Find the type reference field - SerializedProperty typeNameProperty = property.FindPropertyRelative("typeName"); - - // Get all types derived from the specified base type - Type[] types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(assembly => assembly.GetTypes()) - .Where(t => typeSelector.BaseType.IsAssignableFrom(t) && !t.IsAbstract) - .ToArray(); - - // Get the current type - string currentTypeName = typeNameProperty.stringValue; - Type currentType = !string.IsNullOrEmpty(currentTypeName) ? Type.GetType(currentTypeName) : null; - - // Get type names for the dropdown - string[] typeNames = types.Select(t => t.FullName).ToArray(); - int currentIndex = System.Array.IndexOf(typeNames, currentType?.FullName); - - // Show the dropdown in the Inspector - int selectedIndex = EditorGUI.Popup(position, label.text, currentIndex, typeNames); - - // Update the selected type - if (selectedIndex >= 0 && selectedIndex < types.Length) - { - typeNameProperty.stringValue = types[selectedIndex].AssemblyQualifiedName; - } - else - { - typeNameProperty.stringValue = string.Empty; - } - } - } -#endif - -} - -//Use -//[TypeSelector(typeof(MonoBehaviour))] // You can specify the base type here -//public TypeReference selectedType; \ No newline at end of file diff --git a/Runtime/Core/Attributes/SlugAttribute.cs b/Runtime/Core/Attributes/SlugAttribute.cs new file mode 100644 index 00000000..97847d9f --- /dev/null +++ b/Runtime/Core/Attributes/SlugAttribute.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +public class SlugAttribute : PropertyAttribute +{ + // Scale the width (0.0 = tiny, 1.0 = normal) + public float WidthScale = 0.5f; + public SlugAttribute(float _widthScale = 0.5f) + { + WidthScale = _widthScale; + } +} diff --git a/Runtime/Core/Attributes/SlugAttribute.cs.meta b/Runtime/Core/Attributes/SlugAttribute.cs.meta new file mode 100644 index 00000000..0e8e171c --- /dev/null +++ b/Runtime/Core/Attributes/SlugAttribute.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c708d0a804cfd3f4d95287b25667e0dd \ No newline at end of file diff --git a/Runtime/Core/Attributes/TagSelectorAttribute.cs b/Runtime/Core/Attributes/TagSelectorAttribute.cs index 6cfff5a5..0d9a288f 100644 --- a/Runtime/Core/Attributes/TagSelectorAttribute.cs +++ b/Runtime/Core/Attributes/TagSelectorAttribute.cs @@ -1,45 +1,14 @@ using UnityEngine; -#if UNITY_EDITOR -using UnityEditor; -#endif namespace RealMethod { - public class TagSelectorAttribute : PropertyAttribute + /// + /// + /// [TagSelector] + /// + /// + public sealed class TagSelectorAttribute : PropertyAttribute { public bool UseDefaultTagFieldDrawer = false; } - - -#if UNITY_EDITOR - - [CustomPropertyDrawer(typeof(TagSelectorAttribute))] - public class TagSelectorPropertyDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - TagSelectorAttribute tagSelector = (TagSelectorAttribute)attribute; - - if (tagSelector.UseDefaultTagFieldDrawer) - { - EditorGUI.PropertyField(position, property, label); - } - else - { - if (property.propertyType == SerializedPropertyType.String) - { - property.stringValue = EditorGUI.TagField(position, label, property.stringValue); - } - else - { - EditorGUI.PropertyField(position, property, label); - EditorGUI.HelpBox(position, "TagSelector can only be used with strings.", MessageType.Error); - } - } - } - } -#endif -} - -//Use -// [TagSelector] +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/TypeSelectorAttribute.cs b/Runtime/Core/Attributes/TypeSelectorAttribute.cs new file mode 100644 index 00000000..b1389c7b --- /dev/null +++ b/Runtime/Core/Attributes/TypeSelectorAttribute.cs @@ -0,0 +1,22 @@ + +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif +using System; +using System.Linq; + + + +namespace RealMethod +{ + public sealed class TypeSelectorAttribute : PropertyAttribute + { + public Type BaseType { get; private set; } + + public TypeSelectorAttribute(Type baseType = null) + { + BaseType = baseType ?? typeof(object); + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Attributes/ShowTypeAttribute.cs.meta b/Runtime/Core/Attributes/TypeSelectorAttribute.cs.meta similarity index 100% rename from Runtime/Core/Attributes/ShowTypeAttribute.cs.meta rename to Runtime/Core/Attributes/TypeSelectorAttribute.cs.meta diff --git a/Runtime/ReadySet/DefaultsClass.meta b/Runtime/Core/DefaultClass.meta similarity index 100% rename from Runtime/ReadySet/DefaultsClass.meta rename to Runtime/Core/DefaultClass.meta diff --git a/Runtime/Core/DefaultClass/DefaultGameBridge.cs b/Runtime/Core/DefaultClass/DefaultGameBridge.cs new file mode 100644 index 00000000..a0a636e0 --- /dev/null +++ b/Runtime/Core/DefaultClass/DefaultGameBridge.cs @@ -0,0 +1,11 @@ +using System; + +namespace RealMethod +{ + public sealed class DefaultGameBridge : GameBridge + { + public DefaultGameBridge(Action method) : base(method) + { + } + } +} \ No newline at end of file diff --git a/Runtime/Core/DefaultClass/DefaultGameBridge.cs.meta b/Runtime/Core/DefaultClass/DefaultGameBridge.cs.meta new file mode 100644 index 00000000..a694d818 --- /dev/null +++ b/Runtime/Core/DefaultClass/DefaultGameBridge.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0b901207892a9954dab8c1d7f64585d2 \ No newline at end of file diff --git a/Runtime/ReadySet/DefaultsClass/DefaultGameConfig.cs b/Runtime/Core/DefaultClass/DefaultGameConfig.cs similarity index 76% rename from Runtime/ReadySet/DefaultsClass/DefaultGameConfig.cs rename to Runtime/Core/DefaultClass/DefaultGameConfig.cs index bcde6ed8..eb351eda 100644 --- a/Runtime/ReadySet/DefaultsClass/DefaultGameConfig.cs +++ b/Runtime/Core/DefaultClass/DefaultGameConfig.cs @@ -4,12 +4,7 @@ namespace RealMethod { public sealed class DefaultGameConfig : GameConfig { - public override void Initialized(Game Author) - { - Debug.Log("DefaultConfig Loaded"); - } - - protected override void OnEnable() + private void OnEnable() { if (HasCloneName()) { @@ -17,6 +12,7 @@ protected override void OnEnable() Destroy(this); return; } + Debug.Log("DefaultConfig Loaded"); } } -} +} \ No newline at end of file diff --git a/Runtime/Core/DefaultClass/DefaultGameConfig.cs.meta b/Runtime/Core/DefaultClass/DefaultGameConfig.cs.meta new file mode 100644 index 00000000..ea55e35d --- /dev/null +++ b/Runtime/Core/DefaultClass/DefaultGameConfig.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a4cc479376d66c44f948e7d169085cb0 \ No newline at end of file diff --git a/Runtime/ReadySet/DefaultsClass/DefaultWorld.cs b/Runtime/Core/DefaultClass/DefaultWorld.cs similarity index 51% rename from Runtime/ReadySet/DefaultsClass/DefaultWorld.cs rename to Runtime/Core/DefaultClass/DefaultWorld.cs index 1712602f..68cac716 100644 --- a/Runtime/ReadySet/DefaultsClass/DefaultWorld.cs +++ b/Runtime/Core/DefaultClass/DefaultWorld.cs @@ -5,13 +5,13 @@ namespace RealMethod [AddComponentMenu("RealMethod/Essential/DefaultWorld")] public sealed class DefaultWorld : World { - protected override void AwakeWorld() + protected override void WorldBegin() { - Debug.Log("DefaultWorld Awaked"); + Debug.Log("DefaultWorld Begin"); } - protected override void DestroyWorld() + protected override void WorldEnd() { - Debug.Log("DefaultWorld Destroyed"); + Debug.Log("DefaultWorld End"); } } } \ No newline at end of file diff --git a/Runtime/Core/DefaultClass/DefaultWorld.cs.meta b/Runtime/Core/DefaultClass/DefaultWorld.cs.meta new file mode 100644 index 00000000..dfc3ba54 --- /dev/null +++ b/Runtime/Core/DefaultClass/DefaultWorld.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 943a52a6287851443a5d5533c5f32179 \ No newline at end of file diff --git a/Runtime/Core/DefaultClass/DefultGame.cs b/Runtime/Core/DefaultClass/DefultGame.cs new file mode 100644 index 00000000..02652de2 --- /dev/null +++ b/Runtime/Core/DefaultClass/DefultGame.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace RealMethod +{ + [AddComponentMenu("RealMethod/Essential/DefultGame")] + public sealed class DefultGame : Game + { + protected override void OnGameOpen() + { + Debug.Log("DefultGame Opened"); + } + protected override void OnGameInitialized() + { + AddModule(); + Debug.Log("DefultGame Initialized"); + } + protected override void OnGameStart() + { + Debug.Log("DefultGame Started"); + } + protected override void OnWorldChanged(World NewWorld) + { + Debug.Log($"New world assign: {NewWorld}"); + } + protected override void OnGameClosed() + { + Debug.Log("DefultGame Closed"); + } + + + } +} \ No newline at end of file diff --git a/Runtime/Core/DefaultClass/DefultGame.cs.meta b/Runtime/Core/DefaultClass/DefultGame.cs.meta new file mode 100644 index 00000000..9a70b437 --- /dev/null +++ b/Runtime/Core/DefaultClass/DefultGame.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c771ef0ee64623c498c795821ba35b23 \ No newline at end of file diff --git a/Runtime/Core/Definitions/Assets.cs b/Runtime/Core/Definitions/Assets.cs index fc408592..4375ec00 100644 --- a/Runtime/Core/Definitions/Assets.cs +++ b/Runtime/Core/Definitions/Assets.cs @@ -1,26 +1,59 @@ using UnityEngine; + #if UNITY_EDITOR using UnityEditor; #endif namespace RealMethod { - public interface IAsset + public interface IAsset : IIdentifier { PrimitiveAsset GetAsset(); - void OnSpawned(Object spawner); } - // PrimitiveAsset: is a ScriptableObject with some functions & IAsset interface - public abstract class PrimitiveAsset : ScriptableObject, IAsset + + /// + /// Base class for all custom asset types in the system. + /// Provides shared functionality and common rules for assets derived from ScriptableObject, + /// such as cloning, instancing, or direct usage depending on the derived asset type. + /// + public abstract class PrimitiveAsset : ScriptableObject, IAsset, ISpawn, ISpawnWithAuthor { + public bool IsSpawned { get; private set; } = false; + + // Implement IIdentifier Interface + public Name16 NameID => name; // Implement IAsset Interface - PrimitiveAsset IAsset.GetAsset() + PrimitiveAsset IAsset.GetAsset() => this; + // Implement ISpawn interface + void ISpawn.OnSpawn() { - return this; + IsSpawned = true; + EnsureAssetPermission(); + OnSpawn(null); } - public virtual void OnSpawned(Object spawner) + // Implement ISpawnWithAuthor interface + void ISpawnWithAuthor.OnSpawn(Object author) { + IsSpawned = true; + EnsureAssetPermission(); + OnSpawn(author); + } + + protected virtual void OnSpawn(Object spawner) + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + Debug.Log($"[{name}] Spawned"); +#endif + } + /// + /// Ensures this asset can be used safely. Throws an error if it's not. + /// + protected virtual void EnsureAssetPermission() + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + Debug.LogError($"[{name}] For this asset didnt write any permission."); +#endif } public bool HasCloneName() @@ -44,71 +77,87 @@ public bool IsProjectAsset() #endif } + #if UNITY_EDITOR - public virtual void OnEditorPlay() + /// + /// Returns whether Reset() should be automatically called for the given + /// PlayModeStateChange. If this method returns true, Unity's Reset() method + /// on this ScriptableObject will be invoked for that state. + /// + /// The current play mode state change. + public virtual bool AutoReset(PlayModeStateChange state) { - Debug.Log($"[{GetType()}] -> {name} OnEditorPlay called."); + return false; } #endif } - // DataAsset: is just a PrimitiveAsset + /// + /// A standard asset used to store data. + /// Developers can create and use these assets directly in the project + /// and access the functionality provided by PrimitiveAsset. + /// public abstract class DataAsset : PrimitiveAsset { + } - // TemplateAsset: is a PrimitiveAsset that you can't create new at runtime - public abstract class TemplateAsset : PrimitiveAsset + /// + /// Represents an asset used only as a clone. + /// This asset cannot be used directly or instantiated normally. + /// Its purpose is to generate clones that will be used instead of the original asset. + /// + public abstract class CloneAsset : PrimitiveAsset { - protected virtual void OnEnable() + protected sealed override void EnsureAssetPermission() { +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (!HasCloneName()) { if (!IsProjectAsset()) { - Debug.LogError($"TemplateAsset Can't Create New Instance at Runtime, NewFile Removed!"); - Destroy(this); + Debug.LogError($"[{name}] CloneAsset cannot create new instance at runtime. Asset has been removed!"); + DestroyImmediate(this); return; } } +#endif } + } - // FileAsset: is a PrimitiveAsset that you can't clone at runtime - public abstract class FileAsset : PrimitiveAsset - { - protected virtual void OnEnable() - { - if (HasCloneName()) - { - Debug.LogError($"FileAsset Can't Clone at Runtime, NewFile Removed!"); - Destroy(this); - return; - } - } - } - // UniqueAsset: is a PrimitiveAsset that you can't clone or create new at runtime + /// + /// Represents a unique shared asset in the project. + /// Developers must use the asset directly and cannot clone it + /// or create new instances from it. + /// public abstract class UniqueAsset : PrimitiveAsset { - protected virtual void OnEnable() + protected override void EnsureAssetPermission() { +#if UNITY_EDITOR || DEVELOPMENT_BUILD if (HasCloneName()) { - Debug.LogError($"UniqueAsset Can't Clone at Runtime, NewFile Removed!"); - Destroy(this); + Debug.LogError($"[{name}] UniqueAsset cannot clone at runtime. NewAsset has been removed!"); + DestroyImmediate(this); return; } if (!IsProjectAsset()) { - Debug.LogError($"UniqueAsset Can't Create New Instance at Runtime, NewFile Removed!"); - Destroy(this); + Debug.LogError($"[{name}] UniqueAsset cannot create new instance at runtime. NewAsset has been removed!"); + DestroyImmediate(this); return; } +#endif } } - // ConfigAsset: is a UniqueAsset that you can't decelar modifier variable or method , all of things should be readonly + /// + /// A specialized UniqueAsset used for global configuration. + /// The asset is intended to be read-only at runtime, + /// and developers should not add mutable fields or methods + /// that modify its configuration values. + /// public abstract class ConfigAsset : UniqueAsset { } - -} \ No newline at end of file +} diff --git a/Runtime/Core/Definitions/Context.cs b/Runtime/Core/Definitions/Context.cs new file mode 100644 index 00000000..b958b22f --- /dev/null +++ b/Runtime/Core/Definitions/Context.cs @@ -0,0 +1,72 @@ +using System; + +namespace RealMethod +{ + + /// + /// Generic singleton base class. + /// Ensures only one instance of type exists. + /// + public abstract class Context : IDisposable where T : Context, new() + { + private static T _instance; + private static readonly object _lock = new object(); + + + + /// + /// Gets the single instance of this type. + /// + public static T Instance + { + get + { + lock (_lock) + { + if (_instance == null) + { + // Use Reflection to create the instance since + // the constructor is private/protected + _instance = (T)Activator.CreateInstance(typeof(T), true); + } + return _instance; + } + } + } + + /// + /// Prevents external instantiation. + /// + protected Context() + { + OnBegin(); + } + + /// + /// Cleans up the singleton instance. + /// + public virtual void Dispose() + { + lock (_lock) + { + if (_instance != null) + { + OnEnd(); + _instance = null; // Removing the reference + } + } + } + + + + + /// + /// Override this to perform custom Starter logic (like Subscribing events). + /// + protected abstract void OnBegin(); + /// + /// Override this to perform custom cleanup logic (like Unsubscribing events). + /// + protected abstract void OnEnd(); + } +} diff --git a/Runtime/Core/Definitions/Context.cs.meta b/Runtime/Core/Definitions/Context.cs.meta new file mode 100644 index 00000000..5c5d1af2 --- /dev/null +++ b/Runtime/Core/Definitions/Context.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 67b9ab8283ceda845835bf1a2c7ba940 \ No newline at end of file diff --git a/Runtime/Core/Definitions/Draw.cs b/Runtime/Core/Definitions/Draw.cs new file mode 100644 index 00000000..f81f98d7 --- /dev/null +++ b/Runtime/Core/Definitions/Draw.cs @@ -0,0 +1,24 @@ + +namespace RealMethod +{ + public enum DrawMode + { + GUI, + Gizmo, + } + + public interface IDraw : IIdentifier + { + bool CanDraw(int Index); + void Draw(int Index); + } + + public interface IDrawTask : IDraw, ITask + { + int Priority { get; } + bool IsExpired(); + DrawMode GetDrawMode(); + } + + +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/Draw.cs.meta b/Runtime/Core/Definitions/Draw.cs.meta new file mode 100644 index 00000000..86560409 --- /dev/null +++ b/Runtime/Core/Definitions/Draw.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4dfe7e9297074ca49ab4d715a4a69902 \ No newline at end of file diff --git a/Runtime/Core/Definitions/Event.cs b/Runtime/Core/Definitions/Event.cs new file mode 100644 index 00000000..d0b3a2f1 --- /dev/null +++ b/Runtime/Core/Definitions/Event.cs @@ -0,0 +1,4 @@ +namespace RealMethod +{ + public interface IEvent { } +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/Event.cs.meta b/Runtime/Core/Definitions/Event.cs.meta new file mode 100644 index 00000000..4b3b9560 --- /dev/null +++ b/Runtime/Core/Definitions/Event.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 602ac2be96ab007448d28dd436ea78ae \ No newline at end of file diff --git a/Runtime/Core/Definitions/Extensions.cs b/Runtime/Core/Definitions/Extensions.cs new file mode 100644 index 00000000..6f457ab1 --- /dev/null +++ b/Runtime/Core/Definitions/Extensions.cs @@ -0,0 +1,15 @@ +namespace RealMethod +{ + public static class Extensions + { + public static bool IsGameScope(this Scope target) + { + return target is Game; + } + public static bool IsWorldScope(this Scope target) + { + return target is World; + } + + } +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/Extensions.cs.meta b/Runtime/Core/Definitions/Extensions.cs.meta new file mode 100644 index 00000000..459f9ae1 --- /dev/null +++ b/Runtime/Core/Definitions/Extensions.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 43e8dfce657418446b4075c5897ecf40 \ No newline at end of file diff --git a/Runtime/Core/Definitions/Feature.cs b/Runtime/Core/Definitions/Feature.cs new file mode 100644 index 00000000..c363f02a --- /dev/null +++ b/Runtime/Core/Definitions/Feature.cs @@ -0,0 +1,8 @@ +namespace RealMethod +{ + public interface IFeature + { + + } + +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/Feature.cs.meta b/Runtime/Core/Definitions/Feature.cs.meta new file mode 100644 index 00000000..370e6846 --- /dev/null +++ b/Runtime/Core/Definitions/Feature.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 37c641f6b55f84749a203eaf44e249b8 \ No newline at end of file diff --git a/Runtime/Core/Definitions/File.cs b/Runtime/Core/Definitions/File.cs new file mode 100644 index 00000000..beafc4a0 --- /dev/null +++ b/Runtime/Core/Definitions/File.cs @@ -0,0 +1,20 @@ +namespace RealMethod +{ + // FILE + public interface IFile : IIdentifier + { + string FileName { get; } + } + + + /// + /// this is UniqueAsset that implement ISaveFile Interface with some Editor Function + /// for testing save and load + /// + public abstract class FileAsset : UniqueAsset, IFile + { + // Implement IFile Interface + string IFile.FileName => name; + } + +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/File.cs.meta b/Runtime/Core/Definitions/File.cs.meta new file mode 100644 index 00000000..9f0eba54 --- /dev/null +++ b/Runtime/Core/Definitions/File.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9d6971ea25ef788479f2dd1c7f6897ee \ No newline at end of file diff --git a/Runtime/Core/Definitions/GlobalEnum.cs b/Runtime/Core/Definitions/GlobalEnum.cs new file mode 100644 index 00000000..64cd4703 --- /dev/null +++ b/Runtime/Core/Definitions/GlobalEnum.cs @@ -0,0 +1,83 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + /// + /// This struct stores a game status as a byte index. + /// The actual readable names are not stored here. + /// Instead, the names are defined in a global list + /// inside ProjectSettingsAsset that just compile in editor. + /// + [Serializable] + public struct GlobalEnum + { + [SerializeField] + private int Value; // <-- this name must match + + + public static bool operator ==(GlobalEnum a, GlobalEnum b) + { + return a.Value == b.Value; + } + public static bool operator !=(GlobalEnum a, GlobalEnum b) + { + return a.Value != b.Value; + } + public static bool operator <(GlobalEnum a, GlobalEnum b) + { + return a.Value < b.Value; + } + public static bool operator >(GlobalEnum a, GlobalEnum b) + { + return a.Value > b.Value; + } + public static bool operator <=(GlobalEnum a, GlobalEnum b) + { + return a.Value <= b.Value; + } + public static bool operator >=(GlobalEnum a, GlobalEnum b) + { + return a.Value >= b.Value; + } + + + + public override bool Equals(object obj) + { + return obj is GlobalEnum other && other.Value == Value; + } + public override int GetHashCode() + { + return Value.GetHashCode(); + } + + +#if UNITY_EDITOR + public override string ToString() + { + var ProjectSettings = ProjectSettingAsset.Load(); + if (ProjectSettings) + { + var names = ProjectSettings.Status; + if (names == null || Value >= names.Count) + return "Undefined"; + return names[Value]; + } + else + { + return $"GlobalEnum index [{Value}]"; + } + + } +#else + public override string ToString() + { + return $"GlobalEnum index [{Value}]"; + } +#endif + + + + } +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/GlobalEnum.cs.meta b/Runtime/Core/Definitions/GlobalEnum.cs.meta new file mode 100644 index 00000000..bdede599 --- /dev/null +++ b/Runtime/Core/Definitions/GlobalEnum.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a7798e11590785c479b5e152a3cd2ba5 \ No newline at end of file diff --git a/Runtime/Core/Definitions/Identifier.cs b/Runtime/Core/Definitions/Identifier.cs index 7564b908..8e828816 100644 --- a/Runtime/Core/Definitions/Identifier.cs +++ b/Runtime/Core/Definitions/Identifier.cs @@ -1,7 +1,41 @@ +using System; + namespace RealMethod { + /// + /// Represents a base contract for objects that can identify themselves. + /// Provides access to the current instance through the property. + /// This interface serves as the root for different identifier strategies. + /// public interface IIdentifier { - string NameID { get; } + /// + /// Gets the current instance of the implementing object. + /// Useful for generic identifier handling where the object reference is needed. + /// + object Self => this; + } + /// + /// Represents an identifier based on a human-readable name. + /// The name acts as a unique or semi-unique identifier within a specific context. + /// + public interface INameIdentifier : IIdentifier + { + /// + /// Gets the name used to identify the object. + /// The value may be formatted using the attribute. + /// + string SelfName { get; } + } + /// + /// Represents an identifier based on a globally unique identifier (GUID). + /// This ensures uniqueness across systems, sessions, and instances. + /// + public interface IGuidIdentifier : IIdentifier + { + /// + /// Gets the globally unique identifier associated with the object. + /// + Guid SelfID { get; } } } \ No newline at end of file diff --git a/Runtime/Core/Definitions/InspectorInfo.cs b/Runtime/Core/Definitions/InspectorInfo.cs new file mode 100644 index 00000000..a2624a99 --- /dev/null +++ b/Runtime/Core/Definitions/InspectorInfo.cs @@ -0,0 +1,16 @@ +namespace RealMethod +{ + public interface IInspectorInfo + { +#if UNITY_EDITOR + string GetTitleInfo() => GetType().Name; + /// + /// Returns a formatted string containing information about any object can show properties + /// intended for display in the Unity Inspector or debugging interfaces. + /// This method is for visualization purposes only and must not affect logic. + /// + /// Formatted display information. + string GetInfo(); +#endif + } +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/InspectorInfo.cs.meta b/Runtime/Core/Definitions/InspectorInfo.cs.meta new file mode 100644 index 00000000..b1251df9 --- /dev/null +++ b/Runtime/Core/Definitions/InspectorInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1d6b0a4bb10ab3a478b1d62bd5e92926 \ No newline at end of file diff --git a/Runtime/Core/Definitions/Name16.cs b/Runtime/Core/Definitions/Name16.cs new file mode 100644 index 00000000..01e056e1 --- /dev/null +++ b/Runtime/Core/Definitions/Name16.cs @@ -0,0 +1,132 @@ +using System; +using System.Text; +using UnityEngine; + + + +namespace RealMethod +{ + /// + /// String identifier. + /// Store 16 character with very fast compairing + /// + [Serializable] + public struct Name16 + { + [SerializeField] + public ulong Name_A; + [SerializeField] + public ulong Name_B; + + /// + /// Creates a Name16 from a string. + /// + public Name16(string value) + { + if (value.Length > 16) + throw new ArgumentException($"Name cannot exceed {16} characters."); + + Name_A = 0; + Name_B = 0; + + if (string.IsNullOrEmpty(value)) + return; + + int len = Math.Min(16, value.Length); + + for (int i = 0; i < len; i++) + { + byte b = (byte)value[i]; + + if (i < 8) + Name_A |= ((ulong)b) << (i * 8); + else + Name_B |= ((ulong)b) << ((i - 8) * 8); + } + } + + + /// + /// Checks equality with another Name. + /// + public bool Equals(Name16 other) + { + return this == other; + } + + + /// + /// Converts Name to string. + /// + public override string ToString() + { + Span bytes = stackalloc byte[16]; + + for (int i = 0; i < 8; i++) + bytes[i] = (byte)((Name_A >> (i * 8)) & 0xFF); + + for (int i = 0; i < 8; i++) + bytes[i + 8] = (byte)((Name_B >> (i * 8)) & 0xFF); + + int len = 16; + while (len > 0 && bytes[len - 1] == 0) + len--; + + return Encoding.ASCII.GetString(bytes.Slice(0, len)); + } + /// + /// Checks equality with an object. + /// + public override bool Equals(object obj) + { + return obj is Name16 other && Equals(other); + } + /// + /// Hash code of the Name. + /// + public override int GetHashCode() + { + return HashCode.Combine(Name_A, Name_B); + } + + + + /// + /// Implicit conversion from string. + /// + public static implicit operator Name16(string value) + { + return new Name16(value); + } + /// + /// Implicit conversion to string. + /// + public static implicit operator string(Name16 value) + { + return value.ToString(); + } + /// + /// Equality operator. + /// + public static bool operator ==(Name16 a, Name16 b) + { + return a.Name_A == b.Name_A && a.Name_B == b.Name_B; + } + /// + /// Inequality operator. + /// + public static bool operator !=(Name16 a, Name16 b) + { + return !(a == b); + } + + } + + + + +} + + + + diff --git a/Runtime/Core/Definitions/Name16.cs.meta b/Runtime/Core/Definitions/Name16.cs.meta new file mode 100644 index 00000000..001e53fb --- /dev/null +++ b/Runtime/Core/Definitions/Name16.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9c6da38df6f709e40b377b75472167aa \ No newline at end of file diff --git a/Runtime/Core/Definitions/Prefab.cs b/Runtime/Core/Definitions/Prefab.cs index c031ef83..c8b7948c 100644 --- a/Runtime/Core/Definitions/Prefab.cs +++ b/Runtime/Core/Definitions/Prefab.cs @@ -8,16 +8,17 @@ namespace RealMethod public abstract class PrefabCore : IIdentifier { [SerializeField] - private GameObject PrefabAsset; // <-- this name must match - public GameObject asset => PrefabAsset; - public string NameID => PrefabAsset != null ? PrefabAsset.name : "Empty"; + protected GameObject PrefabAsset; // <-- this name must match + + // Implement IIdentidier Interface + public Name16 NameID => PrefabAsset != null ? PrefabAsset.name : "Empty"; // Public Functions - public J GetSoftClass() where J : Component + public J GetSoftComponent() where J : Component { return PrefabAsset.GetComponent(); } - public J[] GetAllSoftClass() where J : Component + public J[] GetSoftComponentsInChildren() where J : Component { return PrefabAsset.GetComponentsInChildren(); } @@ -26,26 +27,35 @@ public bool HasInterface() return PrefabAsset.GetComponent() != null; } + // Override Functions + public override int GetHashCode() => PrefabAsset != null ? PrefabAsset.GetHashCode() : 0; + + // Operator + public static implicit operator GameObject(PrefabCore prefab) + { + return prefab.PrefabAsset; + } + // Abstract Methods public abstract bool IsValid(); - public abstract System.Type GetTargetClass(); // <--- added + public abstract System.Type GetMainType(); // <--- added } // Prefab Class [System.Serializable] public class PrefabCore : PrefabCore where T : Component { - // Prefab Methods + // PrefabCore Methods public override bool IsValid() { - return asset != null && asset.GetComponent() != null; + return PrefabAsset != null && PrefabAsset.GetComponent() != null; } + public override System.Type GetMainType() => typeof(T); // <--- implemented - public T GetSoftClassTarget() + // Public Method + public T GetMainComponent() { - return asset.GetComponent(); + return PrefabAsset.GetComponent(); } - - public override System.Type GetTargetClass() => typeof(T); // <--- implemented } diff --git a/Runtime/Core/Definitions/RealMethodNames.cs b/Runtime/Core/Definitions/RealMethodNames.cs new file mode 100644 index 00000000..440471be --- /dev/null +++ b/Runtime/Core/Definitions/RealMethodNames.cs @@ -0,0 +1,34 @@ +namespace RealMethod +{ + public static class MessageNames + { + // Lifecycle + public const string Spawn = "OnSpawn"; + public const string Despawn = "OnDespawn"; + public const string Die = "OnDie"; + + // Combat + public const string ApplyDamage = "OnTakeDamage"; + + // Attachment + public const string Attach = "OnAttach"; + public const string Detach = "OnDetach"; + + // Save + public const string Save = "OnSave"; + public const string Load = "Onload"; + + // Register + public const string Register = "OnRegister"; + public const string Unregister = "OnUnregister"; + + // Messaenger + public const string Notify = "OnNotify"; + } + + public static class FunctionNames + { + public const string AssetPermission = "EnsureAssetPermission"; + public const string Reset = "Reset"; + } +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/RealMethodNames.cs.meta b/Runtime/Core/Definitions/RealMethodNames.cs.meta new file mode 100644 index 00000000..c3c17a5f --- /dev/null +++ b/Runtime/Core/Definitions/RealMethodNames.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5f841a73e68d0554f983f85c3882199d \ No newline at end of file diff --git a/Runtime/Core/Definitions/SceneAsset.cs b/Runtime/Core/Definitions/SceneAsset.cs new file mode 100644 index 00000000..b36c46f9 --- /dev/null +++ b/Runtime/Core/Definitions/SceneAsset.cs @@ -0,0 +1,62 @@ +using System; +using UnityEngine; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace RealMethod +{ + [Serializable] + public class SceneAsset : ISerializationCallbackReceiver + { +#if UNITY_EDITOR + public UnityEditor.SceneAsset Asset; // Only in editor +#endif + public string ScenePath; + public string ScneName => System.IO.Path.GetFileNameWithoutExtension(ScenePath); + + + // Implement ISerializationCallbackReceiver Interface + public void OnBeforeSerialize() + { +#if UNITY_EDITOR + UpdateScenePath(); +#endif + } + public void OnAfterDeserialize() + { + } + + // Implicit conversion to string + public static implicit operator string(SceneAsset sceneReference) + { + return sceneReference?.ScenePath; + } + + +#if UNITY_EDITOR + private void UpdateScenePath() + { + if (Asset != null) + { + string newPath = AssetDatabase.GetAssetPath(Asset); + if (ScenePath != newPath) + { + ScenePath = newPath; + EditorUtility.SetDirty(Selection.activeObject); + } + } + else + { + ScenePath = string.Empty; + } + } +#endif + + + } +} + + + diff --git a/Runtime/Core/Architecture/SceneReference.cs.meta b/Runtime/Core/Definitions/SceneAsset.cs.meta similarity index 100% rename from Runtime/Core/Architecture/SceneReference.cs.meta rename to Runtime/Core/Definitions/SceneAsset.cs.meta diff --git a/Runtime/Core/Definitions/Services.cs b/Runtime/Core/Definitions/Services.cs new file mode 100644 index 00000000..c5a96e8a --- /dev/null +++ b/Runtime/Core/Definitions/Services.cs @@ -0,0 +1,141 @@ +using UnityEngine; + +namespace RealMethod +{ + public interface IAnalyticsService : IService + { + void Track(string eventName, params object[] arguments); + void LevelStart(int levelIndex); + void LevelComplete(int levelIndex); + void Error(string message, string stacktrace = ""); + } + public interface ISaveService : IService + { + void Load(); + void Save(); + } + public interface ICloudService : ISaveService + { + void Save(object data); + void Load(System.Action onLoaded); + void Sync(); + } + public interface IAuthService : IService + { + void LoginGuest(); + void LoginGoogle(); + void LoginApple(); + void Logout(); + string GetUserId(); + } + public interface ILeaderboardService : IService + { + void Submit(int score); + void GetTop(int count, System.Action onResult); + void GetAroundPlayer(System.Action onResult); + } + public interface IRemoteConfigService : IService + { + void Refresh(System.Action onComplete = null); + T Get(string key, T defaultValue = default); + } + public interface ILogService : IService + { + void Info(string message); + void Warning(string message); + void Error(string message); + } + public interface IStoreService : IService + { + void Purchase(string productId); + void RestorePurchases(); + } + public interface INotificationService : IService + { + void Schedule(string message, int delaySeconds); + void CancelAll(); + } + public interface ISettingsService : ISaveService + { + float Volume { get; set; } + string Language { get; set; } + int GraphicsQuality { get; set; } + } + public interface IDeviceService : IService + { + string UniqueID { get; } + string Platform { get; } + int Memory { get; } + } + public interface IGUIService : IService + { + Vector2 PrintPivot { get; } + int PrintSize { get; } + void SetPivot(Vector2 pivot); + void SetSize(int size); + } + public interface IDebugService : IGUIService + { + float PrintSpace { get; } + event System.Action OnLogWrited; + } + public interface IDeveloperService : IService + { + void ShowFPS(bool active); + void ShowToast(string message); + void SetGodMode(bool active); + } + public interface IStorageService : ISaveService + { + /// + /// Checks whether the specified file exists in the save storage. + /// + bool IsExist(IFile file); + /// + /// Saves the specified file to the save storage. + /// + void Save(IFile file); + /// + /// Loads the specified file from the save storage into memory. + /// + void Load(IFile file); + /// + /// Deletes the specified file from the save storage. + /// + void Delete(IFile file); + /// + /// use for adding file to filelist in savemsystem. + /// if you want to use saveall or geting file with name + /// + /// target file you want adding + /// return true if can add + bool AddFile(IFile file); + /// + /// use for removing file to filelist in savesystem + /// + /// target file you want removing + /// return true if can remove + bool RemoveFile(IFile file); + /// + /// Determines whether the specified file already exists in the file list. + /// Checks by object reference unless IFile implementations override equality. + /// + /// The file instance to check. + /// True if the file is found in the list; otherwise false. + bool HasFile(IFile file); + /// + /// The file that created by savesystem for merging all file selected in sytem to one file + /// + IFile MainSaveFile { get; } + } + public interface ILogService2 : IService + { + void Log(object message, Object context); + void LogWarning(object message, Object context); + void LogError(object message, Object context); + //void LogException(Exception exception, UnityEngine.Object context); + void Assert(object message, Object context); + } + + +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/Services.cs.meta b/Runtime/Core/Definitions/Services.cs.meta new file mode 100644 index 00000000..5fe6ce80 --- /dev/null +++ b/Runtime/Core/Definitions/Services.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 34f4b741d9061d44e9155bc4c54b190c \ No newline at end of file diff --git a/Runtime/Core/Definitions/SoftType.cs b/Runtime/Core/Definitions/SoftType.cs new file mode 100644 index 00000000..33b5e997 --- /dev/null +++ b/Runtime/Core/Definitions/SoftType.cs @@ -0,0 +1,91 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + public abstract class SoftType + { + [SerializeField] + protected string typeName; // => PropertyRelative + public Type Type + { + get => string.IsNullOrEmpty(typeName) ? GetNullType() : Type.GetType(typeName); + set => typeName = value?.AssemblyQualifiedName; + } + + + + // Operations + public static implicit operator Type(SoftType softType) + { + return softType?.Type; + } + public static bool operator ==(SoftType a, SoftType b) + { + if (ReferenceEquals(a, b)) + return true; + + if (a is null || b is null) + return false; + + return a.typeName == b.typeName; + } + public static bool operator !=(SoftType a, SoftType b) + { + return !(a == b); + } + public static bool operator ==(SoftType a, Type b) + { + if (a is null || b is null) + return false; + + return a.typeName == b.AssemblyQualifiedName; + } + public static bool operator !=(SoftType a, Type b) + { + return !(a == b); + } + public static bool operator ==(Type a, SoftType b) + { + return b == a; + } + public static bool operator !=(Type a, SoftType b) + { + return !(b == a); + } + + // Override Methods + public override bool Equals(object obj) + { + if (obj is SoftType other) + return typeName == other.typeName; + + return false; + } + public override int GetHashCode() + { + return typeName?.GetHashCode() ?? 0; + } + + // Abstract Method + protected abstract Type GetNullType(); + } + + [Serializable] + public class SoftType : SoftType where T : class + { + // Operations + public static implicit operator SoftType(Type type) + { + if (type != null && !typeof(T).IsAssignableFrom(type)) + throw new InvalidCastException($"{type} is not assignable to {typeof(T)}"); + + return new SoftType { typeName = type?.AssemblyQualifiedName }; + } + + // SoftType Method + protected override Type GetNullType() => typeof(T); + } + + +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/SoftType.cs.meta b/Runtime/Core/Definitions/SoftType.cs.meta new file mode 100644 index 00000000..86f64ddd --- /dev/null +++ b/Runtime/Core/Definitions/SoftType.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6b2ce29e49455754b96688c6d4125d68 \ No newline at end of file diff --git a/Runtime/Core/Definitions/Task.cs b/Runtime/Core/Definitions/Task.cs new file mode 100644 index 00000000..20c9c97d --- /dev/null +++ b/Runtime/Core/Definitions/Task.cs @@ -0,0 +1,11 @@ +using System; + +namespace RealMethod +{ + public interface ITask + { + void Active(); + void Deactive(); + } + +} \ No newline at end of file diff --git a/Runtime/Core/Definitions/Task.cs.meta b/Runtime/Core/Definitions/Task.cs.meta new file mode 100644 index 00000000..46c96a96 --- /dev/null +++ b/Runtime/Core/Definitions/Task.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e9488560ad3e25c428377b069afeaa1a \ No newline at end of file diff --git a/Runtime/Core/Definitions/WorldAsset.cs b/Runtime/Core/Definitions/WorldAsset.cs new file mode 100644 index 00000000..6b1da7b9 --- /dev/null +++ b/Runtime/Core/Definitions/WorldAsset.cs @@ -0,0 +1,63 @@ + +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor.SceneManagement; +#endif + +namespace RealMethod +{ + /// + /// ScriptableObject for configuring a world scene setup in Unity. + /// Allows specifying a persistent scene and multiple additive layers. + /// + [CreateAssetMenu(fileName = "WorldAsset", menuName = "Scene/World", order = 1)] + public class WorldAsset : UniqueAsset + { + [Header("Scenes")] + /// + /// The persistent scene that is always loaded and acts as the base scene. + /// + [SerializeField] + private SceneAsset persistent; + /// + /// Public getter for the persistent scene. + /// + public SceneAsset Persistent => persistent; + /// + /// Array of additive layer scenes that can be loaded alongside the persistent scene. + /// + [SerializeField] + private SceneAsset[] Layers; + /// + /// Gets the number of additive layer scenes. + /// + public int Count => Layers.Length; + /// + /// Indexer to access additive layer scenes by index. + /// + /// Index of the layer scene. + /// The at the specified index. + public SceneAsset this[int index] => Layers[index]; + + + + +#if UNITY_EDITOR + /// + /// Opens the persistent scene and all additive layer scenes in the editor. + /// Only available in the Unity Editor. + /// + public void OnAssetClick() + { + // Open the persistent base scene in Single mode + EditorSceneManager.OpenScene(Persistent, OpenSceneMode.Single); + + // Open all layer scenes additively + foreach (var item in Layers) + { + EditorSceneManager.OpenScene(item, OpenSceneMode.Additive); + } + } +#endif + } +} \ No newline at end of file diff --git a/Runtime/Core/Architecture/WorldSceneConfig.cs.meta b/Runtime/Core/Definitions/WorldAsset.cs.meta similarity index 100% rename from Runtime/Core/Architecture/WorldSceneConfig.cs.meta rename to Runtime/Core/Definitions/WorldAsset.cs.meta diff --git a/Runtime/Core/Framework.meta b/Runtime/Core/Framework.meta new file mode 100644 index 00000000..0a56ca08 --- /dev/null +++ b/Runtime/Core/Framework.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1b599ae98725ff84c852b9c8a2b26660 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Framework/BaseClass.meta b/Runtime/Core/Framework/BaseClass.meta new file mode 100644 index 00000000..83bb0f02 --- /dev/null +++ b/Runtime/Core/Framework/BaseClass.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0cb2e08d9acb8624aacf270ca02db351 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Framework/BaseClass/GameModule.cs b/Runtime/Core/Framework/BaseClass/GameModule.cs new file mode 100644 index 00000000..4bd04f30 --- /dev/null +++ b/Runtime/Core/Framework/BaseClass/GameModule.cs @@ -0,0 +1,64 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + /// + /// Abstract base class for game modules, providing lifecycle management and integration with the Game system. + /// A is instantiated once per module type + /// and automatically registered by Scope"/>. + /// Implements IBridge, IInspectorInfo, and IDisposable interfaces. + /// + public abstract class GameModule : IBridge, IInspectorInfo, IDisposable + { + /// + /// Initializes a new instance of the GameModule class. + /// Checks if the game is initialized and binds the module to the Game.Bridge. + /// Calls the OnBegin method for initialization. + /// + public GameModule() + { + // Check if you game not initialized + if (!Game.IsGameInitialized) + { + Debug.LogWarning($"Game doesn't initialized !"); + return; + } + Game.Bridge.Bind(this); + OnBegin(); + } + + // Implement IBridge Interface + void IBridge.OnWorldChanged(World world) => OnWorldChanged(); + void IDisposable.Dispose() + { + Game.Bridge.Unbind(this); + OnEnd(); + } + + // Abstraction Methods + protected abstract void OnBegin(); + protected abstract void OnWorldChanged(); + protected abstract void OnEnd(); + +#if UNITY_EDITOR + /// + /// Provides information for the Unity Inspector in the editor. + /// + /// A string containing inspector information. + string IInspectorInfo.GetInfo() + { + return GetInspectorInfo(); + } + /// + /// Can be overridden to provide custom information for the Unity Inspector. + /// Default implementation returns null. + /// + /// A string containing custom inspector information. + protected virtual string GetInspectorInfo() + { + return null; + } +#endif + } +} \ No newline at end of file diff --git a/Runtime/Core/Framework/BaseClass/GameModule.cs.meta b/Runtime/Core/Framework/BaseClass/GameModule.cs.meta new file mode 100644 index 00000000..8527ce4e --- /dev/null +++ b/Runtime/Core/Framework/BaseClass/GameModule.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ec193cd2194f8614eb221434996c3f62 \ No newline at end of file diff --git a/Runtime/Core/Framework/BaseClass/GameSubsystem.cs b/Runtime/Core/Framework/BaseClass/GameSubsystem.cs new file mode 100644 index 00000000..6bc02136 --- /dev/null +++ b/Runtime/Core/Framework/BaseClass/GameSubsystem.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; + +namespace RealMethod +{ + public interface IBootstrap + { + void Setup(GameSubsystem.ShareData data); + } + + public abstract class GameSubsystem : IInspectorInfo, IDisposable, IBootstrap + { + public sealed class ShareData : IInspectorInfo, IDisposable + { + public Dictionary> Repository { get; } + public Dictionary> Events { get; } + + public ShareData(int prewarm) + { + Repository = new Dictionary>(prewarm); + Events = new Dictionary>(prewarm); + } + + + // Implement IDisposable Interface + void IDisposable.Dispose() + { + Repository.Clear(); + Events.Clear(); + } + +#if UNITY_EDITOR + string IInspectorInfo.GetInfo() + { + return $"Repository ({Repository.Count}) , Events ({Events.Count})"; + } +#endif + } + protected ShareData Data { get; private set; } + + + // Implement IBootstrap Interface + void IBootstrap.Setup(ShareData data) + { + Data = data; + OnBegin(); + } + // Implement IDisposable Interface + void IDisposable.Dispose() + { + OnEnd(); + Data = null; + } + + protected abstract void OnBegin(); + protected abstract void OnEnd(); + + +#if UNITY_EDITOR + string IInspectorInfo.GetInfo() + { + return GetInspectorInfor(); + } + protected abstract string GetInspectorInfor(); +#endif + } +} \ No newline at end of file diff --git a/Runtime/Core/Framework/BaseClass/GameSubsystem.cs.meta b/Runtime/Core/Framework/BaseClass/GameSubsystem.cs.meta new file mode 100644 index 00000000..841caeaf --- /dev/null +++ b/Runtime/Core/Framework/BaseClass/GameSubsystem.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e7b025512bcd3a8469548a82c5c07fc1 \ No newline at end of file diff --git a/Runtime/Core/Framework/Kernel.cs b/Runtime/Core/Framework/Kernel.cs new file mode 100644 index 00000000..8163408d --- /dev/null +++ b/Runtime/Core/Framework/Kernel.cs @@ -0,0 +1,114 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + /// + /// The foundational runtime core of the RealMethod framework. + /// Provides the minimal infrastructure required for all higher-level systems, + /// including lightweight dependency injection and the base module/manager pipeline. + /// + /// This class does not implement gameplay logic and is not intended to be used + /// directly by typical developers. Instead, it serves as the internal root that + /// powers , Scope, and Scope. + /// + /// Responsibilities: + /// • Acts as the DI root for registering and resolving services. + /// • Provides the shared base for all game modules and managers. + /// • Defines internal lifecycle hooks used by all scopes. + /// + /// Regular users normally interact only with GameScope or WorldScope, + /// while RealKernel remains an internal framework component. + /// + public abstract class Kernel : MonoBehaviour + { + private static GameSubsystem.ShareData _rpository; + private static ServiceLocator _serviceLocator; + private static DependencyInjection _dependencyInjection; + private static EventBus _eventBus; + + + // GameModules + private static GameSubsystem.ShareData Repo + { + get + { + if (_rpository == null) + { + _rpository = new GameSubsystem.ShareData(10); + } + return _rpository; + } + } + protected static ServiceLocator Services + { + get + { + if (_serviceLocator == null) + { + _serviceLocator = new ServiceLocator(); + ((IBootstrap)_serviceLocator).Setup(Repo); + } + return _serviceLocator; + } + } + protected static DependencyInjection DInjection + { + get + { + if (_dependencyInjection == null) + { + _dependencyInjection = new DependencyInjection(); + ((IBootstrap)_dependencyInjection).Setup(Repo); + } + return _dependencyInjection; + } + } + protected static EventBus EventBus + { + get + { + if (_eventBus == null) + { + _eventBus = new EventBus(); + ((IBootstrap)_eventBus).Setup(Repo); + } + return _eventBus; + } + } + + protected static void ClearKernel() + { + if (_serviceLocator != null) + { + ((IDisposable)_serviceLocator).Dispose(); + _serviceLocator = null; + } + if (_dependencyInjection != null) + { + ((IDisposable)_dependencyInjection).Dispose(); + _dependencyInjection = null; + } + if (_eventBus != null) + { + ((IDisposable)_eventBus).Dispose(); + _eventBus = null; + } + if (_rpository != null) + { + ((IDisposable)_rpository).Dispose(); + _rpository = null; + } + + } + + + +#if UNITY_EDITOR + public virtual IInspectorInfo[] GetAllInfo() + { + return new IInspectorInfo[4] { _rpository, Services, DInjection, EventBus }; + } +#endif + } +} \ No newline at end of file diff --git a/Runtime/Core/Framework/Kernel.cs.meta b/Runtime/Core/Framework/Kernel.cs.meta new file mode 100644 index 00000000..8ec1e6ff --- /dev/null +++ b/Runtime/Core/Framework/Kernel.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 91e1d8f8c6d65f74e8cbe55162d21bfc \ No newline at end of file diff --git a/Runtime/Core/Framework/Scope.cs b/Runtime/Core/Framework/Scope.cs new file mode 100644 index 00000000..d5a1e544 --- /dev/null +++ b/Runtime/Core/Framework/Scope.cs @@ -0,0 +1,437 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace RealMethod +{ + /// + /// An abstract base class that extends to provide a structured + /// container for managing game systems and features within a specific context. + /// + /// Scope instances are responsible for collecting, initializing, and providing access + /// to various implementations. + /// It acts as a localized service locator for its immediate context and potentially + /// delegates to parent scopes for unresolved dependencies. + /// + /// This class defines the core manager lifecycle within a given boundary, such as + /// global application lifetime or a scene-specific context. + /// + /// + /// Developers will typically implement or inherit from concrete Scope types like + /// Scope (for global systems) or Scope (for scene-bound systems). + /// + public abstract class Scope : Kernel + { + /// + /// Returns true if the Game system has one or more module; + /// otherwise, returns false. + /// + public bool HasModule => _gameModules.Count > 0; + public bool IsScopeOpened { get; private set; } = false; + /// + /// Cached array of managers that were instantiated from configured game prefabs or World gameobject. + /// + private IGameManager[] _gameManagers; + /// + /// Cached list of modules that were instantiated from scope functions (add / remove). + /// + private List _gameModules; + + + + /// + /// Attempts to find a manager whose Component matches the specified type . + /// + /// The component type to search for. + /// + /// When this method returns, contains the found component of type if successful; + /// otherwise null. + /// + /// + /// true if a matching manager component was found; otherwise false. + /// + public bool TryFindGameManager(out T result) where T : Component, IGameManager + { + result = null; + + if (IsScopeLive()) + return false; + + if (_gameManagers == null) + { + return false; + } + + foreach (var manager in _gameManagers) + { + if (manager == null) + { + Debug.LogError($"A manager reference({typeof(T)}) has been removed or destroyed. Managers should never be null."); + return false; + } + if (manager.Component is T found) + { + result = found; + return true; + } + } + return false; + } + /// + /// Attempts to locate an existing game service of type within the current scope. + /// If the scope is not active, or the service list is unavailable, the method returns false. + /// Null service entries produce an error log, as game services are expected to remain valid, + /// and the search is aborted. + /// + /// + /// The type of game service to search for. Must inherit from . + /// + /// + /// When the method returns, contains the found service instance if a match is discovered; otherwise null. + /// + /// + /// True if a service of type is found; otherwise false. + /// + public bool TryFindModule(out T result) where T : GameModule + { + result = null; + + if (IsScopeLive()) + return false; + + if (_gameModules == null) + { + return false; + } + + foreach (var service in _gameModules) + { + if (service == null) + { + Debug.LogError($"A GameService reference({typeof(T)}) has been removed or destroyed. GameService should never be null."); + return false; + } + if (service is T targetclass) + { + result = targetclass; + return true; + } + } + return false; + } + /// + /// Creates, stores, and registers a new service of type . + /// If a service of the same type already exists, the method logs a warning and returns null. + /// The created service must implement to be registered and returned. + /// All implemented interfaces derived from are registered + /// in the service container, except the base interface itself. + /// + /// + /// The type of service to create and add. Must inherit from + /// and provide a parameterless constructor. + /// + /// + /// The created service as if successful; otherwise null. + /// + public T AddModule() where T : GameModule, new() + { + if (IsExistsModule()) + { + Debug.LogWarning($"Module of type {typeof(T)} is already added and still alive."); + return null; + } + + // Create Service + T newModule = new T(); + _gameModules.Add(newModule); + RegisterInterface(newModule); + + return newModule; + } + public GameModule AddModule(Type moduleType) + { + if (IsExistsModule(moduleType)) + { + Debug.LogWarning($"Module of type {moduleType.Name} is already added and still alive."); + return null; + } + + if (!typeof(GameModule).IsAssignableFrom(moduleType)) + { + Debug.LogWarning($"Your type({moduleType.Name}) is not assignable to GameModuel"); + return null; + } + + // Create Service + GameModule newModule = (GameModule)Activator.CreateInstance(moduleType); + _gameModules.Add(newModule); + RegisterInterface(newModule); + return newModule; + } + /// + /// Removes a service of type from the scope. + /// If the service exists, it will be unregistered and disposed. + /// + /// + /// Type of the service to remove. + /// + /// + /// True if the service was successfully removed; otherwise false. + /// + public bool RemoveModule() where T : GameModule + { + if (!IsExistsModule()) + { + Debug.LogWarning($"Service of type {typeof(T)} is not exist."); + return false; + } + return RemoveModule(typeof(T)); + } + public void ClearModules() + { + for (int i = 0; i < _gameModules.Count; i++) + { + var interfaces = _gameModules[i].GetType().GetInterfaces(); + foreach (var interf in interfaces) + { + // Only interfaces derived from Interface + if (typeof(IService).IsAssignableFrom(interf)) + { + Services.Unregister(interf); + } + } + ((IDisposable)_gameModules[i]).Dispose(); + _gameModules.RemoveAt(i); + } + _gameModules.Clear(); + } + + + + + /// + /// Opens the scope and initializes managers and services for the provided GameObjects. + /// It collects all instances from the given objects and prepares + /// the internal service container. If the scope is already opened, the call will be ignored. + /// + /// + /// Array of GameObjects that may contain managers to be collected and registered in this scope. + /// + protected void OpenScope(GameObject[] Objects) + { + if (IsScopeOpened) + { + Debug.LogWarning($"{this} This scope it was opend befor."); + return; + } + IsScopeOpened = true; + + _gameModules = new List(10); + + + if (Objects == null) + { + Debug.LogError("OpeningScope failed: GameObject array 'Objects' is null."); + return; + } + + + List result = new List(); + for (int i = 0; i < Objects.Length; i++) + { + var Newmanager = CollectManagers(Objects[i]); + if (Newmanager != null) + { + foreach (var manager in Newmanager) + { + result.Add(manager); + } + } + } + _gameManagers = result.ToArray(); + } + /// + /// Closes the current scope and releases all registered services and managers. + /// All services implementing are unregistered and disposed, + /// and all managers are properly dispensed. If the scope is already closed, + /// the call will be ignored. + /// + protected void CloseScope() + { + if (!IsScopeOpened) + { + Debug.LogWarning($"{this} This scope it was Closed befor."); + return; + } + IsScopeOpened = false; + + for (int i = 0; i < _gameModules.Count; i++) + { + var interfaces = _gameModules[i].GetType().GetInterfaces(); + foreach (var interf in interfaces) + { + // Only interfaces derived from Interface + if (typeof(IService).IsAssignableFrom(interf)) + { + Services.Unregister(interf); + } + } + ((IDisposable)_gameModules[i]).Dispose(); + _gameModules.RemoveAt(i); + } + _gameModules = null; + + foreach (var manager in _gameManagers) + { + DispenseManagers(manager); + } + _gameManagers = null; + + } + + + + + private bool RemoveModule(Type type) + { + if (type == null) + return false; + + + for (int i = 0; i < _gameModules.Count; i++) + { + if (_gameModules[i].GetType() == type) + { + UnregisterInterface(_gameModules[i]); + ((IDisposable)_gameModules[i]).Dispose(); + _gameModules.RemoveAt(i); + return true; + } + } + + Debug.LogWarning($"Service of type {type.Name} not found to remove."); + return false; + } + private IGameManager[] CollectManagers(GameObject Object) + { + if (Object == null) + { + // Debug.LogWarning("CollectManagers: GameObject 'Object' is null."); + return null; + } + + var managers = Object.GetComponents(); + + foreach (var manager in managers) + { + Component comp = manager.Component; + RegisterInterface(comp); + RegisterInterface(comp); + manager.InitiateManager(this); + } + return managers; + } + private void DispenseManagers(IGameManager manager) + { + if (manager == null) + { + Debug.LogWarning("DispenseManagers: Manager 'manager' is null."); + return; + } + Component comp = manager.Component; + UnregisterInterface(comp); + UnregisterInterface(comp); + } + private void RegisterInterface(object comp) + { + if (comp is T) + { + var interfaces = comp.GetType().GetInterfaces(); + + foreach (var i in interfaces) + { + // Skip the base Interface + if (i == typeof(T)) + continue; + + // Only interfaces derived from Interface + if (typeof(T).IsAssignableFrom(i)) + { + Services.Register(comp, i, false); + } + } + } + } + private void UnregisterInterface(object comp) + { + if (comp is T) + { + var interfaces = comp.GetType().GetInterfaces(); + + foreach (var i in interfaces) + { + // Skip the base Interface + if (i == typeof(T)) + continue; + + // Only interfaces derived from Interface + if (typeof(T).IsAssignableFrom(i)) + { + Services.Unregister(i); + } + } + } + } + private bool IsScopeLive() + { + if (!IsScopeOpened) + { + Debug.LogWarning($"First you shoul open Scope."); + return false; + } + return true; + } + private bool IsExistsModule() where T : GameModule + { + foreach (var module in _gameModules) + { + if (module is T) + return true; + } + return false; + } + private bool IsExistsModule(Type moduleType) + { + foreach (var module in _gameModules) + { + if (module.GetType() == moduleType) + return true; + } + return false; + } + + +#if UNITY_EDITOR + public override IInspectorInfo[] GetAllInfo() + { + List Result = new List(); + foreach (var item in base.GetAllInfo()) + { + Result.Add(item); + } + // My Info + var servicesInfo = _gameModules != null ? _gameModules.OfType().ToArray() : Array.Empty(); + foreach (var item in servicesInfo) + { + Result.Add(item); + } + return Result.ToArray(); + } +#endif + + } + + + +} \ No newline at end of file diff --git a/Runtime/Core/Framework/Scope.cs.meta b/Runtime/Core/Framework/Scope.cs.meta new file mode 100644 index 00000000..f8577a3d --- /dev/null +++ b/Runtime/Core/Framework/Scope.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cdc1d3e86457c474ca9464cbbf61f0f6 \ No newline at end of file diff --git a/Runtime/Core/Framework/Subsystems.meta b/Runtime/Core/Framework/Subsystems.meta new file mode 100644 index 00000000..3904b1df --- /dev/null +++ b/Runtime/Core/Framework/Subsystems.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 15362fcc122cff641955c9545d9da9f5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Framework/Subsystems/DependencyInjection.cs b/Runtime/Core/Framework/Subsystems/DependencyInjection.cs new file mode 100644 index 00000000..234514fb --- /dev/null +++ b/Runtime/Core/Framework/Subsystems/DependencyInjection.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; + +namespace RealMethod +{ + public sealed class DependencyInjection : GameSubsystem + { + private readonly object _lock = new(); + private Dictionary> bindings => Data.Repository; + + + // GameSubsystem Methods + protected override void OnBegin() + { + } + protected override void OnEnd() + { + } + + + + /// + /// Registers the specified instance as a dependency in the DI container. + /// After registration, any object resolving or being injected + /// with the same type will receive this instance. + /// + public void Register(T instance, bool overwrite = false) + { + lock (_lock) + { + Type objectType = typeof(T); + if (bindings.TryGetValue(objectType, out var weak)) + { + if (!weak.TryGetTarget(out _)) + { + bindings[objectType] = new WeakReference(instance); + return; + } + + if (overwrite) + { + bindings[objectType] = new WeakReference(instance); + return; + } + + throw new InvalidOperationException( + $"Instance of type {objectType.Name} is already registered and still alive."); + } + + + bindings[objectType] = new WeakReference(instance); + } + } + public bool Unregister() + { + var type = typeof(T); + lock (_lock) + { + return Unregister(type); + } + } + public bool Unregister(Type type) + { + lock (_lock) + { + if (bindings.ContainsKey(type)) + { + return bindings.Remove(type); + } + return false; + } + } + + + /// + /// Injects all fields, properties, and methods marked with [Inject]. + /// Works for MonoBehaviours, ScriptableObjects, and normal classes. + /// + public void Inject(object target) + { + var type = target.GetType(); + + // Fields + foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) + { + if (Attribute.IsDefined(field, typeof(InjectAttribute))) + { + var dependency = Resolve(field.FieldType); + field.SetValue(target, dependency); + } + } + + // Properties + foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) + { + if (Attribute.IsDefined(prop, typeof(InjectAttribute)) && prop.CanWrite) + { + var dependency = Resolve(prop.PropertyType); + prop.SetValue(target, dependency); + } + } + + // Methods + foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) + { + if (Attribute.IsDefined(method, typeof(InjectAttribute))) + { + var parameters = method.GetParameters(); + var args = parameters.Select(p => Resolve(p.ParameterType)).ToArray(); + method.Invoke(target, args); + } + } + } + + + private object Resolve(Type type) + { + // If already registered, return directly + if (bindings != null) + { + if (bindings.TryGetValue(type, out var weak)) + { + if (weak.TryGetTarget(out object existing)) + return existing; + } + + } + + Debug.LogError($"Cannot resolve type {type.Name}: no registered instance or injectable constructor."); + return null; + } + +#if UNITY_EDITOR + protected override string GetInspectorInfor() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + for (int i = 0; i < bindings.Count; i++) + { + var type = bindings.GetKey(i); + if (typeof(IFeature).IsAssignableFrom(type)) + { + var weakRef = bindings.GetValue(i); + if (weakRef.TryGetTarget(out var target)) + sb.AppendLine($"{i}. {type.Name} -> Alive ({target})"); + else + sb.AppendLine($"{i}. {type.Name} -> Collected"); + } + } + return sb.ToString(); + } +#endif + } +} \ No newline at end of file diff --git a/Runtime/Core/Framework/Subsystems/DependencyInjection.cs.meta b/Runtime/Core/Framework/Subsystems/DependencyInjection.cs.meta new file mode 100644 index 00000000..3fea0e7a --- /dev/null +++ b/Runtime/Core/Framework/Subsystems/DependencyInjection.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e6fc0ab6e758e49468a4513618244863 \ No newline at end of file diff --git a/Runtime/Core/Framework/Subsystems/EventBus.cs b/Runtime/Core/Framework/Subsystems/EventBus.cs new file mode 100644 index 00000000..7cdf43e4 --- /dev/null +++ b/Runtime/Core/Framework/Subsystems/EventBus.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace RealMethod +{ + public sealed class EventBus : GameSubsystem + { + private readonly object _lock = new(); + private Dictionary> _subscribers => Data.Events; + + + + // GameSubsystem Methods + protected override void OnBegin() + { + } + protected override void OnEnd() + { + } + + + + + + public void Subscribe(Action listener) + { + var type = typeof(T); + + if (!_subscribers.TryGetValue(type, out var listeners)) + { + listeners = new List(); + _subscribers[type] = listeners; + } + + if (!listeners.Contains(listener)) + { + listeners.Add(listener); + } + } + public void Unsubscribe(Action listener) + { + var type = typeof(T); + + if (!_subscribers.TryGetValue(type, out var listeners)) + return; + + listeners.Remove(listener); + + if (listeners.Count == 0) + { + _subscribers.Remove(type); + } + } + public void Publish(T eventData) + { + var type = typeof(T); + + if (!_subscribers.TryGetValue(type, out var listeners)) + return; + + var listenersCopy = listeners.ToArray(); + + foreach (var listener in listenersCopy) + { + try + { + ((Action)listener)?.Invoke(eventData); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + } + public void Clear() + { + _subscribers.Clear(); + } + + +#if UNITY_EDITOR + protected override string GetInspectorInfor() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + + for (int i = 0; i < _subscribers.Count; i++) + { + var type = _subscribers.GetKey(i); + List weakRef = _subscribers.GetValue(i); + sb.AppendLine($"{i}. {type.Name} -> Listener ({weakRef.Count})"); + } + + return sb.ToString(); + } +#endif + + } + +} \ No newline at end of file diff --git a/Runtime/Core/Framework/Subsystems/EventBus.cs.meta b/Runtime/Core/Framework/Subsystems/EventBus.cs.meta new file mode 100644 index 00000000..e991dba8 --- /dev/null +++ b/Runtime/Core/Framework/Subsystems/EventBus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 78b636ff334a55f4a8ccbafda05b0cf3 \ No newline at end of file diff --git a/Runtime/Core/Framework/Subsystems/ServiceLocator.cs b/Runtime/Core/Framework/Subsystems/ServiceLocator.cs new file mode 100644 index 00000000..441d0ea2 --- /dev/null +++ b/Runtime/Core/Framework/Subsystems/ServiceLocator.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; + +namespace RealMethod +{ + /// + /// Global service locator with automatic garbage collection safety. + /// Stores services by interface type using WeakReferences. + /// Thread‑safe for Register / Get / Remove operations. + /// + public sealed class ServiceLocator : GameSubsystem + { + private readonly object _lock = new(); + private Dictionary> _services => Data.Repository; + + // GameSubsystem Methods + protected override void OnBegin() + { + } + protected override void OnEnd() + { + } + + + /// + /// Register a service instance under its concrete or interface type T. + /// T must implement IService so we know this is a service. + /// Stored internally as WeakReference<object>. + /// + public void Register(T service, bool overwrite = false) + where T : class + { + Register(service, typeof(T), overwrite); + } + /// + /// Register a service instance under its concrete or interface type T. + /// T must implement IService so we know this is a service. + /// Stored internally as WeakReference<object>. + /// + public void Register(object service, Type type = null, bool overwrite = false) + { + Type serviceType = null; + if (type == null) + { + serviceType = service.GetType(); + } + else + { + serviceType = type; + } + + + if (service == null) + throw new ArgumentNullException(nameof(service)); + + if (!serviceType.IsAssignableFrom(service.GetType())) + throw new ArgumentException($"{service.GetType().Name} is not assignable to {serviceType.Name}"); + + lock (_lock) + { + if (_services.TryGetValue(serviceType, out var weak)) + { + if (!weak.TryGetTarget(out _)) + { + _services[serviceType] = new WeakReference(service); + return; + } + + if (overwrite) + { + _services[serviceType] = new WeakReference(service); + return; + } + + throw new InvalidOperationException( + $"Service of type {serviceType.Name} is already registered and still alive."); + } + + _services[serviceType] = new WeakReference(service); + } + } + /// + /// Register only if no live instance is currently registered for T. + /// + public void RegisterIfAbsent(T service) where T : class + { + if (service == null) + throw new ArgumentNullException(nameof(service)); + + var type = typeof(T); + + lock (_lock) + { + if (!_services.TryGetValue(type, out var weak) || + !weak.TryGetTarget(out _)) + { + _services[type] = new WeakReference(service); + } + } + } + /// + /// Get the registered instance for type T. + /// Returns null if not found or GC-collected. + /// You can call this as Get<PlayerObject>(). + /// + public T Get() where T : class + { + var type = typeof(T); + + lock (_lock) + { + if (_services.TryGetValue(type, out var weak)) + { + if (weak.TryGetTarget(out var obj) && obj != null) + { + return obj as T; + } + + // Weak reference dead → remove entry + _services.Remove(type); + } + return null; + } + } + /// + /// Try to get the registered instance for type T. + /// + public bool TryGet(out T result) + { + var type = typeof(T); + + lock (_lock) + { + if (_services.TryGetValue(type, out var weak)) + { + if (weak.TryGetTarget(out var obj) && obj != null) + { + result = (T)obj; + return result != null; + } + + // Weak reference dead → remove entry + _services.Remove(type); + } + + + result = default; + return false; + } + } + /// + /// Check whether a live instance exists for type T. + /// + public bool Exists() where T : class + { + var type = typeof(T); + + lock (_lock) + { + return _services.TryGetValue(type, out var weak) && + weak.TryGetTarget(out _); + } + } + /// + /// Manually unregisters (removes) a service type. + /// + public bool Unregister() where T : class + { + var type = typeof(T); + lock (_lock) + { + return Unregister(type); + } + } + /// + /// Removes the service associated with type + /// from the Service Locator. + /// + /// + /// If no service of this type is registered, the method does nothing. + /// Use this when services are registered using generic calls such as + /// Register<T>(instance). + /// + public bool Unregister(Type type) + { + lock (_lock) + { + if (_services.ContainsKey(type)) + { + return _services.Remove(type); + } + return false; + } + } + /// + /// Force-clears all services from the locator. + /// + public void ClearAll() + { + lock (_lock) + { + foreach (var item in _services) + { + Unregister(item.Key); + } + _services.Clear(); + } + } + + +#if UNITY_EDITOR + protected override string GetInspectorInfor() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + + for (int i = 0; i < _services.Count; i++) + { + var type = _services.GetKey(i); + if (typeof(IService).IsAssignableFrom(type)) + { + var weakRef = _services.GetValue(i); + if (weakRef.TryGetTarget(out var target)) + sb.AppendLine($"{i}. {type.Name} -> Alive ({target})"); + else + sb.AppendLine($"{i}. {type.Name} -> Collected"); + } + } + + return sb.ToString(); + } +#endif + + } +} diff --git a/Runtime/Core/Framework/Subsystems/ServiceLocator.cs.meta b/Runtime/Core/Framework/Subsystems/ServiceLocator.cs.meta new file mode 100644 index 00000000..d11f4d4f --- /dev/null +++ b/Runtime/Core/Framework/Subsystems/ServiceLocator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c7f15b6d00f6b51469e7e8eb40786050 \ No newline at end of file diff --git a/Runtime/Core/ProjectSetting/ProjectSettingAsset.cs b/Runtime/Core/ProjectSetting/ProjectSettingAsset.cs index cea5c516..493c5cef 100644 --- a/Runtime/Core/ProjectSetting/ProjectSettingAsset.cs +++ b/Runtime/Core/ProjectSetting/ProjectSettingAsset.cs @@ -1,20 +1,14 @@ using System; +using System.Collections.Generic; using UnityEngine; namespace RealMethod { // Real Method Setting Storage - public class ProjectSettingAsset : ScriptableObject + public class ProjectSettingAsset : PrimitiveAsset { [Serializable] - public struct FolderAddress - { - public IdentityAsset Identity; - public string Path; - public string FolderName => System.IO.Path.GetFileName(Path); - } - [Serializable] - public enum IdentityAsset + public enum AssetFormat { Scene = 0, Script = 1, @@ -29,128 +23,160 @@ public enum IdentityAsset Audio = 10, Particle = 11, Animationclip = 12, - Miscellaneous = 13, - User = 14, - Resources = 15, - ThirdpartyPack = 16, - PCG = 17, - ScriptTemplate = 18, - PrefabTemplate = 19, - AnimatorParam, + Other = 13 + } + [Serializable] + public struct FolderAddress + { + public AssetFormat AssetType; + public string AssetPath; + public string FolderName => System.IO.Path.GetFileName(AssetPath); + public string GetFolderPath(ProjectSettingAsset settingAsset) + { + string RootPath = "Assets/" + Application.productName; + return $"{RootPath}/{AssetPath}"; + } + } + public static string Path = "Assets/Resources/RealMethod/RealMethodSetting.asset"; [Header("Initializer")] + [SerializeField, ReadOnly] + private string GameClass = string.Empty; // <-- this name must match + [SerializeField, ReadOnly] + private string GameBridge = string.Empty; // <-- this name must match [SerializeField] - private string GameClass = "RealMethod.DefultGame"; - [SerializeField] - private string GameService = "RealMethod.DefaultGameService"; - [SerializeField] - private GameConfig GameConfig; + private GameConfig GameConfig; // <-- this name must match [SerializeField] - private GameObject GamePrefab_1; + private GameObject GamePrefab_1; // <-- this name must match + +#if UNITY_EDITOR [SerializeField] - private GameObject GamePrefab_2; + private GameObject GamePrefab_2; // <-- this name must match +#endif + +#if UNITY_SERVER || UNITY_EDITOR [SerializeField] - private GameObject GamePrefab_3; + private GameObject GamePrefab_3; // <-- this name must match +#endif + +#if UNITY_EDITOR [Header("FolderStructure")] - public FolderAddress[] ProjectStructure = new FolderAddress[21] - { - new FolderAddress { Identity = 0, Path = "Assets/1_Scenes"}, - new FolderAddress { Identity = (IdentityAsset)1, Path = "Assets/2_Scripts" }, - new FolderAddress { Identity = (IdentityAsset)2, Path = "Assets/3_Prefabs"}, - new FolderAddress { Identity = (IdentityAsset)3, Path = "Assets/4_Data" }, - new FolderAddress { Identity = (IdentityAsset)4, Path = "Assets/5_Mesh"}, - new FolderAddress { Identity = (IdentityAsset)5, Path = "Assets/5_Sprite"}, - new FolderAddress { Identity = (IdentityAsset)6, Path = "Assets/7_Misc/Textures"}, - new FolderAddress { Identity = (IdentityAsset)7, Path = "Assets/7_Misc/Videos"}, - new FolderAddress { Identity = (IdentityAsset)8, Path = "Assets/7_Misc/Materials"}, - new FolderAddress { Identity = (IdentityAsset)9, Path = "Assets/6_Shader"}, - new FolderAddress { Identity = (IdentityAsset)10, Path = "Assets/8_Sound&Music"}, - new FolderAddress { Identity = (IdentityAsset)11, Path = "Assets/9_VFX"}, - new FolderAddress { Identity = (IdentityAsset)12, Path = "Assets/10_Animation"}, - new FolderAddress { Identity = (IdentityAsset)13, Path = "Assets/7_Misc"}, - new FolderAddress { Identity = (IdentityAsset)14, Path = "Assets/Developer"}, - new FolderAddress { Identity = (IdentityAsset)15, Path = "Assets/Resources"}, - new FolderAddress { Identity = (IdentityAsset)16, Path = "Assets/~Thirdparty"}, - new FolderAddress { Identity = (IdentityAsset)17, Path = "Assets/4_Data/PCG"}, - new FolderAddress { Identity = (IdentityAsset)18, Path = "Assets/7_Misc/Templates/Scripts"}, - new FolderAddress { Identity = (IdentityAsset)19, Path = "Assets/7_Misc/Templates/Prefabs"}, - new FolderAddress { Identity = (IdentityAsset)20, Path = "Assets/2_Scripts/_Game/Utility"} + [SerializeField, ReadOnly] + private FolderAddress[] folderStructure = new FolderAddress[14] + { + new FolderAddress { AssetType = 0, AssetPath = "1_Scenes"}, + new FolderAddress { AssetType = (AssetFormat)1, AssetPath = "2_Scripts" }, + new FolderAddress { AssetType = (AssetFormat)2, AssetPath = "3_Prefabs"}, + new FolderAddress { AssetType = (AssetFormat)3, AssetPath = "4_Data" }, + new FolderAddress { AssetType = (AssetFormat)4, AssetPath = "5_Mesh"}, + new FolderAddress { AssetType = (AssetFormat)5, AssetPath = "5_Sprite"}, + new FolderAddress { AssetType = (AssetFormat)6, AssetPath = "7_Misc/Textures"}, + new FolderAddress { AssetType = (AssetFormat)7, AssetPath = "7_Misc/Videos"}, + new FolderAddress { AssetType = (AssetFormat)8, AssetPath = "7_Misc/Materials"}, + new FolderAddress { AssetType = (AssetFormat)9, AssetPath = "6_Shader"}, + new FolderAddress { AssetType = (AssetFormat)10, AssetPath = "8_Sound&Music"}, + new FolderAddress { AssetType = (AssetFormat)11, AssetPath = "9_VFX"}, + new FolderAddress { AssetType = (AssetFormat)12, AssetPath = "10_Animation"}, + new FolderAddress { AssetType = (AssetFormat)13, AssetPath = "7_Misc"} }; + public IReadOnlyList FolderStructure => folderStructure; + [Header("GameStatus")] + [ReadOnly] + public List Status = new List(5) { "Default", "Menu", "Playing", "Pause", "GameOver" }; + [Header("CompileGuard")] + [SerializeField, ReadOnly] + private bool Compiling = true; // <-- this name must match + [SerializeField, ReadOnly] + private string[] Rules = null; // <-- this name must match +#endif + + // Unity Methods + protected virtual void OnEnable() + { + if (string.IsNullOrEmpty(GameClass)) + GameClass = typeof(DefultGame).AssemblyQualifiedName; + if (string.IsNullOrEmpty(GameBridge)) + GameBridge = typeof(DefaultGameBridge).AssemblyQualifiedName; + } + protected virtual void Reset() + { + if (string.IsNullOrEmpty(GameClass)) + GameClass = typeof(DefultGame).AssemblyQualifiedName; + if (string.IsNullOrEmpty(GameBridge)) + GameBridge = typeof(DefaultGameBridge).AssemblyQualifiedName; + } // Public Functions - public Type GetGameInstanceClass() + public Type GetGameType() { - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - var type = assembly.GetType(GameClass); - if (type != null) - return type; - } - return null; + return Type.GetType(GameClass); } - public void SetGameInstanceClass(Type type) + public Type GetBridgeType() { - // Store fully qualified name of the type - if (type != null) - { - GameClass = type.AssemblyQualifiedName; - } - else - { - Debug.LogError("Type is null. Cannot set GameInstanceClass."); - } - + return Type.GetType(GameBridge); } - public Type GetGameServiceClass() + public GameConfig GetGameConfigAsset() { - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - var type = assembly.GetType(GameService); - if (type != null) - return type; - } - return null; + return GameConfig; } - public void SetGameServiceClass(Type type) + public GameObject GetPrefab_1() { - // Store fully qualified name of the type - if (type != null) - { - GameService = type.AssemblyQualifiedName; - } - else - { - Debug.LogError("Type is null. Cannot set GameInstanceClass."); - } + return GamePrefab_1; + } +#if UNITY_EDITOR + protected sealed override void EnsureAssetPermission() + { } - public GameConfig GetGameConfig() + public static ProjectSettingAsset Load() { - return GameConfig; + return UnityEditor.AssetDatabase.LoadAssetAtPath(Path); } - public GameObject[] GetGamePrefabs() + public GameObject GetPrefab_2() { - return new GameObject[3] { - GamePrefab_1, - GamePrefab_2, - GamePrefab_3, - }; + return GamePrefab_2; } - public FolderAddress FindAddres(IdentityAsset identity) + public FolderAddress GetFolderAddressByType(AssetFormat identity) { - foreach (var PS in ProjectStructure) + foreach (var PS in folderStructure) { - if (PS.Identity == identity) + if (PS.AssetType == identity) { return PS; } } - return default(FolderAddress); + return default; + } + public string GetFolderPathByType(AssetFormat identity) + { + return GetFolderAddressByType(identity).GetFolderPath(this); + } + public FolderAddress GetFolderAddressByIndex(int index) => folderStructure[index]; + public void SetFolderAddressPath(int index, string value) => folderStructure[index].AssetPath = value; + public bool CanCompile() + { + return Compiling; + } + public Type[] GetCompileRules() + { + List result = new List(); + foreach (var item in Rules) + { + result.Add(Type.GetType(item)); + } + return result.ToArray(); } +#endif +#if UNITY_SERVER || UNITY_EDITOR + public GameObject GetPrefab_3() + { + return GamePrefab_3; + } +#endif } diff --git a/Runtime/Library/Extension/Animator.cs b/Runtime/Library/Extension/Animator.cs index 3b44b8c9..c06af738 100644 --- a/Runtime/Library/Extension/Animator.cs +++ b/Runtime/Library/Extension/Animator.cs @@ -4,19 +4,18 @@ namespace RealMethod { public static class Animator_Extension { - public static Coroutine PlayAndNotify(this Animator animator, string stateName, System.Action onFinished, int layer = 0) + public static Coroutine Play(this Animator animator, string stateName, System.Action onFinished, int layer = 0) { animator.Play(stateName, layer); // Start a coroutine to watch for finish var runner = animator.GetComponent(); if (runner == null) { - Debug.LogWarning("For Use PlayAndNotify you need to a MonoBehaviour for running Cortine for Finish Callback"); + Debug.LogWarning("For Use Play you need to a MonoBehaviour for running Cortine for Finish Callback"); return null; } - return runner.StartCoroutine(RM_Coroutine.WaitForState(animator, layer, stateName, onFinished)); + return runner.StartCoroutine(RM_Animation.WaitForState(animator, layer, stateName, onFinished)); } - /// /// Checks if the Animator is currently playing a specific state. /// @@ -25,7 +24,6 @@ public static bool IsPlaying(this Animator animator, string stateName, int layer var info = animator.GetCurrentAnimatorStateInfo(layer); return info.IsName(stateName) && info.normalizedTime < 1f; } - /// /// Checks if the Animator is in a specific state (finished or still playing). /// @@ -33,7 +31,6 @@ public static bool IsInState(this Animator animator, string stateName, int layer { return animator.GetCurrentAnimatorStateInfo(layer).IsName(stateName); } - /// /// Returns the normalized progress of the current animation state (0 → 1). /// @@ -41,7 +38,6 @@ public static float GetProgress(this Animator animator, int layer = 0) { return animator.GetCurrentAnimatorStateInfo(layer).normalizedTime; } - /// /// Safely sets a trigger (resets it first to avoid stuck transitions). /// @@ -50,7 +46,6 @@ public static void SetTriggerSafe(this Animator animator, string triggerName) animator.ResetTrigger(triggerName); animator.SetTrigger(triggerName); } - /// /// Immediately stops all animations and plays the given state. /// @@ -59,7 +54,6 @@ public static void ForcePlay(this Animator animator, string stateName, int layer animator.Play(stateName, layer, normalizedTime); animator.Update(0f); // force immediate update so the state is applied instantly } - /// /// Checks if the current state is about to end (useful for chaining combos). /// @@ -68,7 +62,6 @@ public static bool IsNearEnd(this Animator animator, float threshold = 0.9f, int var info = animator.GetCurrentAnimatorStateInfo(layer); return info.normalizedTime >= threshold && !info.loop; } - /// /// Crossfades safely only if the target state isn’t already playing. /// diff --git a/Runtime/Library/Extension/Array.cs b/Runtime/Library/Extension/Array.cs index 68a54240..d594a0ac 100644 --- a/Runtime/Library/Extension/Array.cs +++ b/Runtime/Library/Extension/Array.cs @@ -4,7 +4,6 @@ namespace RealMethod { public static class Array_Extension { - // Extention public static bool IsValidIndex(this Array array, int index) { return index >= 0 && index < array.Length; @@ -51,6 +50,24 @@ public static int Sum(this int[] array) } return sum; } + /// + /// Appends two arrays into a new combined array. + /// + /// The element type of the arrays. + /// The first array. + /// The second array. + /// A new array containing elements of both arrays. + public static T[] CombineWith(this T[] first, T[] second) + { + if (first == null) return second; + if (second == null) return first; + + T[] result = new T[first.Length + second.Length]; + Array.Copy(first, 0, result, 0, first.Length); + Array.Copy(second, 0, result, first.Length, second.Length); + + return result; + } } } \ No newline at end of file diff --git a/Runtime/Library/Extension/Component.cs b/Runtime/Library/Extension/Component.cs deleted file mode 100644 index b312c7bf..00000000 --- a/Runtime/Library/Extension/Component.cs +++ /dev/null @@ -1,16 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public static class Component_Extension - { - public static void SendSpawnEvent(this Component owner, Object spawner, SendMessageOptions option = SendMessageOptions.RequireReceiver) - { - owner.SendMessage("OnSpawn", spawner, option); - } - public static void SendDespawnEvent(this Component owner, Object despawner, SendMessageOptions option = SendMessageOptions.RequireReceiver) - { - owner.SendMessage("OnDespawn", despawner, option); - } - } -} \ No newline at end of file diff --git a/Runtime/Library/Extension/Component.cs.meta b/Runtime/Library/Extension/Component.cs.meta deleted file mode 100644 index a23013d0..00000000 --- a/Runtime/Library/Extension/Component.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 81728d66b32736d438d7ed5ae52dade5 \ No newline at end of file diff --git a/Runtime/Library/Extension/Dictionary.cs b/Runtime/Library/Extension/Dictionary.cs index 5114110d..e4fe1b41 100644 --- a/Runtime/Library/Extension/Dictionary.cs +++ b/Runtime/Library/Extension/Dictionary.cs @@ -42,7 +42,7 @@ public static T Wheel(this Dictionary DataBase) // Fallback (should rarely happen due to floating point errors) return DataBase.Keys.Last(); } - public static T Wheel(this SerializableDictionary DataBase) + public static T Wheel(this Map DataBase) { if (DataBase == null || DataBase.Count == 0) throw new System.ArgumentException("Database is null or empty"); diff --git a/Runtime/Library/Extension/GameObject.cs b/Runtime/Library/Extension/GameObject.cs index 7b5f9b6c..48ca5e9e 100644 --- a/Runtime/Library/Extension/GameObject.cs +++ b/Runtime/Library/Extension/GameObject.cs @@ -1,39 +1,150 @@ using UnityEngine; using System.Reflection; +#if UNITY_EDITOR +using UnityEditor; +#endif + namespace RealMethod { + /// + /// Extension methods for the GameObject class to add common functionalities. + /// public static class GameObject_Extension { - public static void SendSpawnEvent(this GameObject owner, Object spawner, SendMessageOptions option = SendMessageOptions.RequireReceiver) + public static void Death(this GameObject target) { - owner.SendMessage("OnSpawn", spawner, option); + IDamageable provider = target.GetComponent(); + if (provider != null) + { + provider.Die(); + } + else + { + target.SendMessage(MessageNames.Die, SendMessageOptions.RequireReceiver); + } } - public static void SendDespawnEvent(this GameObject owner, Object despawner, SendMessageOptions option = SendMessageOptions.RequireReceiver) + /// + /// pplies damage to the target GameObject. + /// + /// The GameObject that should receive damage. + /// ther GameObject how applyed damage + /// The damage payload containing specific value + public static void ApplyDamage(this GameObject target, GameObject attacker, float damage) { - owner.SendMessage("OnDespawn", despawner, option); + target.ApplyDamage(new HitData(new RaycastHit(), attacker, damage)); + } + /// + /// Applies damage to the target GameObject using two fallback methods: + /// 1) If the object implements , damage is applied directly through TakeDamage. + /// 2) Otherwise, a Unity SendMessage call is made using GameMessages.ApplyDamage. + /// + /// This allows all GameObjects to receive damage regardless of whether they use the interface + /// or the older SendMessage-based system. + /// + /// The GameObject that should receive damage. + /// The damage payload containing values such as damage amount and hit details. + public static void ApplyDamage(this GameObject target, HitData hitdata) + { + IDamageable provider = target.GetComponent(); + if (provider != null) + { + provider.TakeDamage(hitdata); + } + else + { + target.SendMessage(MessageNames.ApplyDamage, hitdata, SendMessageOptions.RequireReceiver); + } } - public static TComponent AddComponent(this GameObject gameObject) - where TComponent : MonoBehaviour, IInitializable + /// + /// Attaches this GameObject to a specified Socket transform, optionally preserving world position. + /// Also sends an "OnAttach" message to the owner GameObject. + /// + /// The GameObject to attach. + /// The Transform to get Socket from that. + /// The Socket name to attach to + /// If true, the parent-relative position, rotation, and scale are modified so that the last local transformation is equal to the world transformation. + public static void Attach(this GameObject target, Transform parent, Name16 socketname, bool worldPositionStays = true) { - var component = gameObject.AddComponent(); - component.Initialize(); + Transform MySocket = parent.GetSocket(socketname); + MySocket.SetParent(parent.transform, worldPositionStays); + target.SendMessage(MessageNames.Attach, parent, SendMessageOptions.DontRequireReceiver); + } + /// + /// Attaches this GameObject to a specified parent GameObject, optionally preserving world position. + /// Also sends an "OnAttach" message to the owner GameObject. + /// + /// The GameObject to attach. + /// The GameObject to attach to. + /// If true, the parent-relative position, rotation, and scale are modified so that the last local transformation is equal to the world transformation. + public static void Attach(this GameObject target, GameObject parent, bool worldPositionStays = true) + { + target.transform.SetParent(parent.transform, worldPositionStays); + target.SendMessage(MessageNames.Attach, parent, SendMessageOptions.DontRequireReceiver); + } + /// + /// Detaches this GameObject from its current parent and sends an "OnDetach" message. + /// + /// The GameObject to detach. + /// The parent GameObject it was attached to (primarily for context, not used in the current implementation). + public static void Detach(this GameObject target, GameObject parent) + { + target.transform.SetParent(null); + target.SendMessage(MessageNames.Detach, SendMessageOptions.DontRequireReceiver); + } + /// + /// Adds a new component of type TComponent to the GameObject and initializes it without arguments. + /// + /// The type of the component to add, must inherit from MonoBehaviour and IInitializable. + /// This type parameter is unused in this overload. + /// The GameObject to add the component to. + /// The newly added and initialized component. + public static TComponent AddComponent(this GameObject target) + where TComponent : MonoBehaviour, ISpawn + { + var component = target.AddComponent(); + component.OnSpawn(); return component; } - public static TComponent AddComponent(this GameObject gameObject, TArgument argument) - where TComponent : MonoBehaviour, IInitializableWithArgument + /// + /// Adds a new component of type TComponent to the GameObject and initializes it with a single argument. + /// + /// The type of the component to add, must inherit from MonoBehaviour and IInitializableWithArgument. + /// The type of the argument used for initialization. + /// The GameObject to add the component to. + /// The argument to pass to the component's Initialize method. + /// The newly added and initialized component. + public static TComponent AddComponent(this GameObject target, TArgument argument) + where TComponent : MonoBehaviour, ISpawnWithArgument { - var component = gameObject.AddComponent(); - component.Initialize(argument); + var component = target.AddComponent(); + component.OnSpawn(argument); return component; } - public static TComponent AddComponent(this GameObject gameObject, TArgumentA argumentA, TArgumentB argumentB) - where TComponent : MonoBehaviour, IInitializableWithTwoArgument + /// + /// Adds a new component of type TComponent to the GameObject and initializes it with two arguments. + /// + /// The type of the component to add, must inherit from MonoBehaviour and IInitializableWithTwoArgument. + /// The type of the first argument used for initialization. + /// The type of the second argument used for initialization. + /// The GameObject to add the component to. + /// The first argument to pass to the component's Initialize method. + /// The second argument to pass to the component's Initialize method. + /// The newly added and initialized component. + public static TComponent AddComponent(this GameObject target, TArgumentA argumentA, TArgumentB argumentB) + where TComponent : MonoBehaviour, ISpawnWithTwoArgument { - var component = gameObject.AddComponent(); - component.Initialize(argumentA, argumentB); + var component = target.AddComponent(); + component.OnSpawn(argumentA, argumentB); return component; } + /// + /// Copies all public fields from an original component to a new component of the same type on a destination GameObject. + /// + /// The type of the component to copy. Must inherit from Component. + /// The GameObject to add the copied component to. + /// The component to copy from. + /// The newly created and populated component on the destination GameObject. public static TComponent CopyComponent(this GameObject desitation, TComponent originalComponent) where TComponent : Component { System.Type componentType = originalComponent.GetType(); @@ -45,5 +156,107 @@ public static TComponent CopyComponent(this GameObject desitation, T } return copy as TComponent; } + /// + /// Checks if a GameObject is a valid scene object (not a prefab asset, and belongs to a scene). + /// This method's behavior differs slightly between Editor and runtime. + /// + /// The GameObject to check. + /// True if the GameObject is in a scene, false otherwise. + public static bool IsInScene(this GameObject obj) + { +#if UNITY_EDITOR + return PrefabUtility.GetPrefabAssetType(obj) == PrefabAssetType.NotAPrefab + && obj.scene.IsValid(); +#else + return obj.scene.IsValid() && obj.scene.name != null; +#endif + } + /// + /// Check if GameObject was lives in DontDestroyOnload scene + /// + /// The GameObject to check. + /// True if the GameObject is in DontDestroyOnload scene, false otherwise. + public static bool IsDontDestroyOnLoad(this GameObject obj) + { + return obj.scene.name == "DontDestroyOnLoad"; + } + /// + /// Set layer on object and children + /// + /// GameObject Target + /// the layer you want to set that + public static void SetLayerRecursively(this GameObject target, int layer) + { + foreach (Transform t in target.GetComponentsInChildren(true)) + { + t.gameObject.layer = layer; + } + } + /// + /// Checks whether the GameObject contains a component that implements or matches type T. + /// + /// The interface or component type to search for. + /// The GameObject to check. + /// True if a component of type T exists on the GameObject; otherwise false. + public static bool HasImplementInterface(this GameObject target) + { + if (target != null) + { + T provider = target.GetComponent(); + if (provider != null) + { + return true; + } + } + return false; + } + /// + /// Checks whether the GameObject contains a component that implements or matches type T + /// and returns the found component. + /// + /// The interface or component type to search for. + /// The GameObject to check. + /// Outputs the found component if one exists. + /// True if a component of type T exists on the GameObject; otherwise false. + public static bool HasImplementInterface(this GameObject target, out T Result) + { + if (target != null) + { + T provider = target.GetComponent(); + if (provider != null) + { + Result = provider; + return true; + } + } + + Result = default; + return false; + + } + + +#if UNITY_EDITOR + /// + /// Checks if the GameObject is a prefab asset itself (not an instance of a prefab). + /// + /// The GameObject to check. + /// True if it's a prefab asset, false otherwise. + public static bool IsPrefabAsset(this GameObject obj) + { + return PrefabUtility.GetPrefabAssetType(obj) != PrefabAssetType.NotAPrefab + && PrefabUtility.GetPrefabInstanceStatus(obj) == PrefabInstanceStatus.NotAPrefab; + } + /// + /// Checks if the GameObject is an instance of a connected prefab. + /// + /// The GameObject to check. + /// True if it's a connected prefab instance, false otherwise. + public static bool IsPrefabInstance(this GameObject obj) + { + return PrefabUtility.GetPrefabInstanceStatus(obj) == PrefabInstanceStatus.Connected; + } +#endif + } } \ No newline at end of file diff --git a/Runtime/Library/Extension/Interface.cs b/Runtime/Library/Extension/Interface.cs new file mode 100644 index 00000000..e8c4bbe7 --- /dev/null +++ b/Runtime/Library/Extension/Interface.cs @@ -0,0 +1,37 @@ +using UnityEngine; + +namespace RealMethod +{ + /// + /// Extension methods for the Interface to add common functionalities. + /// + public static class Interface_Extension + { + public static bool IsSame(this IIdentifier a, IIdentifier b) + { + // 1. Exactly same reference + if (ReferenceEquals(a, b)) + return true; + + // 2. If one is null + if (a is null || b is null) + return false; + + return Equals(a.Self, b.Self); + } + public static bool HasNameID(this INameIdentifier target, string Name) + { + if (Name == string.Empty) + { + Debug.LogWarning("HasNameID is false [Name is empty]"); + return false; + } + if (target.SelfName == string.Empty) + { + Debug.LogWarning("HasNameID is false [NameID is empty]"); + return false; + } + return target.SelfName == Name; + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Extension/Interface.cs.meta b/Runtime/Library/Extension/Interface.cs.meta new file mode 100644 index 00000000..74ff06b1 --- /dev/null +++ b/Runtime/Library/Extension/Interface.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3ea7987ff424800478430001ef0e023e \ No newline at end of file diff --git a/Runtime/Library/Extension/Object.cs b/Runtime/Library/Extension/Object.cs index db3ad9bc..7291d90e 100644 --- a/Runtime/Library/Extension/Object.cs +++ b/Runtime/Library/Extension/Object.cs @@ -1,12 +1,13 @@ +using System.Reflection; using UnityEngine; namespace RealMethod { public static class Object_Extension { - public static bool NullChecker(this Object Obj, string Name) + public static bool NullChecker(this object Obj, string Name) { - if (Obj) + if (Obj != null) { return true; } @@ -16,5 +17,411 @@ public static bool NullChecker(this Object Obj, string Name) return false; } } + /// + /// Sends an "OnSpawn" message to the owner object. + /// Auto detect type for MonoBehaviour,GameObject,PrimitiveAsset and object + /// + /// The GameObject to send the message to. + /// The object that triggered the spawn event (passed as parameter to the message). + /// Specifies whether the message must be received, or if it is optional. + public static void InvokeSpawnEvent(this object owner, Object spawner = null, SendMessageOptions option = SendMessageOptions.DontRequireReceiver) + { + if (owner is MonoBehaviour mono) + { + if (spawner != null) + { + if (mono is ISpawnWithAuthor provider) + { + provider.OnSpawn(spawner); + } + else + { + mono.SendMessage(MessageNames.Spawn, spawner, option); + } + } + else + { + if (mono is ISpawn provider) + { + provider.OnSpawn(); + } + else + { + mono.SendMessage(MessageNames.Spawn, option); + } + } + } + else if (owner is GameObject gameobject) + { + if (spawner != null) + { + ISpawnWithAuthor provider = gameobject.GetComponent(); + if (provider != null) + { + provider.OnSpawn(spawner); + } + else + { + gameobject.SendMessage(MessageNames.Spawn, spawner, option); + } + } + else + { + ISpawn provider = gameobject.GetComponent(); + if (provider != null) + { + provider.OnSpawn(); + } + else + { + gameobject.SendMessage(MessageNames.Spawn, option); + } + } + } + else + { + if (spawner != null) + { + if (owner is ISpawnWithAuthor provider) + { + provider.OnSpawn(spawner); + } + else + { + owner.SendMessage(MessageNames.Spawn, spawner, option); + } + } + else + { + if (owner is ISpawn provider) + { + provider.OnSpawn(); + } + else + { + owner.SendMessage(MessageNames.Spawn, option); + } + } + } + } + /// + /// Sends an "OnDespawn" message to the owner object. + /// Auto detect type for MonoBehaviour,GameObject,PrimitiveAsset and object + /// + /// The GameObject to send the message to. + /// The object that triggered the despawn event (passed as parameter to the message). + /// Specifies whether the message must be received, or if it is optional. + public static void InvokeDespawnEvent(this object owner, Object despawner = null, SendMessageOptions option = SendMessageOptions.DontRequireReceiver) + { + if (owner is MonoBehaviour mono) + { + if (despawner != null) + { + if (mono is IDespawnWithAuthor provider) + { + provider.OnDespawn(despawner); + } + else + { + mono.SendMessage(MessageNames.Despawn, despawner, option); + } + } + else + { + if (mono is IDespawn provider) + { + provider.OnDespawn(); + } + else + { + mono.SendMessage(MessageNames.Despawn, option); + } + } + } + else if (owner is GameObject gameobject) + { + if (despawner != null) + { + IDespawnWithAuthor provider = gameobject.GetComponent(); + if (provider != null) + { + provider.OnDespawn(despawner); + } + else + { + gameobject.SendMessage(MessageNames.Despawn, despawner, option); + } + } + else + { + IDespawn provider = gameobject.GetComponent(); + if (provider != null) + { + provider.OnDespawn(); + } + else + { + gameobject.SendMessage(MessageNames.Despawn, option); + } + } + } + else + { + if (despawner != null) + { + if (owner is IDespawnWithAuthor provider) + { + provider.OnDespawn(despawner); + } + else + { + owner.SendMessage(MessageNames.Despawn, despawner, option); + } + } + else + { + if (owner is IDespawn provider) + { + provider.OnDespawn(); + } + else + { + owner.SendMessage(MessageNames.Despawn, option); + } + } + } + } + public static void InvokeSaveEvent(this object obj, SendMessageOptions option = SendMessageOptions.RequireReceiver) + { + if (obj is ISaveable provider) + { + provider.OnSaved(); + } + else + { + obj.SendMessage(MessageNames.Save, option); + } + } + public static void InvokeLoadEvent(this object obj, SendMessageOptions option = SendMessageOptions.RequireReceiver) + { + if (obj is ISaveable provider) + { + provider.OnLoaded(); + } + else + { + obj.SendMessage(MessageNames.Load, option); + } + } + public static void InvokeReqisterEvent(this object obj, SendMessageOptions option = SendMessageOptions.DontRequireReceiver) + { + if (obj is IRegistrable provider) + { + provider.OnRegister(); + } + else + { + obj.SendMessage(MessageNames.Register, option); + } + } + public static void InvokeUnreqisterEvent(this object obj, SendMessageOptions option = SendMessageOptions.DontRequireReceiver) + { + if (obj is IRegistrable provider) + { + provider.OnUnregister(); + } + else + { + obj.SendMessage(MessageNames.Unregister, option); + } + } + public static void InvokeNotify(this object obj, string tag, SendMessageOptions option = SendMessageOptions.RequireReceiver) + { + if (obj is INotifiable provider) + { + provider.OnNotify(tag); + } + else + { + obj.SendMessage(MessageNames.Notify, tag, option); + } + } + public static void SendMessage(this object obj, string methodName, SendMessageOptions option) + { + obj.SendMessage(methodName, null, option); + } + public static void SendMessage(this object obj, string methodName, object parameter, SendMessageOptions options) + { + if (obj is Component comp) + { + comp.SendMessage(methodName, parameter, options); + return; + } + + var method = obj.GetType().GetMethodInHierarchy(methodName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + + if (method != null) + { + if (parameter == null) + { + method.Invoke(obj, null); + } + else + { + method.Invoke(obj, new object[1] { parameter }); + } + } + else + { + if (options == SendMessageOptions.RequireReceiver) + Debug.LogError($"[SendMessageError] Method '{methodName}' was not found on '{obj}'."); + } + } + /// + /// Attempts to cast the given to the specified at runtime. + /// + /// The source object to be cast. + /// The target type to cast to. + /// + /// Return true is cansting correct + /// + public static bool IsChild(this object obj, System.Type type) + { + if (obj == null) + throw new System.ArgumentNullException(nameof(obj)); + if (type == null) + throw new System.ArgumentNullException(nameof(type)); + + return type.IsInstanceOfType(obj); + } + public static T Cast(this object obj) where T : class + { + return (T)obj; + } + public static bool TryCast(this object obj, out T result) where T : class + { + if (obj is T refrence) + { + result = refrence; + return true; + } + else + { + result = null; + return false; + } + } + public static SoftType GetSoftType(this object obj) where T : System.Type + { + return obj.GetType(); + } + public static bool TryGetType(this object obj, out SoftType result) where T : System.Type + { + System.Type targetType = obj.GetType(); + if (targetType.IsAssignableFrom(typeof(T))) + { + result = obj.GetType(); + return true; + } + else + { + result = null; + return false; + } + } + /// + /// Checks whether the object contains a component that implements or matches type T. + /// + /// The interface or component type to search for. + /// The object to check. + /// True if a component of type T exists on the object; otherwise false. + public static bool HasImplementInterface(this object target) + { + if (target != null) + { + if (target is T provider) + { + return true; + } + } + return false; + } + /// + /// Checks whether the object contains a component that implements or matches type T + /// and returns the found component. + /// + /// The interface or component type to search for. + /// The object to check. + /// Outputs the found component if one exists. + /// True if a component of type T exists on the object; otherwise false. + public static bool HasImplementInterface(this object target, out T Result) + { + if (target != null) + { + if (target is T provider) + { + Result = provider; + return true; + } + } + + Result = default; + return false; + + } + /// + /// Get all fields from object by filtering bindingflags + /// + /// the object refrence + /// make filtering witch type of field + /// Array of Fieldinfo + public static FieldInfo[] GetFields(this object target, BindingFlags flags) + { + System.Type type = target.GetType(); + return type.GetFields(flags); + } + /// + /// Get all Property from object by filtering bindingflags + /// + /// the object refrence + /// make filtering witch type of Property + /// Array of PropertyInfo + public static PropertyInfo[] GetProperties(this object target, BindingFlags flags) + { + System.Type type = target.GetType(); + return type.GetProperties(flags); + } + public static IIdentifier GetID(this object obj) + { + return GetID(obj); + } + public static T GetID(this object obj) where T : IIdentifier + { + if (obj is T Provider) + { + return Provider; + } + else + { + return default; + } + } + public static bool HasNameID(this object obj, string NameID) + { + if (obj is INameIdentifier Provider) + { + return Provider.HasNameID(NameID); + } + else + { + Debug.LogError($"Target Object({obj}) should implement {typeof(INameIdentifier)} interface."); + return false; + } + } + public static void Destroy(this System.IDisposable provider) + { + + } } } \ No newline at end of file diff --git a/Runtime/Library/Extension/ScriptableObject.cs b/Runtime/Library/Extension/ScriptableObject.cs new file mode 100644 index 00000000..f6b3ebd7 --- /dev/null +++ b/Runtime/Library/Extension/ScriptableObject.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace RealMethod +{ + public static class ScriptableObject_Extension + { + public static ScriptableObject Clone(this ScriptableObject so) + { + return ScriptableObject.Instantiate(so); + } + + } +} \ No newline at end of file diff --git a/Runtime/Library/Extension/ScriptableObject.cs.meta b/Runtime/Library/Extension/ScriptableObject.cs.meta new file mode 100644 index 00000000..073a688c --- /dev/null +++ b/Runtime/Library/Extension/ScriptableObject.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f1e3fbce41e63464e99c5d3a91da779c \ No newline at end of file diff --git a/Runtime/Library/Extension/Transform.cs b/Runtime/Library/Extension/Transform.cs index d4c4f7af..eb475360 100644 --- a/Runtime/Library/Extension/Transform.cs +++ b/Runtime/Library/Extension/Transform.cs @@ -10,7 +10,7 @@ public static void SetTransform(this Transform trans, Transform newtransform) trans.rotation = newtransform.rotation; trans.localScale = newtransform.localScale; } - public static Transform FindSocket(this Transform trans, string socketname) + public static Transform GetSocket(this Transform trans, Name16 socketname) { foreach (var item in trans.GetComponentsInChildren()) { @@ -22,5 +22,19 @@ public static Transform FindSocket(this Transform trans, string socketname) Debug.LogError($"Not find any socket with {socketname} name"); return trans; } + /// + /// Reset transform quickly + /// + /// Target terasform + public static void Reset(this Transform t) + { + t.localPosition = Vector3.zero; + t.localRotation = Quaternion.identity; + t.localScale = Vector3.one; + } + public static TransformData ConvertToData(this Transform trans) + { + return new TransformData(trans); + } } } \ No newline at end of file diff --git a/Runtime/Library/Extension/Type.cs b/Runtime/Library/Extension/Type.cs new file mode 100644 index 00000000..b9bf5ad3 --- /dev/null +++ b/Runtime/Library/Extension/Type.cs @@ -0,0 +1,54 @@ +using System; +using System.Reflection; +using UnityEngine; + +namespace RealMethod +{ + public static class Type_Extension + { + public static bool IsChild(this Type type) + { + return typeof(T).IsAssignableFrom(type); + } + public static bool IsChild(this Type type, Type target) + { + return target.IsAssignableFrom(type); + } + public static object CreateInstance(this Type type) + { + if (type.IsChild(typeof(ScriptableObject))) + { + return ScriptableObject.CreateInstance(type); + } + else + { + return Activator.CreateInstance(type); + } + } + public static MethodInfo GetMethodInHierarchy(this Type type, string methodName, BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly) + { + while (type != null) + { + var method = type.GetMethod(methodName, flags); + if (method != null) + return method; + + type = type.BaseType; + } + + return null; + } + public static bool HasImplementInterface(this Type type) + { + var interfaces = type.GetInterfaces(); + foreach (var i in interfaces) + { + // Only interfaces derived from Interface + if (typeof(T).IsAssignableFrom(i)) + return true; + } + return false; + } + + } +} \ No newline at end of file diff --git a/Runtime/Library/Extension/Type.cs.meta b/Runtime/Library/Extension/Type.cs.meta new file mode 100644 index 00000000..7650dc4a --- /dev/null +++ b/Runtime/Library/Extension/Type.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5db382bc1559fc345abb66c2256eb1b8 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Behaviour.cs.meta b/Runtime/Library/Interfaces/Behaviour.cs.meta deleted file mode 100644 index 3f234629..00000000 --- a/Runtime/Library/Interfaces/Behaviour.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 8f64c6d8086f93f498d15565af34d021 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Blackboard.cs b/Runtime/Library/Interfaces/Blackboard.cs new file mode 100644 index 00000000..eb36f566 --- /dev/null +++ b/Runtime/Library/Interfaces/Blackboard.cs @@ -0,0 +1,37 @@ +using UnityEngine; + +namespace RealMethod +{ + public interface IBlackboard + { + bool HasBool(Name16 name); + void SetBool(Name16 name, bool target); + bool GetBool(Name16 name); + bool HasInt(Name16 name); + void SetInt(Name16 name, int target); + int GetInt(Name16 name); + bool HasFloat(Name16 name); + void SetFloat(Name16 name, float target); + float GetFloat(Name16 name); + bool HasString(Name16 name); + void SetString(Name16 name, string target); + string GetString(Name16 name); + bool HasVector2(Name16 name); + void SetVector2(Name16 name, Vector2 target); + Vector2 GetVector2(Name16 name); + bool HasVector3(Name16 name); + void SetVector3(Name16 name, Vector3 target); + Vector3 GetVector3(Name16 name); + bool HasPefab(Name16 name); + void SetPrefab(Name16 name, Prefab target); + Prefab GetPrefab(Name16 name); + bool HasAsset(Name16 name); + void SetAsset(Name16 name, PrimitiveAsset target); + PrimitiveAsset GetAsset(Name16 name); + bool HasComponent(Name16 name); + void SetComponent(Name16 name, Component target); + Component GetComponent(Name16 name); + } + + +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Blackboard.cs.meta b/Runtime/Library/Interfaces/Blackboard.cs.meta new file mode 100644 index 00000000..53e109b8 --- /dev/null +++ b/Runtime/Library/Interfaces/Blackboard.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 937a63b2d30994f4abca77c0ef7a2a52 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Command.cs b/Runtime/Library/Interfaces/Command.cs new file mode 100644 index 00000000..80a7a6df --- /dev/null +++ b/Runtime/Library/Interfaces/Command.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +namespace RealMethod +{ + // A base command you can execute immediately. + public interface ICommand + { + bool Initiate(Object owner); + void ExecuteCommand(object Executer); + } + +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Command.cs.meta b/Runtime/Library/Interfaces/Command.cs.meta new file mode 100644 index 00000000..596df096 --- /dev/null +++ b/Runtime/Library/Interfaces/Command.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3b1af94cc4165924f91dd898a4b30ee0 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Damage.cs b/Runtime/Library/Interfaces/Damage.cs deleted file mode 100644 index edb07344..00000000 --- a/Runtime/Library/Interfaces/Damage.cs +++ /dev/null @@ -1,40 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public interface IDamage - { - /// - /// Returns true if the object is already dead. - /// - bool IsDead { get; } - /// - /// Called when the object dies or is destroyed due to damage. - /// - void Die(); - } - public interface IDamageable : IDamage - { - float MaxHealth { get; } - float CurrentHealth { get; } - /// - /// Simple damage (only amount + optional source) - /// - void TakeDamage(float amount, GameObject source = null); - void Restore(float amount); - } - /// - /// Interface for objects that can take and restore damage. - /// - /// The type representing TakeDamage data (e.g., int, float, struct). - public interface IDamageable : IDamageable where T : struct where R : struct - { - /// - /// Applies damage to the object. - /// - /// The raw data of damage. - /// The GameObject or system causing the damage. - void TakeDamage(T data); - void Restore(R amount); - } -} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Damageable.cs b/Runtime/Library/Interfaces/Damageable.cs new file mode 100644 index 00000000..c4e622b9 --- /dev/null +++ b/Runtime/Library/Interfaces/Damageable.cs @@ -0,0 +1,16 @@ +namespace RealMethod +{ + public interface IDamageable + { + /// + /// Simple damage (only amount + optional source) + /// + /// Incloude all data that need for reperesent damage + void TakeDamage(HitData HitInfo); + /// + /// Called when the object dies or is destroyed due to damage. + /// + void Die(); + } + +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Damage.cs.meta b/Runtime/Library/Interfaces/Damageable.cs.meta similarity index 100% rename from Runtime/Library/Interfaces/Damage.cs.meta rename to Runtime/Library/Interfaces/Damageable.cs.meta diff --git a/Runtime/Library/Interfaces/Data.cs b/Runtime/Library/Interfaces/Data.cs deleted file mode 100644 index 26eeaa9e..00000000 --- a/Runtime/Library/Interfaces/Data.cs +++ /dev/null @@ -1,32 +0,0 @@ - -namespace RealMethod -{ - public interface IBlackboardPure - { - void SetBool(string name, bool target); - bool GetBool(string name); - void SetByte(string name, byte target); - byte GetByte(string name); - void SetInt(string name, int target); - int GetInt(string name); - void SetFloat(string name, float target); - float GetFloat(string name); - } - public interface IBlackboardUnity : IBlackboardPure - { - void SetVector2(string name, UnityEngine.Vector2 target); - UnityEngine.Vector2 GetVector2(string name); - void SetVector3(string name, UnityEngine.Vector3 target); - UnityEngine.Vector3 GetVector3(string name); - void SetObject(string name, UnityEngine.Object target); - UnityEngine.Object GetObject(string name); - } - public interface IBlackboard : IBlackboardUnity - { - void SetIdentity(string name, IIdentifier target); - IIdentifier GetIdentity(string name); - void SetAsset(string name, PrimitiveAsset target); - PrimitiveAsset GetAsset(string name); - - } -} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Data.cs.meta b/Runtime/Library/Interfaces/Data.cs.meta deleted file mode 100644 index cf06feaf..00000000 --- a/Runtime/Library/Interfaces/Data.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 011d67550e3bcf84997ecc1ad3c34e57 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Factory.cs b/Runtime/Library/Interfaces/Factory.cs new file mode 100644 index 00000000..fa97c285 --- /dev/null +++ b/Runtime/Library/Interfaces/Factory.cs @@ -0,0 +1,13 @@ +namespace RealMethod +{ + public interface IFactoryEditorAccess + { + + } + public interface IFactoryAction : ICommand + { + //void Initiate(); + //void Execute(); + } + +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Factory.cs.meta b/Runtime/Library/Interfaces/Factory.cs.meta new file mode 100644 index 00000000..eca59529 --- /dev/null +++ b/Runtime/Library/Interfaces/Factory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f34a9b4304409044088b9fc1e89ecf18 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Behaviour.cs b/Runtime/Library/Interfaces/Handle.cs similarity index 60% rename from Runtime/Library/Interfaces/Behaviour.cs rename to Runtime/Library/Interfaces/Handle.cs index e57c0aad..f381c398 100644 --- a/Runtime/Library/Interfaces/Behaviour.cs +++ b/Runtime/Library/Interfaces/Handle.cs @@ -1,6 +1,28 @@ namespace RealMethod { - public interface IBehaviour + /// + /// Represents the root interface for any system that exposes + /// an external control handle. + /// + /// This interface itself defines no functionality; instead, it acts + /// as a conceptual marker for objects whose execution, lifecycle, + /// or behavior can be controlled through derived interfaces such as + /// IHandleTrigger, IHandleLifecycle, IHandleTimed, or IHandleAction. + /// + /// In other words, IHandle identifies a controllable unit that + /// provides a unified access point for interacting with the + /// underlying process, behavior, or action. + /// + public interface IHandle : IIdentifier + { + } + + public interface IHandleTrigger : IHandle + { + void Trigger(); + void Cancel(); + } + public interface IHandleBehaviour : IHandle { /// Called when the Behaviour starts. void Start(); @@ -11,10 +33,10 @@ public interface IBehaviour /// Whether the Behaviour is currently started. bool IsStarted { get; } } - public interface IBehaviourCycle : IBehaviour + public interface IHandleBehaviourCycle : IHandleBehaviour { /// Called when the Behaviour starts with override Time. - void Start(float overrideTime); + void Start(float Duration); // Whether the Behaviour has finished execution. bool IsFinished { get; } /// Has Behaviour infinit lifetime. @@ -26,7 +48,7 @@ public interface IBehaviourCycle : IBehaviour /// Normalized time since Behaviour Live. float NormalizedTime { get; } } - public interface IBehaviourAction : IBehaviourCycle + public interface IHandleBehaviourAction : IHandleBehaviourCycle { /// Called to pause the Behaviour temporarily. void Pause(); @@ -40,4 +62,5 @@ public interface IBehaviourAction : IBehaviourCycle bool IsPaused { get; } } + } \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Handle.cs.meta b/Runtime/Library/Interfaces/Handle.cs.meta new file mode 100644 index 00000000..dc5a0ed4 --- /dev/null +++ b/Runtime/Library/Interfaces/Handle.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ca758207c40f53048bdc05d13910b196 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Initializable.cs b/Runtime/Library/Interfaces/Initializable.cs deleted file mode 100644 index abd8185f..00000000 --- a/Runtime/Library/Interfaces/Initializable.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace RealMethod -{ - public interface IInitializable - { - void Initialize(); - } - public interface IInitializableWithArgument - { - void Initialize(TArgument argument); - } - public interface IInitializableWithTwoArgument - { - void Initialize(TArgumentA argumentA, TArgumentB argumentB); - } - -} - - diff --git a/Runtime/Library/Interfaces/Item.cs b/Runtime/Library/Interfaces/Item.cs index 621bc4c0..0c89b6b9 100644 --- a/Runtime/Library/Interfaces/Item.cs +++ b/Runtime/Library/Interfaces/Item.cs @@ -8,7 +8,7 @@ public interface IItem : IIdentifier Sprite GetSpriteIcon(); Sprite GetSpriteIcon(Rect rect, Vector2 pivot); #if UNITY_EDITOR - void ChangeItemName(string NewName); + void SetItemName(string NewName); #endif } diff --git a/Runtime/Library/Interfaces/Label.cs b/Runtime/Library/Interfaces/Label.cs new file mode 100644 index 00000000..aa7d5b2a --- /dev/null +++ b/Runtime/Library/Interfaces/Label.cs @@ -0,0 +1,32 @@ +namespace RealMethod +{ + public interface ILabel + { + + } + + + // public interface IDamage + // { + // /// + // /// Returns true if the object is already dead. + // /// + // bool IsDead { get; } + + // } + + /// + /// Interface for objects that can take and restore damage. + /// + /// The type representing TakeDamage data (e.g., int, float, struct). + // public interface IDamageable : IDamageable where T : struct where R : struct + // { + // /// + // /// Applies damage to the object. + // /// + // /// The raw data of damage. + // /// The GameObject or system causing the damage. + // void TakeDamage(T data); + // void Restore(R amount); + // } +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Label.cs.meta b/Runtime/Library/Interfaces/Label.cs.meta new file mode 100644 index 00000000..a56f9ccb --- /dev/null +++ b/Runtime/Library/Interfaces/Label.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5afe719b2c95deb4fb7bf11e45120c68 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Notifiable.cs b/Runtime/Library/Interfaces/Notifiable.cs new file mode 100644 index 00000000..ee11ca6e --- /dev/null +++ b/Runtime/Library/Interfaces/Notifiable.cs @@ -0,0 +1,7 @@ +namespace RealMethod +{ + public interface INotifiable + { + void OnNotify(string tag); + } +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Notifiable.cs.meta b/Runtime/Library/Interfaces/Notifiable.cs.meta new file mode 100644 index 00000000..ad691b8e --- /dev/null +++ b/Runtime/Library/Interfaces/Notifiable.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9c6e6c363a0724d44ae42c5137136c6a \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Pool.cs b/Runtime/Library/Interfaces/Pool.cs new file mode 100644 index 00000000..a55a9ad1 --- /dev/null +++ b/Runtime/Library/Interfaces/Pool.cs @@ -0,0 +1,34 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + + +namespace RealMethod +{ + public interface IPool + { + void Prewarm(int amount = 1); + IEnumerator PrewarmEachFrame(int amount = 1); + void Request(); + void Return(int amount = 1); + void Remove(int amount = 1, bool Force = false); + void Clean(); + } + public interface IPool : IPool + { + IEnumerable Request(int amount = 1); + } + public interface IPoolSpawner where J : Component + { + J Spawn(Vector3 location, Quaternion rotation, Vector3 scale); + J Spawn(Vector3 location, Quaternion rotation); + J Spawn(Vector3 location); + J Spawn(); + } + public interface IPoolDespawner where J : Component + { + void Despawn(); + void Despawn(J target); + } + +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Pool.cs.meta b/Runtime/Library/Interfaces/Pool.cs.meta new file mode 100644 index 00000000..f07675e8 --- /dev/null +++ b/Runtime/Library/Interfaces/Pool.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: abf6234193204404496125105048b8a7 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Registrable.cs b/Runtime/Library/Interfaces/Registrable.cs new file mode 100644 index 00000000..35530814 --- /dev/null +++ b/Runtime/Library/Interfaces/Registrable.cs @@ -0,0 +1,17 @@ +namespace RealMethod +{ + /// + /// Defines the contract for a object that can respond to lifecycle events. + /// + public interface IRegistrable + { + /// + /// Called when the object registerd by servicelocator. + /// + void OnRegister(); + /// + /// Called when unregisterd the object is deleted or destroyed from servicelocator. + /// + void OnUnregister(); + } +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Registrable.cs.meta b/Runtime/Library/Interfaces/Registrable.cs.meta new file mode 100644 index 00000000..2ad03209 --- /dev/null +++ b/Runtime/Library/Interfaces/Registrable.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3d859c9d6fcb91241aa741c6a8dabe1d \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Saveable.cs b/Runtime/Library/Interfaces/Saveable.cs new file mode 100644 index 00000000..a63f3ad9 --- /dev/null +++ b/Runtime/Library/Interfaces/Saveable.cs @@ -0,0 +1,8 @@ +namespace RealMethod +{ + public interface ISaveable + { + void OnLoaded(); + void OnSaved(); + } +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Saveable.cs.meta b/Runtime/Library/Interfaces/Saveable.cs.meta new file mode 100644 index 00000000..9ed3476b --- /dev/null +++ b/Runtime/Library/Interfaces/Saveable.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a7ae0ff1d5367584fa20e0d798e23445 \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Spawnable.cs b/Runtime/Library/Interfaces/Spawnable.cs new file mode 100644 index 00000000..2681c1f1 --- /dev/null +++ b/Runtime/Library/Interfaces/Spawnable.cs @@ -0,0 +1,35 @@ +using UnityEngine; + +namespace RealMethod +{ + + public interface ISpawn + { + void OnSpawn(); + } + public interface ISpawnWithAuthor + { + void OnSpawn(Object author); + } + public interface ISpawnWithArgument + { + void OnSpawn(TArgument argument); + } + public interface ISpawnWithTwoArgument + { + void OnSpawn(TArgumentA argumentA, TArgumentB argumentB); + } + public interface IDespawn + { + void OnDespawn(); + } + public interface IDespawnWithAuthor + { + void OnDespawn(Object author); + } + + + +} + + diff --git a/Runtime/Library/Interfaces/Initializable.cs.meta b/Runtime/Library/Interfaces/Spawnable.cs.meta similarity index 100% rename from Runtime/Library/Interfaces/Initializable.cs.meta rename to Runtime/Library/Interfaces/Spawnable.cs.meta diff --git a/Runtime/Core/Definitions/Tick.cs b/Runtime/Library/Interfaces/Tick.cs similarity index 100% rename from Runtime/Core/Definitions/Tick.cs rename to Runtime/Library/Interfaces/Tick.cs diff --git a/Runtime/Core/Definitions/Tick.cs.meta b/Runtime/Library/Interfaces/Tick.cs.meta similarity index 100% rename from Runtime/Core/Definitions/Tick.cs.meta rename to Runtime/Library/Interfaces/Tick.cs.meta diff --git a/Runtime/Library/Interfaces/Widget.cs b/Runtime/Library/Interfaces/Widget.cs new file mode 100644 index 00000000..736aed5f --- /dev/null +++ b/Runtime/Library/Interfaces/Widget.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace RealMethod +{ + public interface IWidget + { + MonoBehaviour GetWidgetClass(); + void SceneInitialized(UIManager manager); + } +} \ No newline at end of file diff --git a/Runtime/Library/Interfaces/Widget.cs.meta b/Runtime/Library/Interfaces/Widget.cs.meta new file mode 100644 index 00000000..a56524ae --- /dev/null +++ b/Runtime/Library/Interfaces/Widget.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5ccd760c30543b141a059a176b7555a8 \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/Blackboard.cs b/Runtime/Library/SharedScripts/Classes/Blackboard.cs new file mode 100644 index 00000000..a2c4e2e9 --- /dev/null +++ b/Runtime/Library/SharedScripts/Classes/Blackboard.cs @@ -0,0 +1,301 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + [Serializable] + public struct Blackboard + { + private enum ValueType + { + None = 0, + Bool = 1, + Int = 2, + Float = 3, + String = 4, + Vector2 = 5, + Vector3 = 6, + Prefab = 7, + Asset = 8, + Component = 10, + } + [Serializable] + private struct ValuePointer + { + [field: SerializeField] + public Hash128 Name { get; private set; } + [field: SerializeField] + public ValueType Type { get; private set; } + [field: SerializeField] + public int Index { get; private set; } + public bool IsValid => Type != ValueType.None; + + public ValuePointer(Name16 Vname, ValueType Vtype, int Vindex = -1) + { + if (Vtype != ValueType.None) + { + Name = Hash128.Compute(Vname); + Type = Vtype; + Index = Vindex; + } + else + { + Debug.LogWarning("Value didnt store in Blackboard,Type is None"); + Name = Hash128.Compute(string.Empty); + Type = ValueType.None; + Index = -1; + } + } + public void Clear() + { + Name = Hash128.Compute(string.Empty); + Type = ValueType.None; + Index = -1; + } + } + + [SerializeField, ReadOnly] + private ValuePointer[] Variables; + [SerializeField, ReadOnly] + private bool[] Boolean; + [SerializeField, ReadOnly] + private int[] Intiger; + [SerializeField, ReadOnly] + private float[] Float; + [SerializeField, ReadOnly] + private string[] String; + [SerializeField, ReadOnly] + private Vector2[] Vector2; + [SerializeField, ReadOnly] + private Vector3[] Vector3; + [SerializeField, ReadOnly] + private Prefab[] Prefab; + [SerializeField, ReadOnly] + private PrimitiveAsset[] Asset; + [SerializeField, ReadOnly] + private Component[] Component; + public int Length + { + get + { + int result = 0; + foreach (var item in Variables) + { + if (item.IsValid) + { + result++; + } + } + return result; + } + } + public int MaxSize + { + get + { + return Boolean.Length; + } + } + + public Blackboard(int size = 10) + { + int TypesCount = Enum.GetValues(typeof(ValueType)).Length - 1; + Variables = new ValuePointer[size * TypesCount]; + Boolean = new bool[size]; + Intiger = new int[size]; + Float = new float[size]; + String = new string[size]; + Vector2 = new Vector2[size]; + Vector3 = new Vector3[size]; + Prefab = new Prefab[size]; + Asset = new PrimitiveAsset[size]; + Component = new Component[size]; + } + + public bool HasValue(Name16 VariableName) + { + return TryFindPointer(VariableName, out ValuePointer outher); + } + public T GetValue(Name16 VariableName) + { + if (TryFindPointer(VariableName, out ValuePointer item)) + { + object result = item.Type switch + { + ValueType.Bool => Boolean[item.Index], + ValueType.Int => Intiger[item.Index], + ValueType.Float => Float[item.Index], + ValueType.String => String[item.Index], + ValueType.Vector2 => Vector2[item.Index], + ValueType.Vector3 => Vector3[item.Index], + ValueType.Prefab => Prefab[item.Index], + ValueType.Asset => Asset[item.Index], + ValueType.Component => Component[item.Index], + _ => null + }; + + if (result is T finalValue) + return finalValue; + + throw new InvalidCastException($"Variable '{VariableName}' is type {item.Type} but requested {typeof(T)}"); + } + + Debug.LogWarning($"Variable '{VariableName}' not found."); + return default; + } + public void SetValue(Name16 VariableName, T value) + { + if (TryFindPointer(VariableName, out ValuePointer item)) + { + SetValue(value, item.Index); + } + else + { + CreateValue(VariableName, value); + } + } + public bool CreateValue(Name16 VariableName, T DefaultValue) + { + ValueType TargetType = ConvertType(); + int TypeIndex = GetLengthByType(TargetType); + if (TypeIndex < MaxSize - 1) + { + if (SetValue(DefaultValue, TypeIndex)) + { + Variables[Length] = new ValuePointer(VariableName, TargetType, TypeIndex); + return true; + } + else + { + return false; + } + } + else + { + Debug.LogWarning($"Blackboard for Variable of {typeof(T)} is full"); + return false; + } + } + public bool RemoveValue(Name16 VariableName) + { + if (TryFindPointer(VariableName, out ValuePointer item)) + { + item.Clear(); + return true; + } + return false; + } + public void SetSize(int size) + { + int TypesCount = Enum.GetValues(typeof(ValueType)).Length - 1; + if (Variables == null || Variables.Length == 0) Variables = new ValuePointer[size * TypesCount]; + if (Boolean == null || Boolean.Length == 0) Boolean = new bool[size]; + if (Intiger == null || Intiger.Length == 0) Intiger = new int[size]; + if (Float == null || Float.Length == 0) Float = new float[size]; + if (String == null || String.Length == 0) String = new string[size]; + if (Vector2 == null || Vector2.Length == 0) Vector2 = new Vector2[size]; + if (Vector3 == null || Vector3.Length == 0) Vector3 = new Vector3[size]; + if (Prefab == null || Prefab.Length == 0) Prefab = new Prefab[size]; + if (Asset == null || Asset.Length == 0) Asset = new PrimitiveAsset[size]; + if (Component == null || Component.Length == 0) Component = new Component[size]; + } + public void Clear() + { + SetSize(MaxSize); + } + + private bool TryFindPointer(Name16 VariableName, out ValuePointer pointer) + { + Hash128 TargetName = Hash128.Compute(VariableName); + ValueType TargetType = ConvertType(); + foreach (var item in Variables) + { + if (item.Type == TargetType) + { + if (item.Name == TargetName) + { + pointer = item; + return true; + } + } + } + pointer = new ValuePointer(); + return false; + } + private int GetLengthByType(ValueType TargetType) + { + int result = 0; + foreach (var item in Variables) + { + if (item.Type == TargetType) + { + if (item.Index > result) + { + result = item.Index; + } + else + { + if (item.Index == result) + result++; + } + } + } + return result; + } + private ValueType ConvertType() + { + if (typeof(T) == typeof(bool)) { return ValueType.Bool; } + else if (typeof(T) == typeof(int)) { return ValueType.Int; } + else if (typeof(T) == typeof(float)) { return ValueType.Float; } + else if (typeof(T) == typeof(string)) { return ValueType.String; } + else if (typeof(T) == typeof(Vector2)) { return ValueType.Vector2; } + else if (typeof(T) == typeof(Vector3)) { return ValueType.Vector3; } + else if (typeof(T) == typeof(Prefab)) { return ValueType.Prefab; } + else if (typeof(T) == typeof(PrimitiveAsset)) { return ValueType.Asset; } + else if (typeof(T) == typeof(Component)) { return ValueType.Component; } + else { return ValueType.None; } + } + private bool SetValue(T value, int index) + { + if (index >= MaxSize) + { + Debug.LogError($"For this index {index} of {typeof(T)} didn't have any slot"); + return false; + } + switch (value) + { + case bool v: + Boolean[index] = v; + return true; + case int v: + Intiger[index] = v; + return true; + case float v: + Float[index] = v; + return true; + case string v: + String[index] = v; + return true; + case Vector2 v: + Vector2[index] = v; + return true; + case Vector3 v: + Vector3[index] = v; + return true; + case Prefab v: + Prefab[index] = v; + return true; + case PrimitiveAsset v: + Asset[index] = v; + return true; + case Component v: + Component[index] = v; + return true; + default: + Debug.LogError($"Type {typeof(T)} is not supported."); + return false; + } + } + } + +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/Blackboard.cs.meta b/Runtime/Library/SharedScripts/Classes/Blackboard.cs.meta new file mode 100644 index 00000000..6f3e8fc3 --- /dev/null +++ b/Runtime/Library/SharedScripts/Classes/Blackboard.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2c2ddfb1230605e45a3c934f06e0209d \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/DoOnce.cs b/Runtime/Library/SharedScripts/Classes/DoOnce.cs deleted file mode 100644 index 1179b94b..00000000 --- a/Runtime/Library/SharedScripts/Classes/DoOnce.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace RealMethod -{ - public class DoOnce - { - private bool hasRun = false; - - /// - /// Executes the given action only once. - /// - public void Do(System.Action action) - { - if (!hasRun) - { - hasRun = true; - action?.Invoke(); - } - } - - /// - /// Resets the DoOnce so it can run again. - /// - public void Reset() - { - hasRun = false; - } - } - -} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/Flag.cs b/Runtime/Library/SharedScripts/Classes/Flag.cs new file mode 100644 index 00000000..4f116191 --- /dev/null +++ b/Runtime/Library/SharedScripts/Classes/Flag.cs @@ -0,0 +1,53 @@ +using UnityEngine; + +namespace RealMethod +{ + public static class Flag + { + private static readonly NameTable Flags = new NameTable(); + + public static void Create(string name) + { + Flags.Add(name, false); + } + public static void Set(string name, bool DefaultValue) + { + if (Flags.ContainsKey(name)) + { + Flags[name] = DefaultValue; + } + else + { + Debug.LogWarning($"Can't find Flag with {name}!"); + } + } + public static bool Get(string name) + { + if (Flags.ContainsKey(name)) + { + return Flags[name]; + } + else + { + Debug.LogWarning($"Can't find Flag with {name}!"); + return false; + } + } + public static bool IsValid(string name) + { + return Flags.ContainsKey(name); + } + public static void Remove(string name) + { + if (Flags.ContainsKey(name)) + { + Flags.Remove(name); + } + else + { + Debug.LogWarning($"Can't find Flag with {name}!"); + } + } + + } +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/Flag.cs.meta b/Runtime/Library/SharedScripts/Classes/Flag.cs.meta new file mode 100644 index 00000000..d1f3cefd --- /dev/null +++ b/Runtime/Library/SharedScripts/Classes/Flag.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fec39332a051c3846b5fe6c0b5d75f19 \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/Map.cs b/Runtime/Library/SharedScripts/Classes/Map.cs new file mode 100644 index 00000000..de230b3d --- /dev/null +++ b/Runtime/Library/SharedScripts/Classes/Map.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using UnityEngine; + +namespace RealMethod +{ + public abstract class MapCore + { + public abstract class Storage { } + + protected class Dictionary : System.Collections.Generic.Dictionary + { + public Dictionary() { } + public Dictionary(IDictionary dict) : base(dict) { } + public Dictionary(SerializationInfo info, StreamingContext context) : base(info, context) { } + } + } + [Serializable] + public abstract class MapCore : MapCore, IDictionary, IDictionary, ISerializationCallbackReceiver, IDeserializationCallback, ISerializable + { + Dictionary m_dict; + [SerializeField] + TKey[] m_keys; + [SerializeField] + TValueStorage[] m_values; + + + // Implement IDictionary Interface + public ICollection Keys { get { return ((IDictionary)m_dict).Keys; } } + public ICollection Values { get { return ((IDictionary)m_dict).Values; } } + public int Count { get { return ((IDictionary)m_dict).Count; } } + public bool IsReadOnly { get { return ((IDictionary)m_dict).IsReadOnly; } } + public TValue this[TKey key] + { + get { return ((IDictionary)m_dict)[key]; } + set { ((IDictionary)m_dict)[key] = value; } + } + public TKey GetKey(int index) + { + return m_dict.Keys.ElementAt(index); + } + public TValue GetValue(int index) + { + return m_dict.Values.ElementAt(index); + } + public void Add(TKey key, TValue value) + { + ((IDictionary)m_dict).Add(key, value); + } + public bool ContainsKey(TKey key) + { + return ((IDictionary)m_dict).ContainsKey(key); + } + public bool Remove(TKey key) + { + return ((IDictionary)m_dict).Remove(key); + } + public bool TryGetValue(TKey key, out TValue value) + { + return ((IDictionary)m_dict).TryGetValue(key, out value); + } + public void Add(KeyValuePair item) + { + ((IDictionary)m_dict).Add(item); + } + public void Clear() + { + ((IDictionary)m_dict).Clear(); + } + public bool Contains(KeyValuePair item) + { + return ((IDictionary)m_dict).Contains(item); + } + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((IDictionary)m_dict).CopyTo(array, arrayIndex); + } + public bool Remove(KeyValuePair item) + { + return ((IDictionary)m_dict).Remove(item); + } + public IEnumerator> GetEnumerator() + { + return ((IDictionary)m_dict).GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() + { + return ((IDictionary)m_dict).GetEnumerator(); + } + + // Implement IDictionary Interface + public bool IsFixedSize { get { return ((IDictionary)m_dict).IsFixedSize; } } + ICollection IDictionary.Keys { get { return ((IDictionary)m_dict).Keys; } } + ICollection IDictionary.Values { get { return ((IDictionary)m_dict).Values; } } + public bool IsSynchronized { get { return ((IDictionary)m_dict).IsSynchronized; } } + public object SyncRoot { get { return ((IDictionary)m_dict).SyncRoot; } } + public object this[object key] + { + get { return ((IDictionary)m_dict)[key]; } + set { ((IDictionary)m_dict)[key] = value; } + } + public void Add(object key, object value) + { + ((IDictionary)m_dict).Add(key, value); + } + public bool Contains(object key) + { + return ((IDictionary)m_dict).Contains(key); + } + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return ((IDictionary)m_dict).GetEnumerator(); + } + public void Remove(object key) + { + ((IDictionary)m_dict).Remove(key); + } + public void CopyTo(System.Array array, int index) + { + ((IDictionary)m_dict).CopyTo(array, index); + } + + // Implement IDeserializationCallback Interface + public void OnDeserialization(object sender) + { + ((IDeserializationCallback)m_dict).OnDeserialization(sender); + } + + // Implement ISerializable Interface + protected MapCore(SerializationInfo info, StreamingContext context) + { + m_dict = new Dictionary(info, context); + } + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + ((ISerializable)m_dict).GetObjectData(info, context); + } + + + + // Constructor + public MapCore() + { + m_dict = new Dictionary(); + } + public MapCore(IDictionary dict) + { + m_dict = new Dictionary(dict); + } + + // Functions + public void CopyFrom(IDictionary dict) + { + m_dict.Clear(); + foreach (var kvp in dict) + { + m_dict[kvp.Key] = kvp.Value; + } + } + public void OnAfterDeserialize() + { + if (m_keys != null && m_values != null && m_keys.Length == m_values.Length) + { + m_dict.Clear(); + int n = m_keys.Length; + for (int i = 0; i < n; ++i) + { + m_dict[m_keys[i]] = GetValue(m_values, i); + } + + m_keys = null; + m_values = null; + } + } + public void OnBeforeSerialize() + { + int n = m_dict.Count; + m_keys = new TKey[n]; + m_values = new TValueStorage[n]; + + int i = 0; + foreach (var kvp in m_dict) + { + m_keys[i] = kvp.Key; + SetValue(m_values, i, kvp.Value); + ++i; + } + } + + // Abstractions + protected abstract void SetValue(TValueStorage[] storage, int i, TValue value); + protected abstract TValue GetValue(TValueStorage[] storage, int i); + } + + + public static class SerializableDictionary + { + public class Storage : MapCore.Storage + { + public T data; + } + } + + [Serializable] + public class Map : MapCore + { + public Map() { } + public Map(IDictionary dict) : base(dict) { } + protected Map(SerializationInfo info, StreamingContext context) : base(info, context) { } + + protected override TValue GetValue(TValue[] storage, int i) + { + return storage[i]; + } + protected override void SetValue(TValue[] storage, int i, TValue value) + { + storage[i] = value; + } + } + [Serializable] + public class Map : MapCore where TValueStorage : SerializableDictionary.Storage, new() + { + public Map() { } + public Map(IDictionary dict) : base(dict) { } + protected Map(SerializationInfo info, StreamingContext context) : base(info, context) { } + + protected override TValue GetValue(TValueStorage[] storage, int i) + { + return storage[i].data; + } + protected override void SetValue(TValueStorage[] storage, int i, TValue value) + { + storage[i] = new TValueStorage(); + storage[i].data = value; + } + } +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/Map.cs.meta b/Runtime/Library/SharedScripts/Classes/Map.cs.meta new file mode 100644 index 00000000..a0bfd23f --- /dev/null +++ b/Runtime/Library/SharedScripts/Classes/Map.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b85e0b29837fdf9478b4b75facb9e18c \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/MemberBinding.cs b/Runtime/Library/SharedScripts/Classes/MemberBinding.cs new file mode 100644 index 00000000..db441b3d --- /dev/null +++ b/Runtime/Library/SharedScripts/Classes/MemberBinding.cs @@ -0,0 +1,164 @@ +using System; +using System.Reflection; +using UnityEngine; + +namespace RealMethod +{ + public abstract class MemberBinding + { + [Header("Member Info")] + [SerializeField] + private bool UseRefrence = false; + [SerializeField, ConditionalHide("UseRefrence", true, true)] + private string gameObjectName; + [SerializeField, ConditionalHide("UseRefrence", true, false)] + private GameObject Ref; + [SerializeField] + private SoftType componentType; + [SerializeField, Slug] + private string memberName; + public GameObject SelectedGameObject + { + get + { + if (UseRefrence) + { + return Ref; + } + + if (cachedObject == null) + { + cachedObject = FindGameObject(); + } + return cachedObject; + } + } + public Component SelectedComponent + { + get + { + if (cachedComponent == null) + { + cachedComponent = FindComponent(SelectedGameObject); + } + return cachedComponent; + } + } + public MemberInfo SelectedMember + { + get + { + if (cachedMember == null) + { + cachedMember = FindMemeber(componentType.Type, memberName); + } + return cachedMember; + } + } + + private GameObject cachedObject; + private Component cachedComponent; + private MemberInfo cachedMember; + + + protected virtual GameObject FindGameObject() + { + var Target = GameObject.Find(gameObjectName); + if (Target == null) + { + Debug.LogWarning($"GameObject '{gameObjectName}' not found."); + } + return null; + } + protected virtual Component FindComponent(GameObject target) + { + var comp = target.GetComponent(componentType.Type); + if (comp == null) + { + Debug.LogWarning($"Component type '{componentType}' not found."); + } + return comp; + } + protected virtual MemberInfo FindMemeber(Type type, string memberName) + { + MemberInfo Info = type.GetField(memberName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + if (Info == null) + { + Info = type.GetProperty(memberName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + } + + return Info; + } + } + + + [Serializable] + public class MemberVariable : MemberBinding where T : struct + { + public T GetValue() + { + if (SelectedMember is FieldInfo FInfo) + { + return (T)FInfo.GetValue(SelectedComponent); + } + else if (SelectedMember is PropertyInfo PInfo) + { + return (T)PInfo.GetValue(SelectedComponent); + } + else + { + Debug.LogWarning($"Member '{SelectedMember.Name}' not found on component type '{SelectedComponent.GetType()}'."); + return default; + } + } + } + [Serializable] + public class MemberMethod : MemberBinding + { + // MemberBinding Methods + protected override MemberInfo FindMemeber(Type type, string memberName) + { + MethodInfo method = type.GetMethod(memberName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + if (method == null) + { + Debug.LogWarning($"Method '{memberName}' not found on '{type}'."); + return null; + } + + return method; + } + + // Functions + public void Invoke(params object[] arguments) + { + if (SelectedMember is MethodInfo Info) + { + if (arguments == null) + { + Info.Invoke(SelectedComponent, null); + } + else + { + if (arguments.Length > 0) + { + Info.Invoke(SelectedComponent, arguments); + } + } + } + else + { + Debug.LogWarning($"Member '{SelectedMember}' should be [MethodInfo] for Invoking."); + } + } + + } + + + + +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/MemberBinding.cs.meta b/Runtime/Library/SharedScripts/Classes/MemberBinding.cs.meta new file mode 100644 index 00000000..2bdee0f0 --- /dev/null +++ b/Runtime/Library/SharedScripts/Classes/MemberBinding.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 10c20d6a5d4d0ae4f9e539304b76448e \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/NameTable.cs b/Runtime/Library/SharedScripts/Classes/NameTable.cs new file mode 100644 index 00000000..ec78d837 --- /dev/null +++ b/Runtime/Library/SharedScripts/Classes/NameTable.cs @@ -0,0 +1,138 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + + +namespace RealMethod +{ + /// + /// A dictionary keyed by string but internally hashes each key using . + /// Provides stable lookups and near-zero collision risk. + /// + public class NameTable : IEnumerable> + { + private Dictionary list; + private static int GlobalIdCounter; + public int ID { get; private set; } + + + /// + /// Gets the number of entries. + /// + public int Count => list?.Count ?? 0; + public bool IsValid => list != null; + /// + /// Gets all stored keys. + /// + public ICollection Keys + { + get + { + List keys = new(); + foreach (var k in list.Keys) + keys.Add(k.ToString()); + return keys; + } + } + /// + /// Gets all stored values. + /// + public IEnumerable Values + { + get + { + return list.Values; + } + } + public bool IsReadOnly => false; + + + public NameTable(int prewarm = 10) + { + ID = ++GlobalIdCounter; + list = new Dictionary(prewarm); + } + + + // Indexer + public T this[string name] + { + get => list[Key(name)]; + set => list[Key(name)] = value; + } + + // Implement IEnumerable Interface + public IEnumerator> GetEnumerator() + { + return list.GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + + // Functions + public bool ContainsKey(string name) + { + return list.ContainsKey(Key(name)); + } + public bool TryGetValue(string name, out T value) + { + return list.TryGetValue(Key(name), out value); + } + /// + /// Adds or replaces an entry by name. + /// + public void Add(string name, T value) + { + list.Add(Key(name), value); + } + public bool TryAdd(string name, T value) + { + return list.TryAdd(Key(name), value); + } + /// + /// Removes an entry by name. + /// + public bool Remove(string name) + { + return list.Remove(Key(name)); + } + /// + /// Removes all entries. + /// + public void Clear() + { + list.Clear(); + } + public string[] GetKeys() + { + int c = list.Count; + string[] result = new string[c]; + + int i = 0; + foreach (var kvp in list) + result[i++] = kvp.Key.ToString(); + + return result; + } + + public string Find(T value) + { + foreach (var kvp in list) + { + if (EqualityComparer.Default.Equals(kvp.Value, value)) + return kvp.Key.ToString(); + } + + return null; + } + + + /// + /// Computes a stable 128-bit key from a string. + /// + private Hash128 Key(string name) => Hash128.Compute(name); + } +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Structs/Hictionary.cs.meta b/Runtime/Library/SharedScripts/Classes/NameTable.cs.meta similarity index 100% rename from Runtime/Library/SharedScripts/Structs/Hictionary.cs.meta rename to Runtime/Library/SharedScripts/Classes/NameTable.cs.meta diff --git a/Runtime/Library/Vendor/SerializableDictionary/SerializableHashSet.cs b/Runtime/Library/SharedScripts/Classes/SerializableHashSet.cs similarity index 96% rename from Runtime/Library/Vendor/SerializableDictionary/SerializableHashSet.cs rename to Runtime/Library/SharedScripts/Classes/SerializableHashSet.cs index fe9bddd7..82d0cdea 100644 --- a/Runtime/Library/Vendor/SerializableDictionary/SerializableHashSet.cs +++ b/Runtime/Library/SharedScripts/Classes/SerializableHashSet.cs @@ -11,6 +11,7 @@ public abstract class SerializableHashSetBase { public abstract class Storage { } + protected class HashSet : System.Collections.Generic.HashSet { public HashSet() { } @@ -26,172 +27,146 @@ public abstract class SerializableHashSet : SerializableHashSetBase, ISet, [SerializeField] T[] m_keys; - public SerializableHashSet() - { - m_hashSet = new HashSet(); - } - - public SerializableHashSet(ISet set) - { - m_hashSet = new HashSet(set); - } - - public void CopyFrom(ISet set) - { - m_hashSet.Clear(); - foreach (var value in set) - { - m_hashSet.Add(value); - } - } - - public void OnAfterDeserialize() - { - if (m_keys != null) - { - m_hashSet.Clear(); - int n = m_keys.Length; - for (int i = 0; i < n; ++i) - { - m_hashSet.Add(m_keys[i]); - } - - m_keys = null; - } - } - - public void OnBeforeSerialize() - { - int n = m_hashSet.Count; - m_keys = new T[n]; - - int i = 0; - foreach (var value in m_hashSet) - { - m_keys[i] = value; - ++i; - } - } - - #region ISet + // Implement ISet Interface public int Count { get { return ((ISet)m_hashSet).Count; } } public bool IsReadOnly { get { return ((ISet)m_hashSet).IsReadOnly; } } - public bool Add(T item) { return ((ISet)m_hashSet).Add(item); } - public void ExceptWith(IEnumerable other) { ((ISet)m_hashSet).ExceptWith(other); } - public void IntersectWith(IEnumerable other) { ((ISet)m_hashSet).IntersectWith(other); } - public bool IsProperSubsetOf(IEnumerable other) { return ((ISet)m_hashSet).IsProperSubsetOf(other); } - public bool IsProperSupersetOf(IEnumerable other) { return ((ISet)m_hashSet).IsProperSupersetOf(other); } - public bool IsSubsetOf(IEnumerable other) { return ((ISet)m_hashSet).IsSubsetOf(other); } - public bool IsSupersetOf(IEnumerable other) { return ((ISet)m_hashSet).IsSupersetOf(other); } - public bool Overlaps(IEnumerable other) { return ((ISet)m_hashSet).Overlaps(other); } - public bool SetEquals(IEnumerable other) { return ((ISet)m_hashSet).SetEquals(other); } - public void SymmetricExceptWith(IEnumerable other) { ((ISet)m_hashSet).SymmetricExceptWith(other); } - public void UnionWith(IEnumerable other) { ((ISet)m_hashSet).UnionWith(other); } - void ICollection.Add(T item) { ((ISet)m_hashSet).Add(item); } - public void Clear() { ((ISet)m_hashSet).Clear(); } - public bool Contains(T item) { return ((ISet)m_hashSet).Contains(item); } - public void CopyTo(T[] array, int arrayIndex) { ((ISet)m_hashSet).CopyTo(array, arrayIndex); } - public bool Remove(T item) { return ((ISet)m_hashSet).Remove(item); } - public IEnumerator GetEnumerator() { return ((ISet)m_hashSet).GetEnumerator(); } - IEnumerator IEnumerable.GetEnumerator() { return ((ISet)m_hashSet).GetEnumerator(); } - #endregion - - #region IDeserializationCallback - + // Implement IDeserializationCallback Interface public void OnDeserialization(object sender) { ((IDeserializationCallback)m_hashSet).OnDeserialization(sender); } - #endregion - - #region ISerializable - + // Implement ISerializable Interface protected SerializableHashSet(SerializationInfo info, StreamingContext context) { m_hashSet = new HashSet(info, context); } - public void GetObjectData(SerializationInfo info, StreamingContext context) { ((ISerializable)m_hashSet).GetObjectData(info, context); } - #endregion + + + + public SerializableHashSet() + { + m_hashSet = new HashSet(); + } + public SerializableHashSet(ISet set) + { + m_hashSet = new HashSet(set); + } + + public void CopyFrom(ISet set) + { + m_hashSet.Clear(); + foreach (var value in set) + { + m_hashSet.Add(value); + } + } + public void OnAfterDeserialize() + { + if (m_keys != null) + { + m_hashSet.Clear(); + int n = m_keys.Length; + for (int i = 0; i < n; ++i) + { + m_hashSet.Add(m_keys[i]); + } + + m_keys = null; + } + } + public void OnBeforeSerialize() + { + int n = m_hashSet.Count; + m_keys = new T[n]; + + int i = 0; + foreach (var value in m_hashSet) + { + m_keys[i] = value; + ++i; + } + } + } } #endif \ No newline at end of file diff --git a/Runtime/Library/Vendor/SerializableDictionary/SerializableHashSet.cs.meta b/Runtime/Library/SharedScripts/Classes/SerializableHashSet.cs.meta similarity index 100% rename from Runtime/Library/Vendor/SerializableDictionary/SerializableHashSet.cs.meta rename to Runtime/Library/SharedScripts/Classes/SerializableHashSet.cs.meta diff --git a/Runtime/Library/SharedScripts/Enumeration/CSharpSystem.cs b/Runtime/Library/SharedScripts/Enumeration/CSharpSystem.cs new file mode 100644 index 00000000..a049d962 --- /dev/null +++ b/Runtime/Library/SharedScripts/Enumeration/CSharpSystem.cs @@ -0,0 +1,8 @@ +namespace RealMethod +{ + public enum LoadStage + { + Ascync, + Scync + } +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Enumeration/CSharpSystem.cs.meta b/Runtime/Library/SharedScripts/Enumeration/CSharpSystem.cs.meta new file mode 100644 index 00000000..3b0d3e31 --- /dev/null +++ b/Runtime/Library/SharedScripts/Enumeration/CSharpSystem.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7d04823552b8ad949bbfb7ab73c91703 \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Enumeration/Directions.cs b/Runtime/Library/SharedScripts/Enumeration/Directions.cs new file mode 100644 index 00000000..485a5f10 --- /dev/null +++ b/Runtime/Library/SharedScripts/Enumeration/Directions.cs @@ -0,0 +1,58 @@ +namespace RealMethod +{ + /// + /// Only the four cardinal directions. + /// + public enum Dir4 + { + Up, + Right, + Down, + Left + } + /// + /// Direction4 + Center (neutral). + /// + public enum Dir5 + { + Center, + Up, + Right, + Down, + Left + } + /// + /// Cardinal + diagonal directions. + /// + public enum Dir8 + { + Up, + UpRight, + Right, + DownRight, + Down, + DownLeft, + Left, + UpLeft + } + /// + /// Direction8 + Center. + /// + public enum Dir9 + { + Center, + Up, + UpRight, + Right, + DownRight, + Down, + DownLeft, + Left, + UpLeft + } + + + + + +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Enumeration/Directions.cs.meta b/Runtime/Library/SharedScripts/Enumeration/Directions.cs.meta new file mode 100644 index 00000000..4e8864a0 --- /dev/null +++ b/Runtime/Library/SharedScripts/Enumeration/Directions.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fdc2da0d08ac4df4fbcd39e1635572c7 \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Enumeration/General_Enum.cs.meta b/Runtime/Library/SharedScripts/Enumeration/General_Enum.cs.meta deleted file mode 100644 index aa05f615..00000000 --- a/Runtime/Library/SharedScripts/Enumeration/General_Enum.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 4c9c5efed73019a45bf952ed85894ddf \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Enumeration/RealMethodSystem.cs b/Runtime/Library/SharedScripts/Enumeration/RealMethodSystem.cs new file mode 100644 index 00000000..2db7881f --- /dev/null +++ b/Runtime/Library/SharedScripts/Enumeration/RealMethodSystem.cs @@ -0,0 +1,9 @@ +namespace RealMethod +{ + public enum ScopeTarget + { + Both, + World, + Game, + } +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Enumeration/RealMethodSystem.cs.meta b/Runtime/Library/SharedScripts/Enumeration/RealMethodSystem.cs.meta new file mode 100644 index 00000000..2ba78a1d --- /dev/null +++ b/Runtime/Library/SharedScripts/Enumeration/RealMethodSystem.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3b0e9a1cf2fcb274085686abcc9366ab \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Enumeration/General_Enum.cs b/Runtime/Library/SharedScripts/Enumeration/UnitySystem.cs similarity index 77% rename from Runtime/Library/SharedScripts/Enumeration/General_Enum.cs rename to Runtime/Library/SharedScripts/Enumeration/UnitySystem.cs index ae54ac41..c7437424 100644 --- a/Runtime/Library/SharedScripts/Enumeration/General_Enum.cs +++ b/Runtime/Library/SharedScripts/Enumeration/UnitySystem.cs @@ -8,11 +8,6 @@ public enum UpdateMethod FixedUpdate = 4 } - public enum LoadStage - { - Ascync, - Scync - } public enum TriggerStage { None = 0, @@ -20,5 +15,9 @@ public enum TriggerStage Stay = 2, Exit = 2, } - + public enum InputSystemType + { + OldInputSystem, + NewInputSystem + } } \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Enumeration/UnitySystem.cs.meta b/Runtime/Library/SharedScripts/Enumeration/UnitySystem.cs.meta new file mode 100644 index 00000000..315d74b4 --- /dev/null +++ b/Runtime/Library/SharedScripts/Enumeration/UnitySystem.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f4ed914a31845584ab8fec0e3985f650 \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Structs/DoOnce.cs b/Runtime/Library/SharedScripts/Structs/DoOnce.cs new file mode 100644 index 00000000..e3781e41 --- /dev/null +++ b/Runtime/Library/SharedScripts/Structs/DoOnce.cs @@ -0,0 +1,30 @@ + +namespace RealMethod +{ + public static class DoOnce + { + private static readonly NameTable Flags = new NameTable(); + public static bool Check(string name) + { + if (!Flags.ContainsKey(name)) + Flags.Add(name, false); + + if (Flags[name]) return false; + + Flags[name] = true; + return true; + } + public static void Reset(string name) + { + if (Flags.ContainsKey(name)) + { + Flags[name] = false; + } + else + { + Flags.Add(name, false); + } + } + } + +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Classes/DoOnce.cs.meta b/Runtime/Library/SharedScripts/Structs/DoOnce.cs.meta similarity index 100% rename from Runtime/Library/SharedScripts/Classes/DoOnce.cs.meta rename to Runtime/Library/SharedScripts/Structs/DoOnce.cs.meta diff --git a/Runtime/Library/SharedScripts/Structs/Hictionary.cs b/Runtime/Library/SharedScripts/Structs/Hictionary.cs deleted file mode 100644 index feb2ffb6..00000000 --- a/Runtime/Library/SharedScripts/Structs/Hictionary.cs +++ /dev/null @@ -1,92 +0,0 @@ -using UnityEngine; -using System.Collections.Generic; -using System.Collections; - - -namespace RealMethod -{ - public struct Hictionary //: IEnumerable> - { - private Dictionary List; - public int Count => List.Count; - - - public Hictionary(int Prewarm) - { - List = new Dictionary(Prewarm); - } - - // Access values - public T this[string Name] - { - get => List[Hash128.Compute(Name)]; - set => List[Hash128.Compute(Name)] = value; - } - - public bool IsValid() - { - return List != null; - } - public bool ContainsKey(string Name) - { - return List.ContainsKey(Hash128.Compute(Name)); - } - public void Add(string Name, T Value) - { - List.Add(Hash128.Compute(Name), Value); - } - public bool Remove(string Name) - { - return List.Remove(Hash128.Compute(Name)); - } - public bool TryGetValue(string Name, out T Result) - { - return List.TryGetValue(Hash128.Compute(Name), out Result); - } - public string[] GetKeys() - { - var keys = new List(List.Keys); - string[] result = new string[keys.Count]; - for (int i = 0; i < keys.Count; i++) - { - result[i] = keys[i].ToString(); - } - return result; - } - public T[] GetValues() - { - return new List(List.Values).ToArray(); - } - public void Clear() - { - List.Clear(); - } - public string Find(T value) - { - foreach (var dictionary in List) - { - if (EqualityComparer.Default.Equals(dictionary.Value, value)) - { - return dictionary.Key.ToString(); - } - } - return null; - } - public bool TryAdd(string Name, T Value) - { - return List.TryAdd(Hash128.Compute(Name), Value); - } - - // // Implement IEnumerable> - // public IEnumerator> GetEnumerator() - // { - // return List.GetEnumerator(); // Delegates to the internal dictionary - // } - - // // Non-generic IEnumerable - // IEnumerator IEnumerable.GetEnumerator() - // { - // return GetEnumerator(); - // } - } -} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Structs/HitData.cs b/Runtime/Library/SharedScripts/Structs/HitData.cs new file mode 100644 index 00000000..1449dc9f --- /dev/null +++ b/Runtime/Library/SharedScripts/Structs/HitData.cs @@ -0,0 +1,65 @@ +using UnityEngine; + +namespace RealMethod +{ + public struct HitData + { + // Actors + public GameObject attacker; + public GameObject target; + + // Components + public Collider collider; + public Rigidbody rigidbody; + + // Location + public Vector3 point; // Impact point + public Vector3 normal; // Impact normal + public Vector3 traceStart; // Trace start + public Vector3 traceEnd; // Trace end + + // Direction + public Vector3 direction; + + // Distance + public float distance; + + // Damage + public float damage; + + // Surface info + public PhysicsMaterial physicMaterial; + + // State + public bool blockingHit; + public bool startPenetrating; + + // Utility constructor + public HitData(RaycastHit hit, GameObject attacker, float damage) + { + this.attacker = attacker; + this.target = hit.collider ? hit.collider.gameObject : null; + + collider = hit.collider; + rigidbody = hit.rigidbody; + + point = hit.point; + normal = hit.normal; + + traceStart = Vector3.zero; + traceEnd = Vector3.zero; + + direction = Vector3.zero; + + distance = hit.distance; + + this.damage = damage; + + physicMaterial = hit.collider ? hit.collider.sharedMaterial : null; + + blockingHit = true; + startPenetrating = false; + } + } + +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Structs/HitData.cs.meta b/Runtime/Library/SharedScripts/Structs/HitData.cs.meta new file mode 100644 index 00000000..cccc9c2f --- /dev/null +++ b/Runtime/Library/SharedScripts/Structs/HitData.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d33abd97910ff4347bf0d3399d36925c \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Structs/Storage.cs b/Runtime/Library/SharedScripts/Structs/Storage.cs new file mode 100644 index 00000000..ef5142ec --- /dev/null +++ b/Runtime/Library/SharedScripts/Structs/Storage.cs @@ -0,0 +1,178 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + public enum StorageMode + { + [DescriptionEnum("Instantiated uniquely for the owner(self).")] + Exclusive = 0, + + [DescriptionEnum("Shared instance obtained from an FileAsset, SaveSystem, or any other global provider.")] + Shared = 1 + } + [Serializable] + public struct Storage where T : IFile + { + [SerializeField] + private StorageMode Mode; + [Space] + [SerializeField, ConditionalShowByEnum("Mode", StorageMode.Shared)] + private bool UseAsset; + [SerializeField, ConditionalShowByEnum("Mode", StorageMode.Shared), ConditionalHide("UseAsset", true, false)] + private FileAsset FileAsset; + [SerializeField, ConditionalShowByEnum("Mode", StorageMode.Shared), ConditionalHide("UseAsset", true, true), ShowOnly] + private string SelectedMergeFile; + [SerializeField, ConditionalShowByEnum("Mode", StorageMode.Exclusive)] + private bool UseSelf; + [SerializeField, ConditionalShowByEnum("Mode", StorageMode.Exclusive), ConditionalHide("UseSelf", true, true)] + private string FileName; + [SerializeField, ConditionalShowByEnum("Mode", StorageMode.Exclusive), ConditionalHide("UseSelf", true, true)] + private SoftType FileClass; + + + // Private Fields + private UnityEngine.Object _owner; + private T _file; + private IStorageService _saveSystem; + private IFile _mergeFile; + + // Properties + private IStorageService saveSystem + { + get + { + if (_saveSystem == null) + { + _saveSystem = Game.GetService(); + } + return _saveSystem; + } + } + public T File + { + get + { + if (_file == null) + { + Refresh(); + } + + return _file; + } + } + public bool IsExist + { + get + { + return saveSystem.IsExist(_file); + } + } + + // Functions + public void Refresh() + { + if (Mode == StorageMode.Shared) + { + if (UseAsset) + { + if (FileAsset == null) + { + Debug.LogError($"Your FileAsset is not valid"); + _file = default; + } + + if (FileAsset is T provider) + { + _file = provider; + } + else + { + Debug.LogError($"Your FileAsset({FileAsset.name}) Should implement {typeof(T)} interface"); + return; + } + } + else + { + _mergeFile = saveSystem.MainSaveFile; + if (_mergeFile != null) + { + SelectedMergeFile = _mergeFile.Self.GetType().ToString(); + if (_mergeFile is T provider) + { + _file = provider; + } + else + { + Debug.LogError($"Your MergeFile({_mergeFile.Self.GetType()}) Should implement {typeof(T)} interface"); + return; + } + } + else + { + Debug.LogError($"MergeFile in savesystem is not valid"); + return; + } + } + } + else + { + if (UseSelf) + { + if (_owner == null) + { + Debug.LogError($"Your SelfRefrence is not valid [use SetSelf(this) function befor get File]"); + return; + } + + if (_owner is T provider) + { + saveSystem.AddFile(provider); + _file = provider; + } + else + { + Debug.LogError($"Your SelfRefrence({_owner.name}) Should implement {typeof(T)} interface"); + return; + } + } + else + { + object instance = FileClass.Type.CreateInstance(); + if (instance is T provider) + { + if (instance is ISaveFile saveProvider) + { + saveProvider.SetName(FileName); + } + saveSystem.AddFile(provider); + _file = provider; + } + else + { + Debug.LogError($"Your class type({FileClass}) Should implement {typeof(T)} interface"); + return; + } + } + } + + } + public void SetSelf(UnityEngine.Object self) + { + _owner = self; + } + public void Save() + { + saveSystem.Save(_file); + } + public void SetFileName(string NewName) + { + FileName = NewName; + } + public void Clear() + { + Debug.LogWarning("Clear Dint implement! Sorry"); + } + } + +} \ No newline at end of file diff --git a/Runtime/Pattern/Managers/DataManager.cs.meta b/Runtime/Library/SharedScripts/Structs/Storage.cs.meta similarity index 100% rename from Runtime/Pattern/Managers/DataManager.cs.meta rename to Runtime/Library/SharedScripts/Structs/Storage.cs.meta diff --git a/Runtime/Library/SharedScripts/Structs/StyleData.cs b/Runtime/Library/SharedScripts/Structs/StyleData.cs new file mode 100644 index 00000000..fce4feed --- /dev/null +++ b/Runtime/Library/SharedScripts/Structs/StyleData.cs @@ -0,0 +1,94 @@ +#if UNITY_EDITOR || DEVELOPMENT_BUILD +using UnityEngine; +namespace RealMethod +{ + [System.Serializable] + public struct GUIStyleStateData + { + public Texture2D background; + public Color textColor; + + + public void Apply(GUIStyleState state) + { + state.background = background; + state.textColor = textColor; + } + } + + [System.Serializable] + public struct GUIStyleData + { + public Font font; + public int fontSize; + public FontStyle fontStyle; + + public TextAnchor alignment; + public bool wordWrap; + public bool richText; + public bool clipping; + + public Vector2 contentOffset; + + public RectOffset padding; + public RectOffset margin; + public RectOffset border; + public RectOffset overflow; + + public float fixedWidth; + public float fixedHeight; + + public bool stretchWidth; + public bool stretchHeight; + + public GUIStyleStateData normal; + public GUIStyleStateData hover; + public GUIStyleStateData active; + public GUIStyleStateData focused; + + public GUIStyleStateData onNormal; + public GUIStyleStateData onHover; + public GUIStyleStateData onActive; + public GUIStyleStateData onFocused; + + public GUIStyle Build() + { + GUIStyle style = new GUIStyle(); + + style.font = font; + style.fontSize = fontSize; + style.fontStyle = fontStyle; + + style.alignment = alignment; + style.wordWrap = wordWrap; + style.richText = richText; + style.clipping = clipping ? TextClipping.Clip : TextClipping.Overflow; + + style.contentOffset = contentOffset; + + style.padding = padding; + style.margin = margin; + style.border = border; + style.overflow = overflow; + + style.fixedWidth = fixedWidth; + style.fixedHeight = fixedHeight; + + style.stretchWidth = stretchWidth; + style.stretchHeight = stretchHeight; + + normal.Apply(style.normal); + hover.Apply(style.hover); + active.Apply(style.active); + focused.Apply(style.focused); + + onNormal.Apply(style.onNormal); + onHover.Apply(style.onHover); + onActive.Apply(style.onActive); + onFocused.Apply(style.onFocused); + + return style; + } + } +} +#endif \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Structs/StyleData.cs.meta b/Runtime/Library/SharedScripts/Structs/StyleData.cs.meta new file mode 100644 index 00000000..940f8434 --- /dev/null +++ b/Runtime/Library/SharedScripts/Structs/StyleData.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 628530e17d7ff0340bd4e395b9615c2a \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Structs/TransformData.cs b/Runtime/Library/SharedScripts/Structs/TransformData.cs index f541146b..8fdc6a9a 100644 --- a/Runtime/Library/SharedScripts/Structs/TransformData.cs +++ b/Runtime/Library/SharedScripts/Structs/TransformData.cs @@ -14,6 +14,12 @@ public TransformData(Vector3 pos, Quaternion rot, Vector3 scl) rotation = rot; scale = scl; } + public TransformData(Transform comp) + { + position = comp.position; + rotation = comp.rotation; + scale = comp.localScale; + } public static TransformData FromTransform(Transform t) { @@ -241,7 +247,7 @@ public static TransformData Scale(TransformData a, TransformData b, float t, Qua Vector3.Scale(a.scale, new Vector3(q.x, q.y, q.z)) ); } - + } } diff --git a/Runtime/Library/SharedScripts/Structs/UniqueName.cs b/Runtime/Library/SharedScripts/Structs/UniqueName.cs new file mode 100644 index 00000000..c73aa3d4 --- /dev/null +++ b/Runtime/Library/SharedScripts/Structs/UniqueName.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; + +namespace RealMethod +{ + + /// + /// Lightweight engine-style string identifier. + /// Stores only an integer ID while the actual strings live in a global table. + /// + public struct UniqueName : IEquatable + { + /// + /// Maximum allowed characters for a name. + /// + public const int MaxLength = 1024; + /// + /// Internal identifier referencing the global name table. + /// + private int id; + /// + /// Stores strings by ID. + /// + private static readonly List idToName = new List(256); + /// + /// Hash → list of IDs (collision bucket). + /// + private static readonly Dictionary> hashToIds = new Dictionary>(256); + /// + /// Lock for thread-safe name registration. + /// + private static readonly object tableLock = new object(); + + + /// + /// Creates a Name from a string. + /// + public UniqueName(string value) + { + id = GetOrCreateId(value); + } + + + ////////// Static Functions + /// + /// Returns the ID for a string or creates a new one. + /// + public static int GetOrCreateId(string value) + { + if (string.IsNullOrEmpty(value)) + throw new ArgumentException("Name cannot be null or empty."); + + if (value.Length > MaxLength) + throw new ArgumentException($"Name cannot exceed {MaxLength} characters."); + + int hash = value.GetHashCode(); + + lock (tableLock) + { + if (hashToIds.TryGetValue(hash, out var bucket)) + { + for (int i = 0; i < bucket.Count; i++) + { + int existingId = bucket[i]; + + if (idToName[existingId] == value) + return existingId; + } + } + else + { + bucket = new List(2); + hashToIds.Add(hash, bucket); + } + + int newId = idToName.Count; + + idToName.Add(value); + bucket.Add(newId); + + return newId; + } + } + /// + /// Returns the string for an ID. + /// + public static string GetString(int id) + { + if (id < 0 || id >= idToName.Count) + return string.Empty; + + return idToName[id]; + } + + + + ////////// Functions + /// + /// Checks equality with another Name. + /// + public bool Equals(UniqueName other) + { + return id == other.id; + } + + + + + ////////// Overrides + /// + /// Converts Name to string. + /// + public override string ToString() + { + return GetString(id); + } + /// + /// Checks equality with an object. + /// + public override bool Equals(object obj) + { + return obj is UniqueName other && Equals(other); + } + /// + /// Hash code of the Name. + /// + public override int GetHashCode() + { + return id; + } + + + + ////////// Operators + /// + /// Implicit conversion from string. + /// + public static implicit operator UniqueName(string value) + { + return new UniqueName(value); + } + + /// + /// Implicit conversion to string. + /// + public static implicit operator string(UniqueName name) + { + return GetString(name.id); + } + + /// + /// Equality operator. + /// + public static bool operator ==(UniqueName a, UniqueName b) + { + return a.id == b.id; + } + + /// + /// Inequality operator. + /// + public static bool operator !=(UniqueName a, UniqueName b) + { + return a.id != b.id; + } + + } + +} \ No newline at end of file diff --git a/Runtime/Library/SharedScripts/Structs/UniqueName.cs.meta b/Runtime/Library/SharedScripts/Structs/UniqueName.cs.meta new file mode 100644 index 00000000..f7a56cce --- /dev/null +++ b/Runtime/Library/SharedScripts/Structs/UniqueName.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5c9694ddfc582e9428a68603ae6d6332 \ No newline at end of file diff --git a/Runtime/Library/Utilities/AnimationLibrary.cs b/Runtime/Library/Utilities/AnimationLibrary.cs new file mode 100644 index 00000000..ad7b2e15 --- /dev/null +++ b/Runtime/Library/Utilities/AnimationLibrary.cs @@ -0,0 +1,43 @@ +using System.Collections; +using UnityEngine; + +namespace RealMethod +{ + public static class RM_Animation + { + /// + /// Waits until the specified state is entered on an Animator layer, + /// then invokes a callback once the state becomes active. + /// + /// The Animator to monitor. + /// The Animator layer index to check. + /// The name of the state to wait for. + /// Callback invoked when the target state is reached. + /// + /// An that can be used with StartCoroutine(). + /// + /// + /// Useful for sequencing animations without hard‑coded delays. + /// Ensure that the Animator contains the target state on the specified layer. + /// + public static IEnumerator WaitForState(Animator animator, int layer, string stateName, System.Action onFinished) + { + // Wait until we actually enter the state + AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(layer); + while (!info.IsName(stateName)) + { + yield return null; + info = animator.GetCurrentAnimatorStateInfo(layer); + } + + // Now wait until state finishes (non-looping assumption) + while (info.normalizedTime < 1f) + { + yield return null; + info = animator.GetCurrentAnimatorStateInfo(layer); + } + + onFinished?.Invoke(); + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/AnimationLibrary.cs.meta b/Runtime/Library/Utilities/AnimationLibrary.cs.meta new file mode 100644 index 00000000..9e1fedbd --- /dev/null +++ b/Runtime/Library/Utilities/AnimationLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: beb595d1cd67e9247ba2d5076b06d4f9 \ No newline at end of file diff --git a/Runtime/Library/Utilities/ArrayLibrary.cs b/Runtime/Library/Utilities/ArrayLibrary.cs new file mode 100644 index 00000000..16dd0170 --- /dev/null +++ b/Runtime/Library/Utilities/ArrayLibrary.cs @@ -0,0 +1,18 @@ +using System; + +namespace RealMethod +{ + public static class RM_Array + { + public static T[] Append(T[] a, T[] b) + { + if (a == null) return b; + if (b == null) return a; + + T[] result = new T[a.Length + b.Length]; + Array.Copy(a, result, a.Length); + Array.Copy(b, 0, result, a.Length, b.Length); + return result; + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/ArrayLibrary.cs.meta b/Runtime/Library/Utilities/ArrayLibrary.cs.meta new file mode 100644 index 00000000..0f6a9573 --- /dev/null +++ b/Runtime/Library/Utilities/ArrayLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 28c869befe42f604087bb85ebccdccd8 \ No newline at end of file diff --git a/Runtime/Library/Utilities/AudioLibrary.cs b/Runtime/Library/Utilities/AudioLibrary.cs new file mode 100644 index 00000000..9f738748 --- /dev/null +++ b/Runtime/Library/Utilities/AudioLibrary.cs @@ -0,0 +1,37 @@ +using System.Collections; +using UnityEngine; + +namespace RealMethod +{ + public static class RM_Audio + { + public static IEnumerator FadeIn(AudioSource source, float duration) + { + source.Play(); + source.volume = 0f; // Start volume at 0 + float timer = 0f; + while (timer < duration) + { + float t = timer / duration; + source.volume = Mathf.Lerp(0f, 1f, t); + timer += Time.deltaTime; + yield return null; + } + source.volume = 1f; // Ensure volume is set to 1 at the end + } + public static IEnumerator FadeOut(AudioSource source, float duration) + { + source.volume = 1f; // Start volume at 1 + float timer = 0f; + while (timer < duration) + { + float t = timer / duration; + source.volume = Mathf.Lerp(1f, 0f, t); + timer += Time.deltaTime; + yield return null; + } + source.volume = 0f; // Ensure volume is set to 0 at the end + source.Stop(); + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/AudioLibrary.cs.meta b/Runtime/Library/Utilities/AudioLibrary.cs.meta new file mode 100644 index 00000000..d1b083ff --- /dev/null +++ b/Runtime/Library/Utilities/AudioLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bce6038384528304090fe144e937d7d1 \ No newline at end of file diff --git a/Runtime/Library/Utilities/CollectionLibrary.cs b/Runtime/Library/Utilities/CollectionLibrary.cs new file mode 100644 index 00000000..183c659b --- /dev/null +++ b/Runtime/Library/Utilities/CollectionLibrary.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; + +namespace RealMethod +{ + public static class RM_Collection + { + /// + /// Retrieves an element from a collection at the specified index. + /// + /// The type of elements in the collection. + /// The collection of items to retrieve from. + /// The zero-based index of the element to retrieve. + /// + /// The element located at the specified index. + /// + /// + /// Thrown if the index is negative or exceeds the number of elements in the collection. + /// + /// + /// If the provided collection does not support indexed access (), + /// it will be converted to a list internally to allow indexing. + /// + public static T SafeGet(IEnumerable items, int index) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), "Index must be non-negative."); + + // Convert to array or list if you need index access + var itemList = items as IList ?? new List(items); + + if (index >= itemList.Count) + throw new ArgumentOutOfRangeException(nameof(index), "Index exceeds the collection count."); + + return itemList[index]; + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/CollectionLibrary.cs.meta b/Runtime/Library/Utilities/CollectionLibrary.cs.meta new file mode 100644 index 00000000..5ce7d85a --- /dev/null +++ b/Runtime/Library/Utilities/CollectionLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c20cf9a2535c6924ba075d1cf0dae35e \ No newline at end of file diff --git a/Runtime/Library/Utilities/Core.cs b/Runtime/Library/Utilities/Core.cs deleted file mode 100644 index 85b89673..00000000 --- a/Runtime/Library/Utilities/Core.cs +++ /dev/null @@ -1,328 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; - -namespace RealMethod -{ - public static class RM_Core - { - public class input - { - public static bool IsTouchOverUI(GraphicRaycaster HUD_graphicRaycaster, Vector2 touchPosition) - { - // Create a pointer event data from the touch position - PointerEventData pointerEventData = new PointerEventData(null); - pointerEventData.position = touchPosition; - - // Create a list to hold the results - List results = new List(); - - // Raycast using the GraphicRaycaster and pointer event data - HUD_graphicRaycaster.Raycast(pointerEventData, results); - - // Check if we hit any UI elements - return results.Count > 0; - } - } - - public class enumerables - { - public static T GetGameObject(IEnumerable items, int index) - { - if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index), "Index must be non-negative."); - - // Convert to array or list if you need index access - var itemList = items as IList ?? new List(items); - - if (index >= itemList.Count) - throw new ArgumentOutOfRangeException(nameof(index), "Index exceeds the collection count."); - - return itemList[index]; - } - } - - public class file - { - public static bool WriteToFile(string contents, string fullPath) - { - try - { - File.WriteAllText(fullPath, contents); - return true; - } - catch (Exception e) - { - Debug.LogError($"Failed to write to {fullPath} with exception {e}"); - return false; - } - } - public static bool WriteToFile(string contents, string fileName, string ext) - { - var fullPath = Path.Combine(Application.persistentDataPath, fileName + ext); - return WriteToFile(fullPath, contents); - } - - public static bool ReadFromFile(string fullPath, out string result) - { - if (!File.Exists(fullPath)) - { - result = string.Empty; - return false; - } - - try - { - result = File.ReadAllText(fullPath); - return true; - } - catch (Exception e) - { - Debug.LogError($"Failed to read from {fullPath} with exception {e}"); - result = ""; - return false; - } - } - public static bool ReadFromFile(string fileName, string ext, out string result) - { - var fullPath = Path.Combine(Application.persistentDataPath, fileName + ext); - return ReadFromFile(fullPath, out result); - } - - public static bool MoveFile(string fullPath_A, string fullPath_B) - { - try - { - if (File.Exists(fullPath_B)) - { - File.Delete(fullPath_B); - } - - if (!File.Exists(fullPath_A)) - { - return false; - } - - File.Move(fullPath_A, fullPath_B); - } - catch (Exception e) - { - Debug.LogError($"Failed to move file from {fullPath_A} to {fullPath_B} with exception {e}"); - return false; - } - - return true; - } - public static bool MoveFile(string fileName_A, string fileName_B, string ext) - { - var fullPath_A = Path.Combine(Application.persistentDataPath, fileName_A + ext); - var fullPath_B = Path.Combine(Application.persistentDataPath, fileName_B + ext); - return MoveFile(fullPath_A, fullPath_B); - } - } - - public class expression - { - public static string GetVariableName(Expression> expression) - { - if (expression.Body is MemberExpression memberExpression) - { - return memberExpression.Member.Name; - } - throw new ArgumentException("Expression is not a valid member expression."); - } - } - - public class prefs - { - // Boolean - public static void SetBool(string key, bool value) - { - PlayerPrefs.SetInt(key, value ? 1 : 0); - } - public static bool GetBool(string key, bool defaultValue = false) - { - return PlayerPrefs.GetInt(key, defaultValue ? 1 : 0) == 1; - } - - // Vector3 - public static void SetVector3(string key, Vector3 value) - { - PlayerPrefs.SetFloat(key + "_V3x", value.x); - PlayerPrefs.SetFloat(key + "_V3y", value.y); - PlayerPrefs.SetFloat(key + "_V3z", value.z); - } - public static Vector3 GetVector3(string key, Vector3 defaultValue = default) - { - if (!PlayerPrefs.HasKey(key + "_V3x")) return defaultValue; - - float x = PlayerPrefs.GetFloat(key + "_V3x"); - float y = PlayerPrefs.GetFloat(key + "_V3y"); - float z = PlayerPrefs.GetFloat(key + "_V3z"); - return new Vector3(x, y, z); - } - public static bool HasVector3(string key) - { - return PlayerPrefs.HasKey(key + "_V3x"); - } - public static void DeleteVector3(string key) - { - PlayerPrefs.DeleteKey(key + "_V3x"); - PlayerPrefs.DeleteKey(key + "_V3y"); - PlayerPrefs.DeleteKey(key + "_V3z"); - PlayerPrefs.DeleteKey(key + "_V3w"); - } - - // Vector2 - public static void SetVector2(string key, Vector2 value) - { - PlayerPrefs.SetFloat(key + "_V2x", value.x); - PlayerPrefs.SetFloat(key + "_V2y", value.y); - } - public static Vector2 GetVector2(string key, Vector2 defaultValue = default) - { - if (!PlayerPrefs.HasKey(key + "_V2x")) return defaultValue; - - float x = PlayerPrefs.GetFloat(key + "_V2x"); - float y = PlayerPrefs.GetFloat(key + "_V2y"); - return new Vector2(x, y); - } - public static bool HasVector2(string key) - { - return PlayerPrefs.HasKey(key + "_V2x"); - } - public static void DeleteVector2(string key) - { - PlayerPrefs.DeleteKey(key + "_V2x"); - PlayerPrefs.DeleteKey(key + "_V2y"); - PlayerPrefs.DeleteKey(key + "_V2z"); - PlayerPrefs.DeleteKey(key + "_V2w"); - } - - // Quaternion - public static void SetQuaternion(string key, Quaternion value) - { - PlayerPrefs.SetFloat(key + "_Qx", value.x); - PlayerPrefs.SetFloat(key + "_Qy", value.y); - PlayerPrefs.SetFloat(key + "_Qz", value.z); - PlayerPrefs.SetFloat(key + "_Qw", value.w); - } - public static Quaternion GetQuaternion(string key, Quaternion defaultValue = default) - { - if (!PlayerPrefs.HasKey(key + "_Qx")) return defaultValue; - - float x = PlayerPrefs.GetFloat(key + "_Qx"); - float y = PlayerPrefs.GetFloat(key + "_Qy"); - float z = PlayerPrefs.GetFloat(key + "_Qz"); - float w = PlayerPrefs.GetFloat(key + "_Qw"); - return new Quaternion(x, y, z, w); - } - public static bool HasQuaternion(string key) - { - return PlayerPrefs.HasKey(key + "_Qx"); - } - public static void DeleteQuaternion(string key) - { - PlayerPrefs.DeleteKey(key + "_Qx"); - PlayerPrefs.DeleteKey(key + "_Qy"); - PlayerPrefs.DeleteKey(key + "_Qz"); - PlayerPrefs.DeleteKey(key + "_Qw"); - } - - // Transform - public static void SetTransform(string key, Transform transform, bool includeScale = false) - { - // Save Position - PlayerPrefs.SetFloat(key + "_pos_x", transform.position.x); - PlayerPrefs.SetFloat(key + "_pos_y", transform.position.y); - PlayerPrefs.SetFloat(key + "_pos_z", transform.position.z); - - // Save Rotation - PlayerPrefs.SetFloat(key + "_rot_x", transform.rotation.x); - PlayerPrefs.SetFloat(key + "_rot_y", transform.rotation.y); - PlayerPrefs.SetFloat(key + "_rot_z", transform.rotation.z); - PlayerPrefs.SetFloat(key + "_rot_w", transform.rotation.w); - - if (includeScale) - { - PlayerPrefs.SetFloat(key + "_scale_x", transform.localScale.x); - PlayerPrefs.SetFloat(key + "_scale_y", transform.localScale.y); - PlayerPrefs.SetFloat(key + "_scale_z", transform.localScale.z); - } - - PlayerPrefs.Save(); - } - public static void GetTransform(string key, Transform transform, bool includeScale = false) - { - if (!PlayerPrefs.HasKey(key + "_pos_x")) return; // check if saved - - // Load Position - float px = PlayerPrefs.GetFloat(key + "_pos_x"); - float py = PlayerPrefs.GetFloat(key + "_pos_y"); - float pz = PlayerPrefs.GetFloat(key + "_pos_z"); - - // Load Rotation - float rx = PlayerPrefs.GetFloat(key + "_rot_x"); - float ry = PlayerPrefs.GetFloat(key + "_rot_y"); - float rz = PlayerPrefs.GetFloat(key + "_rot_z"); - float rw = PlayerPrefs.GetFloat(key + "_rot_w"); - - transform.position = new Vector3(px, py, pz); - transform.rotation = new Quaternion(rx, ry, rz, rw); - - if (includeScale && PlayerPrefs.HasKey(key + "_scale_x")) - { - float sx = PlayerPrefs.GetFloat(key + "_scale_x"); - float sy = PlayerPrefs.GetFloat(key + "_scale_y"); - float sz = PlayerPrefs.GetFloat(key + "_scale_z"); - transform.localScale = new Vector3(sx, sy, sz); - } - } - public static bool HasTransform(string key) - { - return PlayerPrefs.HasKey(key + "_pos_x"); - } - public static void DeleteTransform(string key) - { - string[] suffixes = { - "_pos_x", "_pos_y", "_pos_z", - "_rot_x", "_rot_y", "_rot_z", "_rot_w", - "_scale_x", "_scale_y", "_scale_z" - }; - - foreach (var suffix in suffixes) - { - PlayerPrefs.DeleteKey(key + suffix); - } - } - - // Array - public static void SetArray(string key, T[] array) - { - string joined = string.Join("|", array); // Use a delimiter unlikely to appear in your strings - PlayerPrefs.SetString(key, joined); - PlayerPrefs.Save(); - } - public static T[] GetArray(string key) - { - if (!PlayerPrefs.HasKey(key)) return new T[0]; - - string joined = PlayerPrefs.GetString(key); - return joined.Split('|').Select(s => (T)System.Convert.ChangeType(s, typeof(T))).ToArray(); // Convert each string to T - } - } - - public class enume - { - public static bool AreEnumValuesEqual(T a, J b) where T : Enum where J : Enum - { - return Convert.ToInt32(a) == Convert.ToInt32(b); - } - } - } -} \ No newline at end of file diff --git a/Runtime/Library/Utilities/Core.cs.meta b/Runtime/Library/Utilities/Core.cs.meta deleted file mode 100644 index a43f0f85..00000000 --- a/Runtime/Library/Utilities/Core.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 6137ed14b90bee8439505d9a15df4c34 \ No newline at end of file diff --git a/Runtime/Library/Utilities/Coroutine.cs b/Runtime/Library/Utilities/Coroutine.cs deleted file mode 100644 index 24be9aa0..00000000 --- a/Runtime/Library/Utilities/Coroutine.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System.Collections; -using UnityEngine; - -namespace RealMethod -{ - public static class RM_Coroutine - { - private class CoroutineHandeler - { - public bool IsDone { get; private set; } - - public IEnumerator Run(IEnumerator coroutine) - { - yield return coroutine; - IsDone = true; - } - } - - - public static IEnumerator Delay(float duration, System.Action callback) - { - yield return new WaitForSeconds(duration); - callback?.Invoke(); - } - public static IEnumerator WaitUntil(System.Func condition, System.Action callback) - { - yield return new WaitUntil(condition); - callback?.Invoke(); - } - public static IEnumerator WaitWhile(System.Func condition, System.Action callback) - { - yield return new WaitWhile(condition); - callback?.Invoke(); - } - public static IEnumerator MoveTo(Transform target, Vector3 end, float duration) - { - Vector3 start = target.position; - float t = 0f; - while (t < duration) - { - t += Time.deltaTime; - target.position = Vector3.Lerp(start, end, t / duration); - yield return null; - } - target.position = end; - } - public static IEnumerator FadeCanvas(CanvasGroup canvas, float targetAlpha, float duration) - { - float start = canvas.alpha; - float t = 0f; - while (t < duration) - { - t += Time.deltaTime; - canvas.alpha = Mathf.Lerp(start, targetAlpha, t / duration); - yield return null; - } - canvas.alpha = targetAlpha; - } - public static IEnumerator ScaleTo(Transform target, Vector3 targetScale, float duration) - { - Vector3 start = target.localScale; - float t = 0f; - while (t < duration) - { - t += Time.deltaTime; - target.localScale = Vector3.Lerp(start, targetScale, t / duration); - yield return null; - } - target.localScale = targetScale; - } - public static IEnumerator RotateTo(Transform target, Quaternion targetRot, float duration) - { - Quaternion start = target.rotation; - float t = 0f; - while (t < duration) - { - t += Time.deltaTime; - target.rotation = Quaternion.Slerp(start, targetRot, t / duration); - yield return null; - } - target.rotation = targetRot; - } - public static IEnumerator Repeat(System.Action action, float interval, int count = -1) - { - int i = 0; - while (count < 0 || i < count) - { - action?.Invoke(); - i++; - yield return new WaitForSeconds(interval); - } - } - public static IEnumerator WaitForCoroutine(MonoBehaviour Owner, IEnumerator coroutine) - { - CoroutineHandeler handle = new CoroutineHandeler(); - yield return Owner.StartCoroutine(handle.Run(coroutine)); - } - public static IEnumerator DelayOneFrame(System.Action callback) - { - yield return new WaitForEndOfFrame(); - callback?.Invoke(); - } - public static IEnumerator WaitForState(Animator animator, int layer, string stateName, System.Action onFinished) - { - // Wait until we actually enter the state - AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(layer); - while (!info.IsName(stateName)) - { - yield return null; - info = animator.GetCurrentAnimatorStateInfo(layer); - } - - // Now wait until state finishes (non-looping assumption) - while (info.normalizedTime < 1f) - { - yield return null; - info = animator.GetCurrentAnimatorStateInfo(layer); - } - - onFinished?.Invoke(); - } - } - -} \ No newline at end of file diff --git a/Runtime/Library/Utilities/Coroutine.cs.meta b/Runtime/Library/Utilities/Coroutine.cs.meta deleted file mode 100644 index 5a0eb7dd..00000000 --- a/Runtime/Library/Utilities/Coroutine.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 52e4b7690bd97e7438fd5adb46d2d1c1 \ No newline at end of file diff --git a/Runtime/Library/Utilities/DebugLibrary.cs b/Runtime/Library/Utilities/DebugLibrary.cs new file mode 100644 index 00000000..b9e2f324 --- /dev/null +++ b/Runtime/Library/Utilities/DebugLibrary.cs @@ -0,0 +1,29 @@ +using UnityEngine; + +namespace RealMethod +{ + public static class RM_Debug + { + // Draws a directional arrow using Debug.DrawRay (no color) + public static void Arrow(Vector3 position, Vector3 direction, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20.0f) + { + Debug.DrawRay(position, direction); + + Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * Vector3.forward; + Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * Vector3.forward; + Debug.DrawRay(position + direction, right * arrowHeadLength); + Debug.DrawRay(position + direction, left * arrowHeadLength); + } + // Draws a directional arrow using Debug.DrawRay (with color) + public static void Arrow(Vector3 position, Vector3 direction, Color color, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20.0f) + { + Debug.DrawRay(position, direction, color); + + Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * Vector3.forward; + Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * Vector3.forward; + Debug.DrawRay(position + direction, right * arrowHeadLength, color); + Debug.DrawRay(position + direction, left * arrowHeadLength, color); + } + } + +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/DebugLibrary.cs.meta b/Runtime/Library/Utilities/DebugLibrary.cs.meta new file mode 100644 index 00000000..c1ba93b5 --- /dev/null +++ b/Runtime/Library/Utilities/DebugLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a01a052ef371a7f4ea8276a4c54c103a \ No newline at end of file diff --git a/Runtime/Library/Utilities/Draw.cs b/Runtime/Library/Utilities/Draw.cs deleted file mode 100644 index e717172a..00000000 --- a/Runtime/Library/Utilities/Draw.cs +++ /dev/null @@ -1,64 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public static class RM_Draw - { - public class gizmos - { - public static void DrawCurve(AnimationCurve curve) - { - for (float t = 0; t < curve.keys[curve.length - 1].time; t += 0.1f) - { - Gizmos.DrawSphere(new Vector3(t, curve.Evaluate(t), 0), 0.1f); - } - } - // Draws a directional arrow using Gizmos (no color) - public static void DrawArrow(Vector3 position, Vector3 direction, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20.0f) - { - Gizmos.DrawRay(position, direction); - - Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * Vector3.forward; - Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * Vector3.forward; - Gizmos.DrawRay(position + direction, right * arrowHeadLength); - Gizmos.DrawRay(position + direction, left * arrowHeadLength); - } - // Draws a directional arrow using Gizmos (with color) - public static void DrawArrow(Vector3 position, Vector3 direction, Color color, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20.0f) - { - Gizmos.color = color; - Gizmos.DrawRay(position, direction); - - Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * Vector3.forward; - Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * Vector3.forward; - Gizmos.DrawRay(position + direction, right * arrowHeadLength); - Gizmos.DrawRay(position + direction, left * arrowHeadLength); - } - } - - public class debug - { - // Draws a directional arrow using Debug.DrawRay (no color) - public static void DrawArrow(Vector3 position, Vector3 direction, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20.0f) - { - Debug.DrawRay(position, direction); - - Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * Vector3.forward; - Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * Vector3.forward; - Debug.DrawRay(position + direction, right * arrowHeadLength); - Debug.DrawRay(position + direction, left * arrowHeadLength); - } - // Draws a directional arrow using Debug.DrawRay (with color) - public static void DrawArrow(Vector3 position, Vector3 direction, Color color, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20.0f) - { - Debug.DrawRay(position, direction, color); - - Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * Vector3.forward; - Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * Vector3.forward; - Debug.DrawRay(position + direction, right * arrowHeadLength, color); - Debug.DrawRay(position + direction, left * arrowHeadLength, color); - } - } - - } -} \ No newline at end of file diff --git a/Runtime/Library/Utilities/Draw.cs.meta b/Runtime/Library/Utilities/Draw.cs.meta deleted file mode 100644 index 55198b34..00000000 --- a/Runtime/Library/Utilities/Draw.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 17e9ab77f56e0034cb688c9aa2ba5b61 \ No newline at end of file diff --git a/Runtime/Library/Utilities/EnumLibrary.cs b/Runtime/Library/Utilities/EnumLibrary.cs new file mode 100644 index 00000000..75a90142 --- /dev/null +++ b/Runtime/Library/Utilities/EnumLibrary.cs @@ -0,0 +1,27 @@ +using System; + +namespace RealMethod +{ + public static class RM_Enum + { + /// + /// Compares two enum values, even if they are of different enum types, + /// by comparing their underlying numeric values. + /// + /// The type of the first enum. + /// The type of the second enum. + /// The first enum value. + /// The second enum value. + /// + /// True if both enum values have the same underlying numeric value; otherwise false. + /// + /// + /// Useful when working with different enum types that share the same value mapping. + /// + + public static bool AreEnumValuesEqual(T a, J b) where T : Enum where J : Enum + { + return Convert.ToInt32(a) == Convert.ToInt32(b); + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/EnumLibrary.cs.meta b/Runtime/Library/Utilities/EnumLibrary.cs.meta new file mode 100644 index 00000000..527f8be4 --- /dev/null +++ b/Runtime/Library/Utilities/EnumLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e5ffbf87db9a03e44918bc47cd961028 \ No newline at end of file diff --git a/Runtime/Library/Utilities/FileLibrary.cs b/Runtime/Library/Utilities/FileLibrary.cs new file mode 100644 index 00000000..7549f276 --- /dev/null +++ b/Runtime/Library/Utilities/FileLibrary.cs @@ -0,0 +1,85 @@ +using System; +using System.IO; +using UnityEngine; + +namespace RealMethod +{ + public static class RM_File + { + public static bool WriteToFile(string contents, string fullPath) + { + try + { + File.WriteAllText(fullPath, contents); + return true; + } + catch (Exception e) + { + Debug.LogError($"Failed to write to {fullPath} with exception {e}"); + return false; + } + } + public static bool WriteToFile(string contents, string fileName, string ext) + { + var fullPath = Path.Combine(Application.persistentDataPath, fileName + ext); + return WriteToFile(fullPath, contents); + } + + public static bool ReadFromFile(string fullPath, out string result) + { + if (!File.Exists(fullPath)) + { + result = string.Empty; + return false; + } + + try + { + result = File.ReadAllText(fullPath); + return true; + } + catch (Exception e) + { + Debug.LogError($"Failed to read from {fullPath} with exception {e}"); + result = ""; + return false; + } + } + public static bool ReadFromFile(string fileName, string ext, out string result) + { + var fullPath = Path.Combine(Application.persistentDataPath, fileName + ext); + return ReadFromFile(fullPath, out result); + } + + public static bool MoveFile(string fullPath_A, string fullPath_B) + { + try + { + if (File.Exists(fullPath_B)) + { + File.Delete(fullPath_B); + } + + if (!File.Exists(fullPath_A)) + { + return false; + } + + File.Move(fullPath_A, fullPath_B); + } + catch (Exception e) + { + Debug.LogError($"Failed to move file from {fullPath_A} to {fullPath_B} with exception {e}"); + return false; + } + + return true; + } + public static bool MoveFile(string fileName_A, string fileName_B, string ext) + { + var fullPath_A = Path.Combine(Application.persistentDataPath, fileName_A + ext); + var fullPath_B = Path.Combine(Application.persistentDataPath, fileName_B + ext); + return MoveFile(fullPath_A, fullPath_B); + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/FileLibrary.cs.meta b/Runtime/Library/Utilities/FileLibrary.cs.meta new file mode 100644 index 00000000..c12d39a4 --- /dev/null +++ b/Runtime/Library/Utilities/FileLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ff2fdeb8f4eb4e642a4b90da35765dc4 \ No newline at end of file diff --git a/Runtime/Library/Utilities/GUILibrary.cs b/Runtime/Library/Utilities/GUILibrary.cs new file mode 100644 index 00000000..e7577f65 --- /dev/null +++ b/Runtime/Library/Utilities/GUILibrary.cs @@ -0,0 +1,67 @@ +#if UNITY_EDITOR || DEVELOPMENT_BUILD +using UnityEngine; + +namespace RealMethod +{ + public static class RM_GUI + { + public static Rect GetButtonRect(Dir9 corner, float width, float height, float margin = 10f) + { + float x = 0; + float y = 0; + + switch (corner) + { + case Dir9.UpLeft: + x = margin; + y = margin; + break; + + case Dir9.Up: + x = (Screen.width - width) * 0.5f; + y = margin; + break; + + case Dir9.UpRight: + x = Screen.width - width - margin; + y = margin; + break; + + case Dir9.Left: + x = margin; + y = (Screen.height - height) * 0.5f; + break; + + case Dir9.Right: + x = Screen.width - width - margin; + y = (Screen.height - height) * 0.5f; + break; + + case Dir9.DownLeft: + x = margin; + y = Screen.height - height - margin; + break; + + case Dir9.Down: + x = (Screen.width - width) * 0.5f; + y = Screen.height - height - margin; + break; + + case Dir9.DownRight: + x = Screen.width - width - margin; + y = Screen.height - height - margin; + break; + + case Dir9.Center: + x = (Screen.width - width) * 0.5f; + y = (Screen.height - height) * 0.5f; + break; + } + + return new Rect(x, y, width, height); + } + + } + +} +#endif \ No newline at end of file diff --git a/Runtime/Library/Utilities/GUILibrary.cs.meta b/Runtime/Library/Utilities/GUILibrary.cs.meta new file mode 100644 index 00000000..6495254d --- /dev/null +++ b/Runtime/Library/Utilities/GUILibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cb062f936e2190e4eb17ab7cbb030eaf \ No newline at end of file diff --git a/Runtime/Library/Utilities/Geometry.cs b/Runtime/Library/Utilities/Geometry.cs deleted file mode 100644 index 6f412df8..00000000 --- a/Runtime/Library/Utilities/Geometry.cs +++ /dev/null @@ -1,37 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public static class RM_Geometry - { - public class Space - { - public static Vector3 GetWorldPositionFromRelative(Transform from, Vector3 relativePos) - { - return from.TransformPoint(relativePos); - } - public static Vector3 GetRelativePosition(Transform from, Transform to) - { - return from.InverseTransformPoint(to.position); - } - } - public class Plane - { - public static bool IsVectorAlignedWithVector(Vector2 vectorA, Vector2 vectorB, float tolerance) - { - float angle = Vector2.Angle(vectorA.normalized, vectorB.normalized); - if (angle <= tolerance) return true; - - return false; - } - } - public class Angle - { - - } - public class Point - { - - } - } -} \ No newline at end of file diff --git a/Runtime/Library/Utilities/Geometry.cs.meta b/Runtime/Library/Utilities/Geometry.cs.meta deleted file mode 100644 index e5d62b42..00000000 --- a/Runtime/Library/Utilities/Geometry.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 335396769639eec4a909baf07dd159e9 \ No newline at end of file diff --git a/Runtime/Library/Utilities/GizmosLibrary.cs b/Runtime/Library/Utilities/GizmosLibrary.cs new file mode 100644 index 00000000..58038dd9 --- /dev/null +++ b/Runtime/Library/Utilities/GizmosLibrary.cs @@ -0,0 +1,103 @@ +#if UNITY_EDITOR +using UnityEngine; +using UnityEditor; + +namespace RealMethod +{ + public static class RM_Gizmos + { + public static void Curve(AnimationCurve curve) + { + for (float t = 0; t < curve.keys[curve.length - 1].time; t += 0.1f) + { + Gizmos.DrawSphere(new Vector3(t, curve.Evaluate(t), 0), 0.1f); + } + } + /// + /// Draws a directional arrow in the scene for debugging or visualization. + /// + /// The starting position of the arrow. + /// The direction the arrow points to. + /// Length of the arrow head. + /// Angle of the arrow head in degrees. + /// + /// Typically used for debugging directions, forces, or movement in the Scene view. + /// Implementation may use Debug.DrawLine or Gizmos. + /// + public static void Arrow(Vector3 position, Vector3 direction, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20.0f) + { + Gizmos.DrawRay(position, direction); + + Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * Vector3.forward; + Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * Vector3.forward; + Gizmos.DrawRay(position + direction, right * arrowHeadLength); + Gizmos.DrawRay(position + direction, left * arrowHeadLength); + } + // Draws a directional arrow using Gizmos (with color) + public static void Arrow(Vector3 position, Vector3 direction, Color color, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20.0f) + { + Gizmos.color = color; + Gizmos.DrawRay(position, direction); + + Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * Vector3.forward; + Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * Vector3.forward; + Gizmos.DrawRay(position + direction, right * arrowHeadLength); + Gizmos.DrawRay(position + direction, left * arrowHeadLength); + } + // Draws a Capsule using Gizmos (no color) + public static void Capsule(Vector3 position, float height = 2f, float radius = 0.5f) + { + // Draw top sphere + Vector3 top = position + Vector3.up * (height / 2 - radius); + Gizmos.DrawWireSphere(top, radius); + + // Draw bottom sphere + Vector3 bottom = position + Vector3.down * (height / 2 - radius); + Gizmos.DrawWireSphere(bottom, radius); + + // Draw cylinder (approximation) + Gizmos.DrawLine(top + Vector3.forward * radius, bottom + Vector3.forward * radius); + Gizmos.DrawLine(top - Vector3.forward * radius, bottom - Vector3.forward * radius); + Gizmos.DrawLine(top + Vector3.right * radius, bottom + Vector3.right * radius); + Gizmos.DrawLine(top - Vector3.right * radius, bottom - Vector3.right * radius); + } + // Draws a Capsule using Gizmos (with color) + public static void Capsule(Vector3 position, Color color, float height = 2f, float radius = 0.5f) + { + // Save previous Gizmos color + Color prevColor = Gizmos.color; + Gizmos.color = color; + + // Draw top sphere + Vector3 top = position + Vector3.up * (height / 2 - radius); + Gizmos.DrawWireSphere(top, radius); + + // Draw bottom sphere + Vector3 bottom = position + Vector3.down * (height / 2 - radius); + Gizmos.DrawWireSphere(bottom, radius); + + // Draw cylinder (approximation) + Gizmos.DrawLine(top + Vector3.forward * radius, bottom + Vector3.forward * radius); + Gizmos.DrawLine(top - Vector3.forward * radius, bottom - Vector3.forward * radius); + Gizmos.DrawLine(top + Vector3.right * radius, bottom + Vector3.right * radius); + Gizmos.DrawLine(top - Vector3.right * radius, bottom - Vector3.right * radius); + + // Restore previous color + Gizmos.color = prevColor; + } + + // Draw a Text using Gizmos (With Colort) + public static void Text(string text, Vector3 position, Color color, FontStyle font = FontStyle.Bold, TextAnchor ancher = TextAnchor.MiddleCenter) + { + // Set color + GUIStyle style = new GUIStyle(); + style.normal.textColor = color; + style.alignment = ancher; + style.fontStyle = font; + + // Draw the label above the GameObject + Handles.Label(position, text, style); + } + } +} +#endif \ No newline at end of file diff --git a/Runtime/Library/Utilities/GizmosLibrary.cs.meta b/Runtime/Library/Utilities/GizmosLibrary.cs.meta new file mode 100644 index 00000000..80104ace --- /dev/null +++ b/Runtime/Library/Utilities/GizmosLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c891057bb2667044b994087f418ec1b1 \ No newline at end of file diff --git a/Runtime/Library/Utilities/Math.cs b/Runtime/Library/Utilities/Math.cs deleted file mode 100644 index aa92e9d0..00000000 --- a/Runtime/Library/Utilities/Math.cs +++ /dev/null @@ -1,162 +0,0 @@ -using UnityEngine; - - -namespace RealMethod -{ - public static class RM_Math - { - public static Vector3 TwoD => new Vector3(1, 0, 1); - - public class Map - { - /// - /// Maps a float value from one range to another and clamps the result to the output range. - /// - /// The input value to map. - /// Minimum of the input range. - /// Maximum of the input range. - /// Minimum of the output range. - /// Maximum of the output range. - /// Mapped and clamped float value. - public static float RemapClamped(float value, float inMin, float inMax, float outMin, float outMax) - { - // Prevent divide by zero - if (Mathf.Approximately(inMax, inMin)) - { - Debug.LogWarning("Input range is zero. Returning outMin."); - return outMin; - } - - // Normalize the input value to 0–1 within the input range - float t = (value - inMin) / (inMax - inMin); - - // Scale and offset to target range - float mappedValue = t * (outMax - outMin) + outMin; - - // Clamp result to the output range - return Mathf.Clamp(mappedValue, Mathf.Min(outMin, outMax), Mathf.Max(outMin, outMax)); - } - /// - /// Determines whether a value is within a specified range, with control over boundary inclusivity. - /// - /// The value to check. - /// The lower bound of the range. - /// The upper bound of the range. - /// Whether the lower bound is inclusive (>=). - /// Whether the upper bound is inclusive (<=). - /// True if the value is within the range; otherwise, false. - public static bool IsInRange(float value, float min, float max, bool inclusiveMin = true, bool inclusiveMax = true) - { - bool isAboveMin = inclusiveMin ? value >= min : value > min; - bool isBelowMax = inclusiveMax ? value <= max : value < max; - - return isAboveMin && isBelowMax; - } - } - - public class Interpolate - { - /// - /// Interpolates a value from Current to Target, applying a given speed over DeltaTime. - /// Mimics Unreal Engine's FInterpTo function. - /// - /// The current value. - /// The target value. - /// The time step to apply the interpolation. - /// The interpolation speed. - /// The interpolated value. - public static float FInterpTo(float current, float target, float deltaTime, float interpSpeed) - { - if (interpSpeed <= 0f || Mathf.Approximately(current, target)) - { - return target; // If speed is zero or already at the target, no interpolation needed - } - - float delta = target - current; // Difference between current and target - float step = delta * Mathf.Clamp01(interpSpeed * deltaTime); // Calculate interpolation step - - return current + step; // Move the current value closer to the target - } - /// - /// Interpolates a value from Current to Target at a constant speed over DeltaTime. - /// Mimics Unreal Engine's FInterpToConstant function. - /// - /// The current value. - /// The target value. - /// The time step to apply the interpolation. - /// The constant speed of interpolation. - /// The interpolated value. - public static float FInterpToConstant(float current, float target, float deltaTime, float interpSpeed) - { - if (interpSpeed <= 0f || Mathf.Approximately(current, target)) - { - return target; // If speed is zero or already at the target, no interpolation needed - } - - // Calculate the step size for this frame - float step = interpSpeed * deltaTime; - - // Move towards the target by the step size, clamped to not overshoot - if (Mathf.Abs(target - current) <= step) - { - return target; // If within one step, snap to target - } - - // Move towards the target - return current + Mathf.Sign(target - current) * step; - } - public static Vector3 VInterpTo(Vector3 current, Vector3 target, float deltaTime, float interpSpeed) - { - if (interpSpeed <= 0f || current == target) - { - return target; // If speed is zero or already at the target, no interpolation needed - } - - // Interpolate towards the target - return Vector3.Lerp(current, target, Mathf.Clamp01(interpSpeed * deltaTime)); - } - public static Vector3 VInterpToConstant(Vector3 current, Vector3 target, float deltaTime, float interpSpeed) - { - if (interpSpeed <= 0f || current == target) - { - return target; // If speed is zero or already at the target, no interpolation needed - } - - // Calculate the step size - Vector3 direction = (target - current).normalized; - float distance = Vector3.Distance(current, target); - float step = interpSpeed * deltaTime; - - // Move towards the target by the step size, clamped to not overshoot - return distance <= step ? target : current + direction * step; - } - public static Quaternion RInterpTo(Quaternion current, Quaternion target, float deltaTime, float interpSpeed) - { - if (interpSpeed <= 0f || current == target) - { - return target; // If speed is zero or already at the target, no interpolation needed - } - - // Interpolate towards the target - return Quaternion.Slerp(current, target, Mathf.Clamp01(interpSpeed * deltaTime)); - } - public static Quaternion RInterpToConstant(Quaternion current, Quaternion target, float deltaTime, float interpSpeed) - { - if (interpSpeed <= 0f || current == target) - { - return target; // If speed is zero or already at the target, no interpolation needed - } - - // Calculate the step size - float angle = Quaternion.Angle(current, target); - float step = interpSpeed * deltaTime; - - // Rotate towards the target by the step size, clamped to not overshoot - return angle <= step ? target : Quaternion.RotateTowards(current, target, step); - } - - } - - } - -} diff --git a/Runtime/Library/Utilities/MathLibrary.cs b/Runtime/Library/Utilities/MathLibrary.cs new file mode 100644 index 00000000..41641f24 --- /dev/null +++ b/Runtime/Library/Utilities/MathLibrary.cs @@ -0,0 +1,154 @@ +using UnityEngine; + + +namespace RealMethod +{ + public static class RM_Math + { + public static Vector3 TwoD => new Vector3(1, 0, 1); + + /// + /// Maps a float value from one range to another and clamps the result to the output range. + /// + /// The input value to map. + /// Minimum of the input range. + /// Maximum of the input range. + /// Minimum of the output range. + /// Maximum of the output range. + /// Mapped and clamped float value. + public static float RemapClamped(float value, float inMin, float inMax, float outMin, float outMax) + { + // Prevent divide by zero + if (Mathf.Approximately(inMax, inMin)) + { + Debug.LogWarning("Input range is zero. Returning outMin."); + return outMin; + } + + // Normalize the input value to 0–1 within the input range + float t = (value - inMin) / (inMax - inMin); + + // Scale and offset to target range + float mappedValue = t * (outMax - outMin) + outMin; + + // Clamp result to the output range + return Mathf.Clamp(mappedValue, Mathf.Min(outMin, outMax), Mathf.Max(outMin, outMax)); + } + /// + /// Determines whether a value is within a specified range, with control over boundary inclusivity. + /// + /// The value to check. + /// The lower bound of the range. + /// The upper bound of the range. + /// Whether the lower bound is inclusive (>=). + /// Whether the upper bound is inclusive (<=). + /// True if the value is within the range; otherwise, false. + public static bool IsInRange(float value, float min, float max, bool inclusiveMin = true, bool inclusiveMax = true) + { + bool isAboveMin = inclusiveMin ? value >= min : value > min; + bool isBelowMax = inclusiveMax ? value <= max : value < max; + + return isAboveMin && isBelowMax; + } + /// + /// Interpolates a value from Current to Target, applying a given speed over DeltaTime. + /// Mimics Unreal Engine's FInterpTo function. + /// + /// The current value. + /// The target value. + /// The time step to apply the interpolation. + /// The interpolation speed. + /// The interpolated value. + public static float FInterpTo(float current, float target, float deltaTime, float interpSpeed) + { + if (interpSpeed <= 0f || Mathf.Approximately(current, target)) + { + return target; // If speed is zero or already at the target, no interpolation needed + } + + float delta = target - current; // Difference between current and target + float step = delta * Mathf.Clamp01(interpSpeed * deltaTime); // Calculate interpolation step + + return current + step; // Move the current value closer to the target + } + /// + /// Interpolates a value from Current to Target at a constant speed over DeltaTime. + /// Mimics Unreal Engine's FInterpToConstant function. + /// + /// The current value. + /// The target value. + /// The time step to apply the interpolation. + /// The constant speed of interpolation. + /// The interpolated value. + public static float FInterpToConstant(float current, float target, float deltaTime, float interpSpeed) + { + if (interpSpeed <= 0f || Mathf.Approximately(current, target)) + { + return target; // If speed is zero or already at the target, no interpolation needed + } + + // Calculate the step size for this frame + float step = interpSpeed * deltaTime; + + // Move towards the target by the step size, clamped to not overshoot + if (Mathf.Abs(target - current) <= step) + { + return target; // If within one step, snap to target + } + + // Move towards the target + return current + Mathf.Sign(target - current) * step; + } + public static Vector3 VInterpTo(Vector3 current, Vector3 target, float deltaTime, float interpSpeed) + { + if (interpSpeed <= 0f || current == target) + { + return target; // If speed is zero or already at the target, no interpolation needed + } + + // Interpolate towards the target + return Vector3.Lerp(current, target, Mathf.Clamp01(interpSpeed * deltaTime)); + } + public static Vector3 VInterpToConstant(Vector3 current, Vector3 target, float deltaTime, float interpSpeed) + { + if (interpSpeed <= 0f || current == target) + { + return target; // If speed is zero or already at the target, no interpolation needed + } + + // Calculate the step size + Vector3 direction = (target - current).normalized; + float distance = Vector3.Distance(current, target); + float step = interpSpeed * deltaTime; + + // Move towards the target by the step size, clamped to not overshoot + return distance <= step ? target : current + direction * step; + } + public static Quaternion RInterpTo(Quaternion current, Quaternion target, float deltaTime, float interpSpeed) + { + if (interpSpeed <= 0f || current == target) + { + return target; // If speed is zero or already at the target, no interpolation needed + } + + // Interpolate towards the target + return Quaternion.Slerp(current, target, Mathf.Clamp01(interpSpeed * deltaTime)); + } + public static Quaternion RInterpToConstant(Quaternion current, Quaternion target, float deltaTime, float interpSpeed) + { + if (interpSpeed <= 0f || current == target) + { + return target; // If speed is zero or already at the target, no interpolation needed + } + + // Calculate the step size + float angle = Quaternion.Angle(current, target); + float step = interpSpeed * deltaTime; + + // Rotate towards the target by the step size, clamped to not overshoot + return angle <= step ? target : Quaternion.RotateTowards(current, target, step); + } + + } + +} diff --git a/Runtime/Library/Utilities/Math.cs.meta b/Runtime/Library/Utilities/MathLibrary.cs.meta similarity index 100% rename from Runtime/Library/Utilities/Math.cs.meta rename to Runtime/Library/Utilities/MathLibrary.cs.meta diff --git a/Runtime/Library/Utilities/Physics.cs b/Runtime/Library/Utilities/Physics.cs deleted file mode 100644 index 65afde96..00000000 --- a/Runtime/Library/Utilities/Physics.cs +++ /dev/null @@ -1,51 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public static class RM_Physics - { - public class Trace - { - public static bool Line(Vector3 Start, Vector3 Direction, float Length, LayerMask Layer, QueryTriggerInteraction TriggerInteraction, Color RayColor, Color HitColor, out RaycastHit HitResult) - { - bool Result; - Result = Physics.Raycast(Start, Direction, out HitResult, Length, Layer, TriggerInteraction); - float debuglength = HitResult.collider ? HitResult.distance : Length; - Color debugcolor = HitResult.collider ? HitColor : RayColor; - Debug.DrawRay(Start, Direction * debuglength, debugcolor); - return Result; - } - - public static bool Line(Vector3 Start, Vector3 Direction, float Length, LayerMask Layer, QueryTriggerInteraction TriggerInteraction, out RaycastHit HitResult) - { - bool Result; - Result = Physics.Raycast(Start, Direction, out HitResult, Length, Layer, TriggerInteraction); - float debuglength = HitResult.collider ? HitResult.distance : Length; - Color debugcolor = HitResult.collider ? Color.green : Color.red; - Debug.DrawRay(Start, Direction * debuglength, debugcolor); - return Result; - } - - public static bool Line(Vector3 Start, Vector3 Direction, float Length, LayerMask Layer, out RaycastHit HitResult) - { - bool Result; - Result = Physics.Raycast(Start, Direction, out HitResult, Length, Layer); - float debuglength = HitResult.collider ? HitResult.distance : Length; - Color debugcolor = HitResult.collider ? Color.green : Color.red; - Debug.DrawRay(Start, Direction * debuglength, debugcolor); - return Result; - } - - public static bool Line(Vector3 Start, Vector3 Direction, float Length, out RaycastHit HitResult) - { - bool Result; - Result = Physics.Raycast(Start, Direction, out HitResult, Length); - float debuglength = HitResult.collider ? HitResult.distance : Length; - Color debugcolor = HitResult.collider ? Color.green : Color.red; - Debug.DrawRay(Start, Direction * debuglength, debugcolor); - return Result; - } - } - - } -} \ No newline at end of file diff --git a/Runtime/Library/Utilities/Physics.cs.meta b/Runtime/Library/Utilities/Physics.cs.meta deleted file mode 100644 index 6f6ba36e..00000000 --- a/Runtime/Library/Utilities/Physics.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f07234397f0818143a880ee7d03a527e \ No newline at end of file diff --git a/Runtime/Library/Utilities/ReflectionLibrary.cs b/Runtime/Library/Utilities/ReflectionLibrary.cs new file mode 100644 index 00000000..14508428 --- /dev/null +++ b/Runtime/Library/Utilities/ReflectionLibrary.cs @@ -0,0 +1,35 @@ +using System; +using System.Linq.Expressions; + +namespace RealMethod +{ + public static class RM_Reflection + { + /// + /// Extracts the variable or property name from a lambda expression. + /// + /// The type of the variable or property. + /// + /// A lambda expression pointing to a variable or property + /// (e.g. () => myVariable or () => myObject.MyProperty). + /// + /// + /// The name of the variable or property represented by the expression. + /// + /// + /// Thrown if the expression does not represent a valid variable or property access. + /// + /// + /// This method is commonly used to avoid hard-coded string names, + /// especially for logging, debugging, and change-notification systems. + /// F + public static string GetVariableName(Expression> expression) + { + if (expression.Body is MemberExpression memberExpression) + { + return memberExpression.Member.Name; + } + throw new ArgumentException("Expression is not a valid member expression."); + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/ReflectionLibrary.cs.meta b/Runtime/Library/Utilities/ReflectionLibrary.cs.meta new file mode 100644 index 00000000..0c81e1d9 --- /dev/null +++ b/Runtime/Library/Utilities/ReflectionLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 298b3a9137927964ba5d5ec48bdf853b \ No newline at end of file diff --git a/Runtime/Library/Utilities/PlayerPrefs.cs b/Runtime/Library/Utilities/SaveLibrary.cs similarity index 87% rename from Runtime/Library/Utilities/PlayerPrefs.cs rename to Runtime/Library/Utilities/SaveLibrary.cs index 3d844e10..2540a58e 100644 --- a/Runtime/Library/Utilities/PlayerPrefs.cs +++ b/Runtime/Library/Utilities/SaveLibrary.cs @@ -1,9 +1,13 @@ using System.Linq; using UnityEngine; +#if UNITY_ADDRESSABLES +using UnityEngine.AddressableAssets; +#endif + namespace RealMethod { - public static class RM_PlayerPrefs + public static class RM_Save { // Boolean public static void SetBool(string key, bool value) @@ -180,5 +184,34 @@ public static T[] GetArray(string key) string joined = PlayerPrefs.GetString(key); return joined.Split('|').Select(s => (T)System.Convert.ChangeType(s, typeof(T))).ToArray(); // Convert each string to T } + + // Asset + public static void SetAsset(string key, T asset) where T : UniqueAsset + { + string savedAddress = string.Empty; +#if UNITY_ADDRESSABLES + savedAddress = AddressablesUtility.GetAddress(asset); +#else + savedAddress = asset.name; +#endif + PlayerPrefs.SetString(key, savedAddress); + PlayerPrefs.Save(); + } + public static T GetAsset(string key) where T : UniqueAsset + { + if (!PlayerPrefs.HasKey(key)) return null; + string savedAddress = PlayerPrefs.GetString(key); + +#if UNITY_ADDRESSABLES + if (!string.IsNullOrEmpty(savedAddress)) + { + loadedObject = await Addressables.LoadAssetAsync(savedAddress).Task; + return loadedObject; + } +#else + return Resources.Load(savedAddress); +#endif + } + } } \ No newline at end of file diff --git a/Runtime/Library/Utilities/PlayerPrefs.cs.meta b/Runtime/Library/Utilities/SaveLibrary.cs.meta similarity index 100% rename from Runtime/Library/Utilities/PlayerPrefs.cs.meta rename to Runtime/Library/Utilities/SaveLibrary.cs.meta diff --git a/Runtime/Library/Utilities/TimeLibrary.cs b/Runtime/Library/Utilities/TimeLibrary.cs new file mode 100644 index 00000000..89373f7d --- /dev/null +++ b/Runtime/Library/Utilities/TimeLibrary.cs @@ -0,0 +1,68 @@ +using UnityEngine; +using System.Collections; + + +namespace RealMethod +{ + public static class RM_Time + { + private class CoroutineHandeler + { + public bool IsDone { get; private set; } + + public IEnumerator Run(IEnumerator coroutine) + { + yield return coroutine; + IsDone = true; + } + } + + + /// + /// Waits for a specified duration and then invokes a callback. + /// + /// Time in seconds to wait before executing the callback. + /// The action to invoke after the delay. + /// + /// An IEnumerator that can be used in a Unity coroutine. + /// + /// + /// Must be started using StartCoroutine(). + /// + public static IEnumerator Delay(float duration, System.Action callback) + { + yield return new WaitForSeconds(duration); + callback?.Invoke(); + } + public static IEnumerator WaitUntil(System.Func condition, System.Action callback) + { + yield return new WaitUntil(condition); + callback?.Invoke(); + } + public static IEnumerator WaitWhile(System.Func condition, System.Action callback) + { + yield return new WaitWhile(condition); + callback?.Invoke(); + } + public static IEnumerator Repeat(System.Action action, float interval, int count = -1) + { + int i = 0; + while (count < 0 || i < count) + { + action?.Invoke(); + i++; + yield return new WaitForSeconds(interval); + } + } + public static IEnumerator DelayOneFrame(System.Action callback) + { + yield return new WaitForEndOfFrame(); + callback?.Invoke(); + } + public static IEnumerator WaitForCoroutine(MonoBehaviour Owner, IEnumerator coroutine) + { + CoroutineHandeler handle = new CoroutineHandeler(); + yield return Owner.StartCoroutine(handle.Run(coroutine)); + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/TimeLibrary.cs.meta b/Runtime/Library/Utilities/TimeLibrary.cs.meta new file mode 100644 index 00000000..7c064773 --- /dev/null +++ b/Runtime/Library/Utilities/TimeLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 72d36d1c7404fca4ead9a94680ca3050 \ No newline at end of file diff --git a/Runtime/Library/Utilities/TraceLibrary.cs b/Runtime/Library/Utilities/TraceLibrary.cs new file mode 100644 index 00000000..c982cbba --- /dev/null +++ b/Runtime/Library/Utilities/TraceLibrary.cs @@ -0,0 +1,67 @@ +using UnityEngine; + +namespace RealMethod +{ + public static class RM_Trace + { + /// + /// Casts a debug line (ray) from a starting point in a given direction + /// with visual feedback for hits and misses. + /// + /// The origin point of the ray. + /// The direction the ray will fire in. + /// The maximum length of the ray. + /// The layer mask that the ray interacts with. + /// + /// Defines whether the ray should hit trigger colliders. + /// + /// Color of the ray if no hit occurs. + /// Color of the ray when a hit occurs. + /// + /// Output RaycastHit containing information about the hit. + /// + /// + /// True if the ray hits a collider; otherwise false. + /// + /// + /// Useful for debugging raycasts in the Scene view. + /// Typically implemented using Physics.Raycast() combined with Debug.DrawLine(). + /// + public static bool Line(Vector3 Start, Vector3 Direction, float Length, LayerMask Layer, QueryTriggerInteraction TriggerInteraction, Color RayColor, Color HitColor, out RaycastHit HitResult) + { + bool Result; + Result = Physics.Raycast(Start, Direction, out HitResult, Length, Layer, TriggerInteraction); + float debuglength = HitResult.collider ? HitResult.distance : Length; + Color debugcolor = HitResult.collider ? HitColor : RayColor; + Debug.DrawRay(Start, Direction * debuglength, debugcolor); + return Result; + } + public static bool Line(Vector3 Start, Vector3 Direction, float Length, LayerMask Layer, QueryTriggerInteraction TriggerInteraction, out RaycastHit HitResult) + { + bool Result; + Result = Physics.Raycast(Start, Direction, out HitResult, Length, Layer, TriggerInteraction); + float debuglength = HitResult.collider ? HitResult.distance : Length; + Color debugcolor = HitResult.collider ? Color.green : Color.red; + Debug.DrawRay(Start, Direction * debuglength, debugcolor); + return Result; + } + public static bool Line(Vector3 Start, Vector3 Direction, float Length, LayerMask Layer, out RaycastHit HitResult) + { + bool Result; + Result = Physics.Raycast(Start, Direction, out HitResult, Length, Layer); + float debuglength = HitResult.collider ? HitResult.distance : Length; + Color debugcolor = HitResult.collider ? Color.green : Color.red; + Debug.DrawRay(Start, Direction * debuglength, debugcolor); + return Result; + } + public static bool Line(Vector3 Start, Vector3 Direction, float Length, out RaycastHit HitResult) + { + bool Result; + Result = Physics.Raycast(Start, Direction, out HitResult, Length); + float debuglength = HitResult.collider ? HitResult.distance : Length; + Color debugcolor = HitResult.collider ? Color.green : Color.red; + Debug.DrawRay(Start, Direction * debuglength, debugcolor); + return Result; + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/TraceLibrary.cs.meta b/Runtime/Library/Utilities/TraceLibrary.cs.meta new file mode 100644 index 00000000..1f4e2a57 --- /dev/null +++ b/Runtime/Library/Utilities/TraceLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e72b5d1882269eb4c87476db08cef7fd \ No newline at end of file diff --git a/Runtime/Library/Utilities/TransformLibrary.cs b/Runtime/Library/Utilities/TransformLibrary.cs new file mode 100644 index 00000000..cad5e8af --- /dev/null +++ b/Runtime/Library/Utilities/TransformLibrary.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +namespace RealMethod +{ + public static class RM_Transform + { + /// + /// Converts a position defined relative to a transform into world space. + /// + /// The reference transform. + /// The position relative to the transform. + /// The corresponding world space position. + /// + /// Useful when you want to compute positions relative to an object + /// and convert them to world coordinates. + /// + public static Vector3 GetWorldPositionFromRelative(Transform from, Vector3 relativePos) + { + return from.TransformPoint(relativePos); + } + public static Vector3 GetRelativePosition(Transform from, Transform to) + { + return from.InverseTransformPoint(to.position); + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/TransformLibrary.cs.meta b/Runtime/Library/Utilities/TransformLibrary.cs.meta new file mode 100644 index 00000000..1be69078 --- /dev/null +++ b/Runtime/Library/Utilities/TransformLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8953e453fba18d04d9ab0848fb84c663 \ No newline at end of file diff --git a/Runtime/Library/Utilities/TweenLibrary.cs b/Runtime/Library/Utilities/TweenLibrary.cs new file mode 100644 index 00000000..4dba6f30 --- /dev/null +++ b/Runtime/Library/Utilities/TweenLibrary.cs @@ -0,0 +1,68 @@ +using System.Collections; +using UnityEngine; + +namespace RealMethod +{ + public static class Tween + { + /// + /// Moves the target transform to a specified position over a given duration. + /// + /// The transform to move. + /// The target position. + /// The time in seconds to complete the movement. + /// An IEnumerator for use with StartCoroutine. + /// + /// Should be started with StartCoroutine(). + /// + public static IEnumerator MoveTo(Transform target, Vector3 end, float duration) + { + Vector3 start = target.position; + float t = 0f; + while (t < duration) + { + t += Time.deltaTime; + target.position = Vector3.Lerp(start, end, t / duration); + yield return null; + } + target.position = end; + } + public static IEnumerator FadeCanvas(CanvasGroup canvas, float targetAlpha, float duration) + { + float start = canvas.alpha; + float t = 0f; + while (t < duration) + { + t += Time.deltaTime; + canvas.alpha = Mathf.Lerp(start, targetAlpha, t / duration); + yield return null; + } + canvas.alpha = targetAlpha; + } + public static IEnumerator ScaleTo(Transform target, Vector3 targetScale, float duration) + { + Vector3 start = target.localScale; + float t = 0f; + while (t < duration) + { + t += Time.deltaTime; + target.localScale = Vector3.Lerp(start, targetScale, t / duration); + yield return null; + } + target.localScale = targetScale; + } + public static IEnumerator RotateTo(Transform target, Quaternion targetRot, float duration) + { + Quaternion start = target.rotation; + float t = 0f; + while (t < duration) + { + t += Time.deltaTime; + target.rotation = Quaternion.Slerp(start, targetRot, t / duration); + yield return null; + } + target.rotation = targetRot; + } + + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/TweenLibrary.cs.meta b/Runtime/Library/Utilities/TweenLibrary.cs.meta new file mode 100644 index 00000000..e554de83 --- /dev/null +++ b/Runtime/Library/Utilities/TweenLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c5c296c6d6b432444b15ade9d82079bd \ No newline at end of file diff --git a/Runtime/Library/Utilities/UILibrary.cs b/Runtime/Library/Utilities/UILibrary.cs new file mode 100644 index 00000000..3084b1d4 --- /dev/null +++ b/Runtime/Library/Utilities/UILibrary.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace RealMethod +{ + public static class RM_UI + { + public static bool IsTouchOverUI(GraphicRaycaster HUD_graphicRaycaster, Vector2 touchPosition) + { + // Create a pointer event data from the touch position + PointerEventData pointerEventData = new PointerEventData(null); + pointerEventData.position = touchPosition; + + // Create a list to hold the results + List results = new List(); + + // Raycast using the GraphicRaycaster and pointer event data + HUD_graphicRaycaster.Raycast(pointerEventData, results); + + // Check if we hit any UI elements + return results.Count > 0; + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/UILibrary.cs.meta b/Runtime/Library/Utilities/UILibrary.cs.meta new file mode 100644 index 00000000..eee20355 --- /dev/null +++ b/Runtime/Library/Utilities/UILibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fc40a86d617dbe446bc15839695b6d05 \ No newline at end of file diff --git a/Runtime/Library/Utilities/VectorLibrary.cs b/Runtime/Library/Utilities/VectorLibrary.cs new file mode 100644 index 00000000..8ac1eab0 --- /dev/null +++ b/Runtime/Library/Utilities/VectorLibrary.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +namespace RealMethod +{ + public static class RM_Vector + { + /// + /// Determines whether two vectors are aligned within a specified tolerance. + /// + /// The first vector. + /// The second vector. + /// + /// The allowed deviation when comparing alignment. + /// Smaller values require closer directional similarity. + /// + /// + /// True if the vectors are aligned within the given tolerance; otherwise false. + /// + /// + /// Alignment usually means the vectors point in nearly the same direction, + /// typically evaluated using the dot product or angle between them. + /// + public static bool IsAligned(Vector2 vectorA, Vector2 vectorB, float tolerance) + { + float angle = Vector2.Angle(vectorA.normalized, vectorB.normalized); + if (angle <= tolerance) return true; + + return false; + } + } +} \ No newline at end of file diff --git a/Runtime/Library/Utilities/VectorLibrary.cs.meta b/Runtime/Library/Utilities/VectorLibrary.cs.meta new file mode 100644 index 00000000..0b0cdce4 --- /dev/null +++ b/Runtime/Library/Utilities/VectorLibrary.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 09d0d2dad219dab45a030c4238bd1320 \ No newline at end of file diff --git a/Runtime/Library/Vendor.meta b/Runtime/Library/Vendor.meta deleted file mode 100644 index a03ab101..00000000 --- a/Runtime/Library/Vendor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 351fbdcf34a545f49a22ac661ed8bcd3 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Library/Vendor/SerializableDictionary.meta b/Runtime/Library/Vendor/SerializableDictionary.meta deleted file mode 100644 index 443cf3de..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 096dbd1bd10691342aed2e35d663eabb -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Library/Vendor/SerializableDictionary/Example.meta b/Runtime/Library/Vendor/SerializableDictionary/Example.meta deleted file mode 100644 index 5bbdabde..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/Example.meta +++ /dev/null @@ -1,5 +0,0 @@ -fileFormatVersion: 2 -guid: ea574807be3814126807ca7b22d13988 -folderAsset: yes -DefaultImporter: - userData: diff --git a/Runtime/Library/Vendor/SerializableDictionary/Example/SerializableDicitonary Example.unity b/Runtime/Library/Vendor/SerializableDictionary/Example/SerializableDicitonary Example.unity deleted file mode 100644 index 073e39ea..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/Example/SerializableDicitonary Example.unity +++ /dev/null @@ -1,256 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!29 &1 -OcclusionCullingSettings: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_OcclusionBakeSettings: - smallestOccluder: 5 - smallestHole: 0.25 - backfaceThreshold: 100 - m_SceneGUID: 00000000000000000000000000000000 - m_OcclusionCullingData: {fileID: 0} ---- !u!104 &2 -RenderSettings: - m_ObjectHideFlags: 0 - serializedVersion: 8 - m_Fog: 0 - m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} - m_FogMode: 3 - m_FogDensity: 0.01 - m_LinearFogStart: 0 - m_LinearFogEnd: 300 - m_AmbientSkyColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} - m_AmbientEquatorColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} - m_AmbientGroundColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} - m_AmbientIntensity: 1 - m_AmbientMode: 3 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 0} - m_HaloStrength: 0.5 - m_FlareStrength: 1 - m_FlareFadeSpeed: 3 - m_HaloTexture: {fileID: 0} - m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} - m_DefaultReflectionMode: 0 - m_DefaultReflectionResolution: 128 - m_ReflectionBounces: 1 - m_ReflectionIntensity: 1 - m_CustomReflection: {fileID: 0} - m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} ---- !u!157 &4 -LightmapSettings: - m_ObjectHideFlags: 0 - serializedVersion: 11 - m_GIWorkflowMode: 1 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_TemporalCoherenceThreshold: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - m_EnableRealtimeLightmaps: 0 - m_LightmapEditorSettings: - serializedVersion: 9 - m_Resolution: 1 - m_BakeResolution: 50 - m_TextureWidth: 1024 - m_TextureHeight: 1024 - m_AO: 1 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_Padding: 2 - m_LightmapParameters: {fileID: 0} - m_LightmapsBakeMode: 1 - m_TextureCompression: 0 - m_FinalGather: 0 - m_FinalGatherFiltering: 1 - m_FinalGatherRayCount: 256 - m_ReflectionCompression: 2 - m_MixedBakeMode: 1 - m_BakeBackend: 0 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 500 - m_PVRBounces: 2 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVRFilteringMode: 0 - m_PVRCulling: 1 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ShowResolutionOverlay: 1 - m_LightingDataAsset: {fileID: 0} - m_UseShadowmask: 0 ---- !u!196 &5 -NavMeshSettings: - serializedVersion: 2 - m_ObjectHideFlags: 0 - m_BuildSettings: - serializedVersion: 2 - agentTypeID: 0 - agentRadius: 0.5 - agentHeight: 2 - agentSlope: 45 - agentClimb: 0.4 - ledgeDropHeight: 0 - maxJumpAcrossDistance: 0 - minRegionArea: 2 - manualCellSize: 0 - cellSize: 0.16666666 - manualTileSize: 0 - tileSize: 256 - accuratePlacement: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1 &714127983 -GameObject: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - serializedVersion: 5 - m_Component: - - component: {fileID: 714127989} - - component: {fileID: 714127988} - - component: {fileID: 714127987} - - component: {fileID: 714127986} - - component: {fileID: 714127985} - - component: {fileID: 714127984} - m_Layer: 0 - m_Name: Main Camera - m_TagString: MainCamera - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &714127984 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 714127983} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d5ff00a74ccb984498070d9930a7944c, type: 3} - m_Name: - m_EditorClassIdentifier: - m_stringStringDictionary: - m_keys: - - first key - - second key - - third key - m_values: - - value A - - value B - - value C - m_objectColorDictionary: - m_keys: - - {fileID: 714127983} - - {fileID: 714127984} - m_values: - - {r: 0, g: 0, b: 1, a: 1} - - {r: 1, g: 0, b: 0, a: 1} - m_stringColorArrayDictionary: - m_keys: - - rainbow - - grayscale - m_values: - - data: - - {r: 1, g: 0, b: 0, a: 1} - - {r: 1, g: 0.40000004, b: 0, a: 1} - - {r: 1, g: 0.9333334, b: 0, a: 1} - - {r: 0, g: 1, b: 0, a: 1} - - {r: 0, g: 0.6, b: 1, a: 1} - - {r: 0.26666668, g: 0, b: 1, a: 1} - - {r: 0.6, g: 0, b: 1, a: 1} - - data: - - {r: 0, g: 0, b: 0, a: 0} - - {r: 0.2509804, g: 0.2509804, b: 0.2509804, a: 0.2509804} - - {r: 0.5019608, g: 0.5019608, b: 0.5019608, a: 0.5019608} - - {r: 0.7529412, g: 0.7529412, b: 0.7529412, a: 0.7529412} - - {r: 1, g: 1, b: 1, a: 1} - m_stringHashSet: - m_keys: - - item 1 - - item 2 - - item 3 ---- !u!81 &714127985 -AudioListener: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 714127983} - m_Enabled: 1 ---- !u!124 &714127986 -Behaviour: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 714127983} - m_Enabled: 1 ---- !u!92 &714127987 -Behaviour: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 714127983} - m_Enabled: 1 ---- !u!20 &714127988 -Camera: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 714127983} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 1 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0.019607844} - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 0.3 - far clip plane: 1000 - field of view: 60 - orthographic: 0 - orthographic size: 5 - m_Depth: -1 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 0} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 0 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!4 &714127989 -Transform: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 714127983} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Runtime/Library/Vendor/SerializableDictionary/Example/SerializableDicitonary Example.unity.meta b/Runtime/Library/Vendor/SerializableDictionary/Example/SerializableDicitonary Example.unity.meta deleted file mode 100644 index 25ff160d..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/Example/SerializableDicitonary Example.unity.meta +++ /dev/null @@ -1,4 +0,0 @@ -fileFormatVersion: 2 -guid: 6c0758ade4ba74b7493ce3806fa2f38b -DefaultImporter: - userData: diff --git a/Runtime/Library/Vendor/SerializableDictionary/Example/UserSerializableDictionaries.cs b/Runtime/Library/Vendor/SerializableDictionary/Example/UserSerializableDictionaries.cs deleted file mode 100644 index 13043a25..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/Example/UserSerializableDictionaries.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using UnityEngine; - -namespace RealMethod -{ - [Serializable] - public class StringBoolDictionary : SerializableDictionary { } - [Serializable] - public class StringByteDictionary : SerializableDictionary { } - [Serializable] - public class StringIntDictionary : SerializableDictionary { } - [Serializable] - public class StringFloatDictionary : SerializableDictionary { } - [Serializable] - public class StringAssetObjectDictionary : SerializableDictionary { } - [Serializable] - public class StringGObjectDictionary : SerializableDictionary { } - [Serializable] - public class ObjectColorDictionary : SerializableDictionary { } - - // ColorArray - [Serializable] - public class ColorArrayStorage : SerializableDictionary.Storage { } - [Serializable] - public class StringColorArrayDictionary : SerializableDictionary { } -} diff --git a/Runtime/Library/Vendor/SerializableDictionary/Example/UserSerializableDictionaries.cs.meta b/Runtime/Library/Vendor/SerializableDictionary/Example/UserSerializableDictionaries.cs.meta deleted file mode 100644 index 8b34ba9c..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/Example/UserSerializableDictionaries.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: bd910530dd8f6b5429c65a494644ed09 -timeCreated: 1493639913 -licenseType: Free -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.cs b/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.cs deleted file mode 100644 index 4926666c..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.cs +++ /dev/null @@ -1,259 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using UnityEngine; - -namespace RealMethod -{ - [Serializable] - public abstract class SerializableDictionaryBase : SerializableDictionaryBase, IDictionary, IDictionary, ISerializationCallbackReceiver, IDeserializationCallback, ISerializable - { - Dictionary m_dict; - [SerializeField] - TKey[] m_keys; - [SerializeField] - TValueStorage[] m_values; - - public SerializableDictionaryBase() - { - m_dict = new Dictionary(); - } - - public SerializableDictionaryBase(IDictionary dict) - { - m_dict = new Dictionary(dict); - } - - protected abstract void SetValue(TValueStorage[] storage, int i, TValue value); - protected abstract TValue GetValue(TValueStorage[] storage, int i); - - public void CopyFrom(IDictionary dict) - { - m_dict.Clear(); - foreach (var kvp in dict) - { - m_dict[kvp.Key] = kvp.Value; - } - } - - public void OnAfterDeserialize() - { - if (m_keys != null && m_values != null && m_keys.Length == m_values.Length) - { - m_dict.Clear(); - int n = m_keys.Length; - for (int i = 0; i < n; ++i) - { - m_dict[m_keys[i]] = GetValue(m_values, i); - } - - m_keys = null; - m_values = null; - } - } - - public void OnBeforeSerialize() - { - int n = m_dict.Count; - m_keys = new TKey[n]; - m_values = new TValueStorage[n]; - - int i = 0; - foreach (var kvp in m_dict) - { - m_keys[i] = kvp.Key; - SetValue(m_values, i, kvp.Value); - ++i; - } - } - - #region IDictionary - - public ICollection Keys { get { return ((IDictionary)m_dict).Keys; } } - public ICollection Values { get { return ((IDictionary)m_dict).Values; } } - public int Count { get { return ((IDictionary)m_dict).Count; } } - public bool IsReadOnly { get { return ((IDictionary)m_dict).IsReadOnly; } } - - public TValue this[TKey key] - { - get { return ((IDictionary)m_dict)[key]; } - set { ((IDictionary)m_dict)[key] = value; } - } - - public TKey GetKey(int index) - { - return m_dict.Keys.ElementAt(index); - } - public TValue GetValue(int index) - { - return m_dict.Values.ElementAt(index); - } - public void Add(TKey key, TValue value) - { - ((IDictionary)m_dict).Add(key, value); - } - - public bool ContainsKey(TKey key) - { - return ((IDictionary)m_dict).ContainsKey(key); - } - - public bool Remove(TKey key) - { - return ((IDictionary)m_dict).Remove(key); - } - - public bool TryGetValue(TKey key, out TValue value) - { - return ((IDictionary)m_dict).TryGetValue(key, out value); - } - - public void Add(KeyValuePair item) - { - ((IDictionary)m_dict).Add(item); - } - - public void Clear() - { - ((IDictionary)m_dict).Clear(); - } - - public bool Contains(KeyValuePair item) - { - return ((IDictionary)m_dict).Contains(item); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ((IDictionary)m_dict).CopyTo(array, arrayIndex); - } - - public bool Remove(KeyValuePair item) - { - return ((IDictionary)m_dict).Remove(item); - } - - public IEnumerator> GetEnumerator() - { - return ((IDictionary)m_dict).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IDictionary)m_dict).GetEnumerator(); - } - - #endregion - - #region IDictionary - - public bool IsFixedSize { get { return ((IDictionary)m_dict).IsFixedSize; } } - ICollection IDictionary.Keys { get { return ((IDictionary)m_dict).Keys; } } - ICollection IDictionary.Values { get { return ((IDictionary)m_dict).Values; } } - public bool IsSynchronized { get { return ((IDictionary)m_dict).IsSynchronized; } } - public object SyncRoot { get { return ((IDictionary)m_dict).SyncRoot; } } - - public object this[object key] - { - get { return ((IDictionary)m_dict)[key]; } - set { ((IDictionary)m_dict)[key] = value; } - } - - public void Add(object key, object value) - { - ((IDictionary)m_dict).Add(key, value); - } - - public bool Contains(object key) - { - return ((IDictionary)m_dict).Contains(key); - } - - IDictionaryEnumerator IDictionary.GetEnumerator() - { - return ((IDictionary)m_dict).GetEnumerator(); - } - - public void Remove(object key) - { - ((IDictionary)m_dict).Remove(key); - } - - public void CopyTo(System.Array array, int index) - { - ((IDictionary)m_dict).CopyTo(array, index); - } - - #endregion - - #region IDeserializationCallback - - public void OnDeserialization(object sender) - { - ((IDeserializationCallback)m_dict).OnDeserialization(sender); - } - - #endregion - - #region ISerializable - - protected SerializableDictionaryBase(SerializationInfo info, StreamingContext context) - { - m_dict = new Dictionary(info, context); - } - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - ((ISerializable)m_dict).GetObjectData(info, context); - } - - #endregion - } - - public static class SerializableDictionary - { - public class Storage : SerializableDictionaryBase.Storage - { - public T data; - } - } - - [Serializable] - public class SerializableDictionary : SerializableDictionaryBase - { - public SerializableDictionary() { } - public SerializableDictionary(IDictionary dict) : base(dict) { } - protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { } - - protected override TValue GetValue(TValue[] storage, int i) - { - return storage[i]; - } - - protected override void SetValue(TValue[] storage, int i, TValue value) - { - storage[i] = value; - } - } - - [Serializable] - public class SerializableDictionary : SerializableDictionaryBase where TValueStorage : SerializableDictionary.Storage, new() - { - public SerializableDictionary() { } - public SerializableDictionary(IDictionary dict) : base(dict) { } - protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { } - - protected override TValue GetValue(TValueStorage[] storage, int i) - { - return storage[i].data; - } - - protected override void SetValue(TValueStorage[] storage, int i, TValue value) - { - storage[i] = new TValueStorage(); - storage[i].data = value; - } - } -} diff --git a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.cs.meta b/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.cs.meta deleted file mode 100644 index 43f3882f..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: e7be1c9624387604fba4005ccf7dbd5a -timeCreated: 1492868176 -licenseType: Free -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.pdf b/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.pdf deleted file mode 100644 index cad88c37..00000000 Binary files a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.pdf and /dev/null differ diff --git a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.pdf.meta b/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.pdf.meta deleted file mode 100644 index b3b51902..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionary.pdf.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 8eb73a56b3a6ee64ab2c30cac8878d8f -timeCreated: 1492869030 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionaryBase.cs b/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionaryBase.cs deleted file mode 100644 index 6e4ac3ad..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionaryBase.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Runtime.Serialization; - -namespace RealMethod -{ - public abstract class SerializableDictionaryBase - { - public abstract class Storage { } - - protected class Dictionary : System.Collections.Generic.Dictionary - { - public Dictionary() { } - public Dictionary(IDictionary dict) : base(dict) { } - public Dictionary(SerializationInfo info, StreamingContext context) : base(info, context) { } - } - } -} \ No newline at end of file diff --git a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionaryBase.cs.meta b/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionaryBase.cs.meta deleted file mode 100644 index 6585f825..00000000 --- a/Runtime/Library/Vendor/SerializableDictionary/SerializableDictionaryBase.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 3e4c04725aff7c545b5c49a0059c0c48 \ No newline at end of file diff --git a/Runtime/Pattern/DataAssets.meta b/Runtime/Pattern/Assets.meta similarity index 100% rename from Runtime/Pattern/DataAssets.meta rename to Runtime/Pattern/Assets.meta diff --git a/Runtime/Pattern/Assets/BlackboardAsset.cs b/Runtime/Pattern/Assets/BlackboardAsset.cs new file mode 100644 index 00000000..39f8f597 --- /dev/null +++ b/Runtime/Pattern/Assets/BlackboardAsset.cs @@ -0,0 +1,53 @@ +using UnityEngine; + +namespace RealMethod +{ + public abstract class BlackboardAsset : UniqueAsset, IBlackboard + { + public Blackboard Blackboard; + + // Implement IBlackboard Interface + public bool HasBool(Name16 name) => Blackboard.HasValue(name); + public void SetBool(Name16 name, bool target) => Blackboard.SetValue(name, target); + public bool GetBool(Name16 name) => Blackboard.GetValue(name); + public bool HasInt(Name16 name) => Blackboard.HasValue(name); + public void SetInt(Name16 name, int target) => Blackboard.SetValue(name, target); + public int GetInt(Name16 name) => Blackboard.GetValue(name); + public bool HasFloat(Name16 name) => Blackboard.HasValue(name); + public void SetFloat(Name16 name, float target) => Blackboard.SetValue(name, target); + public float GetFloat(Name16 name) => Blackboard.GetValue(name); + public bool HasString(Name16 name) => Blackboard.HasValue(name); + public void SetString(Name16 name, string target) => Blackboard.SetValue(name, target); + public string GetString(Name16 name) => Blackboard.GetValue(name); + public bool HasVector2(Name16 name) => Blackboard.HasValue(name); + public void SetVector2(Name16 name, Vector2 target) => Blackboard.SetValue(name, target); + public Vector2 GetVector2(Name16 name) => Blackboard.GetValue(name); + public bool HasVector3(Name16 name) => Blackboard.HasValue(name); + public void SetVector3(Name16 name, Vector3 target) => Blackboard.SetValue(name, target); + public Vector3 GetVector3(Name16 name) => Blackboard.GetValue(name); + public bool HasPefab(Name16 name) => Blackboard.HasValue(name); + public void SetPrefab(Name16 name, Prefab target) => Blackboard.SetValue(name, target); + public Prefab GetPrefab(Name16 name) => Blackboard.GetValue(name); + public bool HasAsset(Name16 name) => Blackboard.HasValue(name); + public void SetAsset(Name16 name, PrimitiveAsset target) => Blackboard.SetValue(name, target); + public PrimitiveAsset GetAsset(Name16 name) => Blackboard.GetValue(name); + public bool HasComponent(Name16 name) => Blackboard.HasValue(name); + public void SetComponent(Name16 name, Component target) => Blackboard.SetValue(name, target); + public Component GetComponent(Name16 name) => Blackboard.GetValue(name); + + + protected virtual void OnEnable() + { + Blackboard.SetSize(GetMaxSize()); + } + + [ContextMenu("Resize")] + private void OnResetSize() + { + Blackboard = new Blackboard(GetMaxSize()); + } + + // Abstract Methods + protected abstract int GetMaxSize(); + } +} \ No newline at end of file diff --git a/Runtime/Pattern/DesignPatterns/SharedDataAsset.cs.meta b/Runtime/Pattern/Assets/BlackboardAsset.cs.meta similarity index 100% rename from Runtime/Pattern/DesignPatterns/SharedDataAsset.cs.meta rename to Runtime/Pattern/Assets/BlackboardAsset.cs.meta diff --git a/Runtime/Pattern/Assets/DelegateAsset.cs b/Runtime/Pattern/Assets/DelegateAsset.cs new file mode 100644 index 00000000..655fd581 --- /dev/null +++ b/Runtime/Pattern/Assets/DelegateAsset.cs @@ -0,0 +1,210 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + public abstract class DelegateAsset : UniqueAsset + { + public abstract void Invoke(); + + public abstract void AddListener(D listener) where D : Delegate; + public abstract void RemoveListener(D listener) where D : Delegate; + +#if UNITY_EDITOR + [ContextMenu("Invoke")] + private void Raise() + { + Invoke(); + } +#endif + } + + public abstract class EventAsset : DelegateAsset + { + [SerializeField] + private bool CanUseDefaultValue = false; + [SerializeField, ConditionalHide("CanUseDefaultValue", true, false)] + private T DefaultValue; + private event Action _event; + + + public void Invoke(T value) + { + _event?.Invoke(value); + } + + public override void Invoke() + { + if (CanUseDefaultValue) + { + _event?.Invoke(DefaultValue); + } + else + { + Debug.LogWarning($"You can Invoke {GetType().Name} Event with Defaut value, [CanUseDefaultValue = false]"); + } + } + public override void AddListener(D listener) + { + if (listener is Action provider) + { + _event += provider; + } + else + { + Debug.LogWarning($"The listener should be {typeof(Action)} for binding, AddListener Faild!"); + } + } + public override void RemoveListener(D listener) + { + if (listener is Action provider) + { + _event -= provider; + } + else + { + Debug.LogWarning($"The listener should be {typeof(Action)} for binding, AddListener Faild!"); + } + } + + + // -------- Operator Overloads -------- + public static EventAsset operator +(EventAsset asset, Action listener) + { + asset._event += listener; + return asset; + } + public static EventAsset operator -(EventAsset asset, Action listener) + { + asset._event -= listener; + return asset; + } + } + public abstract class EventAsset : DelegateAsset + { + [SerializeField] + private bool CanUseDefaultValue = false; + [SerializeField, ConditionalHide("CanUseDefaultValue", true, false)] + private T DefaultValue_st; + [SerializeField, ConditionalHide("CanUseDefaultValue", true, false)] + private J DefaultValue_nd; + + private event Action _event; + + public void Invoke(T value, J value2) + { + _event?.Invoke(value, value2); + } + + + public override void Invoke() + { + if (CanUseDefaultValue) + { + _event?.Invoke(DefaultValue_st, DefaultValue_nd); + } + else + { + Debug.LogWarning($"You can Invoke {GetType().Name} Event with Defaut value"); + } + } + public override void AddListener(D listener) + { + if (listener is Action provider) + { + _event += provider; + } + else + { + Debug.LogWarning($"The listener should be {typeof(Action)} for binding, AddListener Faild!"); + } + } + public override void RemoveListener(D listener) + { + if (listener is Action provider) + { + _event -= provider; + } + else + { + Debug.LogWarning($"The listener should be {typeof(Action)} for binding, AddListener Faild!"); + } + } + + // -------- Operator Overloads -------- + public static EventAsset operator +(EventAsset asset, Action listener) + { + asset._event += listener; + return asset; + } + public static EventAsset operator -(EventAsset asset, Action listener) + { + asset._event -= listener; + return asset; + } + } + public abstract class EventAsset : DelegateAsset + { + [SerializeField] + private bool CanUseDefaultValue = false; + [SerializeField, ConditionalHide("CanUseDefaultValue", true, false)] + private T DefaultValue_st; + [SerializeField, ConditionalHide("CanUseDefaultValue", true, false)] + private J DefaultValue_nd; + [SerializeField, ConditionalHide("CanUseDefaultValue", true, false)] + private F DefaultValue_rd; + + private event Action _event; + + public void Invoke(T value, J value2, F value3) + { + _event?.Invoke(value, value2, value3); + } + + public override void Invoke() + { + if (CanUseDefaultValue) + { + _event?.Invoke(DefaultValue_st, DefaultValue_nd, DefaultValue_rd); + } + else + { + Debug.LogWarning($"You can Invoke {GetType().Name} Event with Defaut value"); + } + } + public override void AddListener(D listener) + { + if (listener is Action provider) + { + _event += provider; + } + else + { + Debug.LogWarning($"The listener should be {typeof(Action)} for binding, AddListener Faild!"); + } + } + public override void RemoveListener(D listener) + { + if (listener is Action provider) + { + _event -= provider; + } + else + { + Debug.LogWarning($"The listener should be {typeof(Action)} for binding, AddListener Faild!"); + } + } + + // -------- Operator Overloads -------- + public static EventAsset operator +(EventAsset asset, Action listener) + { + asset._event += listener; + return asset; + } + public static EventAsset operator -(EventAsset asset, Action listener) + { + asset._event -= listener; + return asset; + } + } +} \ No newline at end of file diff --git a/Runtime/Pattern/Assets/DelegateAsset.cs.meta b/Runtime/Pattern/Assets/DelegateAsset.cs.meta new file mode 100644 index 00000000..399c94ef --- /dev/null +++ b/Runtime/Pattern/Assets/DelegateAsset.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3c7a1be8157370e46899c483df7a9710 \ No newline at end of file diff --git a/Runtime/Pattern/DataAssets/FactoryAsset.cs b/Runtime/Pattern/Assets/FactoryAsset.cs similarity index 58% rename from Runtime/Pattern/DataAssets/FactoryAsset.cs rename to Runtime/Pattern/Assets/FactoryAsset.cs index aa774fe6..03166d87 100644 --- a/Runtime/Pattern/DataAssets/FactoryAsset.cs +++ b/Runtime/Pattern/Assets/FactoryAsset.cs @@ -1,28 +1,21 @@ +using UnityEngine; + namespace RealMethod { - public interface IFactoryEditorAccess - { - - } - public interface IFactoryAction - { - void Initiate(); - void Execute(); - } - public struct FactoryProduct : IFactoryAction { - public void Initiate() + // Implement ICommand Interface + bool ICommand.Initiate(Object owner) { throw new System.NotImplementedException(); } - public void Execute() + void ICommand.ExecuteCommand(object Executer) { throw new System.NotImplementedException(); } } - + public abstract class FactoryAsset : DataAsset { diff --git a/Runtime/Pattern/DataAssets/FactoryAsset.cs.meta b/Runtime/Pattern/Assets/FactoryAsset.cs.meta similarity index 100% rename from Runtime/Pattern/DataAssets/FactoryAsset.cs.meta rename to Runtime/Pattern/Assets/FactoryAsset.cs.meta diff --git a/Runtime/Pattern/Assets/GUIAsset.cs b/Runtime/Pattern/Assets/GUIAsset.cs new file mode 100644 index 00000000..8cf1feec --- /dev/null +++ b/Runtime/Pattern/Assets/GUIAsset.cs @@ -0,0 +1,760 @@ +#if UNITY_EDITOR || DEVELOPMENT_BUILD +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace RealMethod +{ + + public interface IDrawWindow + { + void OnButtonClick(string ButtonName); + void OnToggleChange(string ToggleName, bool Val); + Rect GetRect(Rect element, int index); + GUIStyle GetStyle(int ID); + } + + public abstract class GUIAsset : UniqueAsset, IDraw, ITask, IDrawWindow + { + [Serializable] + public class MemberVariable : MemberBinding + { + public object GetValue() + { + if (SelectedMember is System.Reflection.FieldInfo FInfo) + { + return FInfo.GetValue(SelectedComponent); + } + else if (SelectedMember is System.Reflection.PropertyInfo PInfo) + { + return PInfo.GetValue(SelectedComponent); + } + else + { + Debug.LogWarning($"Member '{SelectedMember.Name}' not found on component type '{SelectedComponent.GetType()}'."); + return default; + } + } + } + public enum BuiltInGUIType + { + Label = 0, + Button = 1, + RepeatButton = 2, + Toggle = 3, + TextField = 4, + PasswordField = 5, + TextArea = 6, + HorizontalSlider = 7, + HorizontalScrollbar = 8, + VerticalSlider = 9, + VerticalScrollbar = 10, + Box = 11, + Group_Begin = 12, + Group_End = 13, + ScrollView_Begin = 14, + ScrollView_End = 15, + SelectionGrid = 16, + Clip_Begin = 17, + Clip_End = 18, + DrawTexture = 19, + Toolbar = 20, + } + [Serializable] + private class DrawSlot : IDraw + { + private enum GUIStyleMode + { + Skin = 0, + Custom_1 = 1, + Custom_2 = 2, + Custom_3 = 3, + None = 4, + } + [Header("GUI Info")] + [Slug] + public string NameID; + public BuiltInGUIType GUIType; + [SerializeField] + private GUIStyleMode StyleMode; + public bool Reset = false; + public Rect Transform = Rect.zero; + [Header("GUI Setting")] + [ConditionalShowByEnum("GUIType", BuiltInGUIType.Button, BuiltInGUIType.RepeatButton, BuiltInGUIType.Toggle, BuiltInGUIType.Box)] + public string Title; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.Label, BuiltInGUIType.TextField, BuiltInGUIType.PasswordField, BuiltInGUIType.TextArea)] + public string Text; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.Toggle)] + public bool Toggle; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.HorizontalScrollbar, BuiltInGUIType.HorizontalSlider, BuiltInGUIType.VerticalScrollbar, BuiltInGUIType.VerticalSlider)] + public float Slider; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.HorizontalSlider, BuiltInGUIType.VerticalSlider)] + public float SliderMin; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.HorizontalSlider, BuiltInGUIType.VerticalSlider)] + public float SliderMax; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.HorizontalScrollbar, BuiltInGUIType.VerticalScrollbar)] + public float ScrollSize; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.ScrollView_Begin)] + public Vector2 scrollPos; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.ScrollView_Begin)] + public Vector2 ContentSize; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.SelectionGrid)] + public int SelectedIndex; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.SelectionGrid, BuiltInGUIType.Toolbar)] + public string Option; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.SelectionGrid)] + public int Columns; + [ConditionalShowByEnum("GUIType", BuiltInGUIType.DrawTexture)] + public Texture Texture; + [Header("MemberInfo")] + [ConditionalShowByEnum("GUIType", BuiltInGUIType.Button, BuiltInGUIType.RepeatButton, BuiltInGUIType.Toggle, + BuiltInGUIType.Label, BuiltInGUIType.TextField, BuiltInGUIType.PasswordField, BuiltInGUIType.TextArea)] + public bool UseMember = false; + [ConditionalHide("UseMember", true, false)] + public string gameObjectName; + [ConditionalHide("UseMember", true, false)] + public SoftType componentType; + [ConditionalHide("UseMember", true, false)] + public string memberName; + + + // Private Variable + private IDrawWindow window; + public bool IsActive => window != null; + private Component CachedComponent; + + + // Implement IDraw Interface + bool IDraw.CanDraw(int Index) + { + if (!IsActive) + return false; + + if (string.IsNullOrEmpty(NameID)) + { + Debug.LogWarning($"[{GUIType}]: NameID Should Not be Empty"); + return false; + } + + switch (GUIType) + { + // ----------- SIMPLE TEXT ELEMENTS ----------- + case BuiltInGUIType.Label: + return !string.IsNullOrEmpty(Text); + + case BuiltInGUIType.TextField: + case BuiltInGUIType.PasswordField: + case BuiltInGUIType.TextArea: + // These can draw even if empty text + return true; + + // ----------- BUTTONS & TOGGLES ----------- + case BuiltInGUIType.Button: + case BuiltInGUIType.RepeatButton: + case BuiltInGUIType.Toggle: + case BuiltInGUIType.Toolbar: + return !string.IsNullOrEmpty(Text); + + // ----------- SLIDERS & SCROLLBARS ----------- + case BuiltInGUIType.HorizontalSlider: + case BuiltInGUIType.VerticalSlider: + case BuiltInGUIType.HorizontalScrollbar: + case BuiltInGUIType.VerticalScrollbar: + return SliderMin < SliderMax; + + // ----------- CONTAINERS ALWAYS DRAW ----------- + case BuiltInGUIType.Group_Begin: + case BuiltInGUIType.Group_End: + case BuiltInGUIType.Clip_Begin: + case BuiltInGUIType.Clip_End: + case BuiltInGUIType.ScrollView_Begin: + case BuiltInGUIType.ScrollView_End: + return true; + + // ----------- SELECTION GRID ----------- + case BuiltInGUIType.SelectionGrid: + //return Options != null && Options.Length > 0; + return string.IsNullOrEmpty(Option); + + // ----------- BOX ----------- + case BuiltInGUIType.Box: + return !string.IsNullOrEmpty(Title); + + // ----------- DRAW TEXTURE ----------- + case BuiltInGUIType.DrawTexture: + return Texture != null; + + // ----------- OTHER ----------- + + // ----------- DEFAULT (fallback) ----------- + default: + Debug.LogWarning($"Not Implement for {GUIType}"); + return false; + } + } + void IDraw.Draw(int Index) + { + Rect Position = window.GetRect(Transform, Index); + GUIStyle Style = GetStyle(); + + switch (GUIType) + { + // ---------------- BASIC CONTROLS ---------------- + case BuiltInGUIType.Label: + if (UseMember) + { + GUI.Label(Position, GetMemberValue().ToString(), Style); + } + else + { + GUI.Label(Position, Text, Style); + } + break; + + case BuiltInGUIType.Button: + if (GUI.Button(Position, Title, Style)) + { + if (UseMember) + InvokeMemberMethod(); + window.OnButtonClick(NameID); + } + break; + + case BuiltInGUIType.RepeatButton: + if (GUI.RepeatButton(Position, Title, Style)) + { + if (UseMember) + InvokeMemberMethod(); + window.OnButtonClick(NameID); + } + break; + + case BuiltInGUIType.Toggle: + bool result = GUI.Toggle(Position, Toggle, Title, Style); + if (result != Toggle) + { + if (UseMember) + InvokeMemberMethod(result); + window.OnToggleChange(NameID, result); + } + Toggle = result; + break; + + case BuiltInGUIType.TextField: + if (UseMember) + { + Text = GUI.TextField(Position, GetMemberValue().ToString(), Style); + } + else + { + Text = GUI.TextField(Position, Text, Style); + } + break; + + case BuiltInGUIType.PasswordField: + if (UseMember) + { + Text = GUI.PasswordField(Position, GetMemberValue().ToString(), '*', Style); + } + else + { + Text = GUI.PasswordField(Position, Text, '*', Style); + } + break; + + case BuiltInGUIType.TextArea: + if (UseMember) + { + Text = GUI.TextArea(Position, GetMemberValue().ToString(), Style); + } + else + { + Text = GUI.TextArea(Position, Text, Style); + } + break; + + // ---------------- SLIDERS / SCROLLBARS ---------------- + case BuiltInGUIType.HorizontalSlider: + Slider = GUI.HorizontalSlider(Position, Slider, SliderMin, SliderMax); + break; + + case BuiltInGUIType.VerticalSlider: + Slider = GUI.VerticalSlider(Position, Slider, SliderMin, SliderMax); + break; + + case BuiltInGUIType.HorizontalScrollbar: + Slider = GUI.HorizontalScrollbar(Position, Slider, ScrollSize, SliderMin, SliderMax); + break; + + case BuiltInGUIType.VerticalScrollbar: + Slider = GUI.VerticalScrollbar(Position, Slider, ScrollSize, SliderMin, SliderMax); + break; + + // ---------------- CONTAINERS ---------------- + case BuiltInGUIType.Box: + GUI.Box(Position, Title, Style); + break; + + case BuiltInGUIType.Group_Begin: + GUI.BeginGroup(Position, Style); + break; + + case BuiltInGUIType.Group_End: + GUI.EndGroup(); + break; + + case BuiltInGUIType.Clip_Begin: + GUI.BeginClip(Position); + break; + + case BuiltInGUIType.Clip_End: + GUI.EndClip(); + break; + + // ---------------- SCROLL VIEW ---------------- + case BuiltInGUIType.ScrollView_Begin: + scrollPos = GUI.BeginScrollView( + Position, + scrollPos, + new Rect(0, 0, ContentSize.x, ContentSize.y), + false, + true + ); + break; + + case BuiltInGUIType.ScrollView_End: + GUI.EndScrollView(); + break; + + // ---------------- COMPLEX CONTROLS ---------------- + case BuiltInGUIType.SelectionGrid: + SelectedIndex = GUI.SelectionGrid(Position, SelectedIndex, new string[1] { Option }, Columns, Style); + break; + + case BuiltInGUIType.DrawTexture: + GUI.DrawTexture(Position, Texture, ScaleMode.ScaleToFit, true); + break; + + case BuiltInGUIType.Toolbar: + SelectedIndex = GUI.Toolbar(Position, SelectedIndex, new string[1] { Option }, Style); + break; + + // ---------------- FALLBACK ---------------- + default: + Debug.LogWarning($"GUI Type {GUIType} not implemented."); + break; + } + } + + // Functions + public void Active(GUIAsset owner) + { + window = owner; + } + public void Deactive() + { + window = null; + } + public void OnValidate(int Index) + { + if (string.IsNullOrEmpty(NameID)) + NameID = Index.ToString(); + + if (string.IsNullOrEmpty(memberName)) + memberName = NameID; + + if ((int)GUIType > 6) + { + UseMember = false; + } + + if (Reset == true) + { + Reset = false; + Transform = GetDefaultRect(GUIType); + //Title = string.Empty; + //Text = string.Empty; + Toggle = false; + Slider = 0; + SliderMin = 0; + SliderMax = 1; + ScrollSize = 0.1f; + scrollPos = Vector2.zero; + ContentSize = new Vector2(500, 500); + SelectedIndex = 0; + //Option = string.Empty; + Columns = 2; + //Texture = null; + } + + if (SliderMax == 0) + SliderMax = 1; + if (ScrollSize == 0) + ScrollSize = 0.1f; + if (ContentSize.x == 0) + ContentSize.x = 500; + if (ContentSize.y == 0) + ContentSize.y = 500; + if (Columns == 0) + Columns = 2; + } + + // Methods + private GUIStyle GetStyle() + { + switch (StyleMode) + { + case GUIStyleMode.Skin: + switch (GUIType) + { + case BuiltInGUIType.Label: return GUI.skin.label; + case BuiltInGUIType.Box: return GUI.skin.box; + case BuiltInGUIType.Button: return GUI.skin.button; + case BuiltInGUIType.Toggle: return GUI.skin.toggle; + case BuiltInGUIType.TextField: return GUI.skin.textField; + case BuiltInGUIType.TextArea: return GUI.skin.textArea; + case BuiltInGUIType.HorizontalSlider: return GUI.skin.horizontalSlider; + case BuiltInGUIType.VerticalSlider: return GUI.skin.verticalSlider; + case BuiltInGUIType.HorizontalScrollbar: return GUI.skin.horizontalScrollbar; + case BuiltInGUIType.VerticalScrollbar: return GUI.skin.verticalScrollbar; + case BuiltInGUIType.ScrollView_Begin: return GUI.skin.scrollView; + default: return GUI.skin.label; + } + case GUIStyleMode.Custom_1: + return window.GetStyle(1); + case GUIStyleMode.Custom_2: + return window.GetStyle(2); + case GUIStyleMode.Custom_3: + return window.GetStyle(3); + case GUIStyleMode.None: + return new GUIStyle(); + default: + return null; + } + } + private Rect GetDefaultRect(BuiltInGUIType type) + { + switch (type) + { + // -------- TEXT / BASIC -------- + case BuiltInGUIType.Label: + return new Rect(10, 20, 120, 20); + + case BuiltInGUIType.Button: + case BuiltInGUIType.RepeatButton: + case BuiltInGUIType.Toggle: + return new Rect(10, 20, 120, 25); + + case BuiltInGUIType.TextField: + case BuiltInGUIType.PasswordField: + return new Rect(10, 20, 160, 22); + + case BuiltInGUIType.TextArea: + return new Rect(10, 20, 200, 80); + + // -------- SLIDERS -------- + case BuiltInGUIType.HorizontalSlider: + return new Rect(10, 20, 200, 20); + + case BuiltInGUIType.VerticalSlider: + return new Rect(10, 20, 20, 200); + + // -------- SCROLLBARS -------- + case BuiltInGUIType.HorizontalScrollbar: + return new Rect(10, 20, 200, 18); + + case BuiltInGUIType.VerticalScrollbar: + return new Rect(10, 20, 18, 200); + + // -------- CONTAINERS -------- + case BuiltInGUIType.Box: + return new Rect(10, 20, 200, 100); + + case BuiltInGUIType.Group_Begin: + return new Rect(10, 20, 300, 200); + + case BuiltInGUIType.Group_End: + return Rect.zero; + + case BuiltInGUIType.ScrollView_Begin: + return new Rect(10, 20, 300, 200); + + case BuiltInGUIType.ScrollView_End: + return Rect.zero; + + case BuiltInGUIType.Clip_Begin: + return new Rect(10, 20, 200, 150); + + case BuiltInGUIType.Clip_End: + return Rect.zero; + + // -------- COMPLEX CONTROLS -------- + case BuiltInGUIType.SelectionGrid: + return new Rect(10, 20, 250, 100); + + case BuiltInGUIType.Toolbar: + return new Rect(10, 20, 250, 25); + + // -------- TEXTURE -------- + case BuiltInGUIType.DrawTexture: + return new Rect(10, 20, 128, 128); + + default: + return new Rect(10, 20, 100, 25); + } + } + private Component GetComponent() + { + if (CachedComponent != null) + return CachedComponent; + + var Target = GameObject.Find(gameObjectName); + if (Target == null) + { + Debug.LogWarning($"GameObject '{gameObjectName}' not found."); + return null; + } + + CachedComponent = Target.GetComponent(componentType.Type); + if (CachedComponent == null) + Debug.LogWarning($"Component type '{componentType.Type}' not found."); + + return CachedComponent; + } + private object GetMemberValue() + { + Component SelectedComponent = GetComponent(); + + // Get Meember + Type type = componentType.Type; + FieldInfo Field = type.GetField(memberName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + if (Field != null) + { + return Field.GetValue(SelectedComponent); + } + + PropertyInfo Property = type.GetProperty(memberName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + if (Property != null) + { + return Property.GetValue(SelectedComponent); + } + + Debug.LogWarning($"Member '{memberName}' not found on component type '{SelectedComponent.GetType()}'."); + return null; + } + private void InvokeMemberMethod(params object[] arguments) + { + Type type = componentType.Type; + MethodInfo method = type.GetMethod(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + + if (method == null) + { + Debug.LogWarning($"Method '{memberName}' not found on '{type}'."); + return; + } + + Component SelectedComponent = GetComponent(); + method.Invoke(SelectedComponent, arguments); + } + } + + + [Header("Window")] + [SerializeField] + private bool WindowsForm = true; + [SerializeField, ConditionalHide("WindowsForm", true, false)] + private string Text = "Window"; + [SerializeField, ConditionalHide("WindowsForm", true, false)] + private Rect Position = new Rect(150, 50, 250, 150); + [SerializeField, ConditionalHide("WindowsForm", true, false)] + private bool Dragable = true; + [SerializeField, ConditionalHide("WindowsForm", true, false)] + private Rect DragBoundry = new Rect(0, 0, Screen.width, Screen.height); + [Header("Rendering")] + [SerializeField] + private GUIStyleData CustomStyle_1; + [SerializeField] + private GUIStyleData CustomStyle_2; + [SerializeField] + private GUIStyleData CustomStyle_3; + [Header("Items")] + [SerializeField, Tooltip("the value is the amount added per index step")] + private Vector2 StepOffset = Vector2.zero; + [SerializeField] + private DrawSlot[] DrawItems; + + + protected DeveloperManager manager { get; private set; } = null; + public bool IsActive => manager != null; + + + // Implement ITask Interface + void ITask.Active() + { + if (IsActive) + { + Debug.LogWarning($"This Asset({name}) already is active."); + return; + } + + manager = Game.GetManager(); + if (manager == null) + { + Debug.LogWarning($"Can't find {typeof(DeveloperManager)} for Asset({name})"); + } + + foreach (var item in DrawItems) + { + item.Active(this); + } + } + void ITask.Deactive() + { + foreach (var item in DrawItems) + { + item.Deactive(); + } + } + // Implement IDraw Interface + bool IDraw.CanDraw(int Index) + { + return DrawItems != null && DrawItems.Length > 0; + } + void IDraw.Draw(int Index) + { + if (WindowsForm) + { + Position = GUI.Window(Index, Position, OnWindowsDraw, Text); + } + else + { + Drawing(); + } + } + // Implement IDrawWindow Interface + public abstract void OnToggleChange(string ToggleName, bool Val); + public abstract void OnButtonClick(string ButtonName); + Rect IDrawWindow.GetRect(Rect element, int index) + { + if (StepOffset == Vector2.zero) + { + return element; + } + else + { + Vector2 offcet = StepOffset * index; + return new Rect(element.x + offcet.x, element.y + offcet.y, element.width, element.height); + } + } + GUIStyle IDrawWindow.GetStyle(int ID) + { + if (ID == 1) + return CustomStyle_1.Build(); + if (ID == 2) + return CustomStyle_2.Build(); + if (ID == 3) + return CustomStyle_3.Build(); + + Debug.LogWarning($"Din't implement any Style for ID: {ID}"); + return null; + } + + // Unity Method + private void OnValidate() + { + for (int i = 0; i < DrawItems.Length; i++) + { + DrawItems[i].OnValidate(i); + } + } + protected virtual void Reset() + { + manager = null; + } + + // Functions + public string GetTextItem(string nameID) + { + foreach (var item in DrawItems) + { + if (item.GUIType == BuiltInGUIType.TextField || item.GUIType == BuiltInGUIType.PasswordField || item.GUIType == BuiltInGUIType.TextArea) + { + if (item.NameID == nameID) + return item.Text; + } + } + return string.Empty; + } + public void SetTextItem(string nameID, string text) + { + foreach (var item in DrawItems) + { + if (item.GUIType == BuiltInGUIType.TextField || item.GUIType == BuiltInGUIType.PasswordField || item.GUIType == BuiltInGUIType.TextArea) + { + if (item.NameID == nameID) + { + item.Text = text; + return; + } + } + } + } + public bool HasItem(string nameID) + { + foreach (var item in DrawItems) + { + if (item.NameID == nameID) + return true; + } + return false; + } + public string[] GetItemList(BuiltInGUIType type) + { + List result = new List(); + foreach (var item in DrawItems) + { + if (item.GUIType == type) + { + result.Add(item.NameID); + } + } + return result.ToArray(); + } + + // Methods + private void Drawing() + { + for (int i = 0; i < DrawItems.Length; i++) + { + IDraw provider = DrawItems[i]; + if (provider.CanDraw(i)) + provider.Draw(i); + } + } + private void OnWindowsDraw(int id) + { + Drawing(); + if (Dragable) + GUI.DragWindow(DragBoundry); + } + + +#if UNITY_EDITOR + public override bool AutoReset(PlayModeStateChange state) + { + if (state == PlayModeStateChange.ExitingPlayMode) + return true; + return base.AutoReset(state); + } +#endif + } + + +} +#endif \ No newline at end of file diff --git a/Runtime/Pattern/Assets/GUIAsset.cs.meta b/Runtime/Pattern/Assets/GUIAsset.cs.meta new file mode 100644 index 00000000..4e988a6f --- /dev/null +++ b/Runtime/Pattern/Assets/GUIAsset.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 56f5ca6bda2e55547b50df8a3e272ffe \ No newline at end of file diff --git a/Runtime/Pattern/DataAssets/ItemConfig.cs b/Runtime/Pattern/Assets/ItemConfig.cs similarity index 91% rename from Runtime/Pattern/DataAssets/ItemConfig.cs rename to Runtime/Pattern/Assets/ItemConfig.cs index f4a4b30d..b128bf64 100644 --- a/Runtime/Pattern/DataAssets/ItemConfig.cs +++ b/Runtime/Pattern/Assets/ItemConfig.cs @@ -7,7 +7,6 @@ public abstract class ItemConfig : ConfigAsset, IItem [Header("Item")] [SerializeField] protected string itemName; - public string NameID => itemName; [SerializeField] protected Texture2D _icon; public Texture2D Icon => _icon; @@ -34,7 +33,7 @@ Sprite IItem.GetSpriteIcon(Rect rect, Vector2 pivot) #if UNITY_EDITOR - void IItem.ChangeItemName(string NewName) + void IItem.SetItemName(string NewName) { itemName = NewName; } diff --git a/Runtime/Pattern/DataAssets/ItemConfig.cs.meta b/Runtime/Pattern/Assets/ItemConfig.cs.meta similarity index 100% rename from Runtime/Pattern/DataAssets/ItemConfig.cs.meta rename to Runtime/Pattern/Assets/ItemConfig.cs.meta diff --git a/Runtime/Pattern/DesignPatterns/PoolAsset.cs b/Runtime/Pattern/Assets/PoolAsset.cs similarity index 85% rename from Runtime/Pattern/DesignPatterns/PoolAsset.cs rename to Runtime/Pattern/Assets/PoolAsset.cs index 406e58ec..c02e2432 100644 --- a/Runtime/Pattern/DesignPatterns/PoolAsset.cs +++ b/Runtime/Pattern/Assets/PoolAsset.cs @@ -2,6 +2,10 @@ using System.Collections.Generic; using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + namespace RealMethod { public class PoolComponent : MonoBehaviour @@ -172,43 +176,22 @@ private void CallPoolBackEvent(T Target, IEnumerator Corotine) protected abstract T CreateObject(); protected abstract IEnumerator PostProcess(T Comp); + protected virtual void Reset() + { + Prewarmed = false; + } + #if UNITY_EDITOR - // Base DataAsset Methods - public override void OnEditorPlay() + public override bool AutoReset(PlayModeStateChange state) { - //base.OnEditorPlay(); - Prewarmed = false; + if (state == PlayModeStateChange.ExitingPlayMode) + return true; + + return base.AutoReset(state); } #endif } - - public interface IPool - { - void Prewarm(int amount = 1); - IEnumerator PrewarmEachFrame(int amount = 1); - void Request(); - void Return(int amount = 1); - void Remove(int amount = 1, bool Force = false); - void Clean(); - } - public interface IPool : IPool - { - IEnumerable Request(int amount = 1); - } - public interface IPoolSpawner where J : Component - { - J Spawn(Vector3 location, Quaternion rotation, Vector3 scale); - J Spawn(Vector3 location, Quaternion rotation); - J Spawn(Vector3 location); - J Spawn(); - } - public interface IPoolDespawner where J : Component - { - void Despawn(); - void Despawn(J target); - } - } diff --git a/Runtime/Pattern/DesignPatterns/PoolAsset.cs.meta b/Runtime/Pattern/Assets/PoolAsset.cs.meta similarity index 100% rename from Runtime/Pattern/DesignPatterns/PoolAsset.cs.meta rename to Runtime/Pattern/Assets/PoolAsset.cs.meta diff --git a/Runtime/Pattern/DataAssets/ResourcAsset.cs b/Runtime/Pattern/Assets/ResourcAsset.cs similarity index 95% rename from Runtime/Pattern/DataAssets/ResourcAsset.cs rename to Runtime/Pattern/Assets/ResourcAsset.cs index a897ef56..529d64ad 100644 --- a/Runtime/Pattern/DataAssets/ResourcAsset.cs +++ b/Runtime/Pattern/Assets/ResourcAsset.cs @@ -2,6 +2,10 @@ using System.Threading.Tasks; using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + namespace RealMethod { public abstract class ResourcAsset : DataAsset @@ -144,11 +148,18 @@ private IEnumerator LoadRoutine(System.Action result) } -#if UNITY_EDITOR - public override void OnEditorPlay() + private void Reset() { Asset = null; } + +#if UNITY_EDITOR + public override bool AutoReset(PlayModeStateChange state) + { + if (PlayModeStateChange.ExitingPlayMode == state) + return true; + return base.AutoReset(state); + } #endif } diff --git a/Runtime/Pattern/DataAssets/ResourcAsset.cs.meta b/Runtime/Pattern/Assets/ResourcAsset.cs.meta similarity index 100% rename from Runtime/Pattern/DataAssets/ResourcAsset.cs.meta rename to Runtime/Pattern/Assets/ResourcAsset.cs.meta diff --git a/Runtime/Pattern/Assets/SaveAsset.cs b/Runtime/Pattern/Assets/SaveAsset.cs new file mode 100644 index 00000000..c5a6f332 --- /dev/null +++ b/Runtime/Pattern/Assets/SaveAsset.cs @@ -0,0 +1,143 @@ + +using UnityEditor; +#if UNITY_EDITOR +using UnityEngine; +#endif + +namespace RealMethod +{ + public interface ISaveFile : IFile, ISaveable + { + void SetName(string NewName); + } + + public abstract class SaveFileAsset : FileAsset, ISaveFile + { + // Implement ISave Interface + void ISaveable.OnLoaded() + { + OnLoaded(); + } + void ISaveable.OnSaved() + { + OnSaved(); + } + // Implement ISaveFile Interface + void ISaveFile.SetName(string NewName) + { + Debug.LogWarning($"Can't change Name for Asset({name}). the SaveAsset get asset name for file naming"); + } + + + // Unity Method + protected virtual void OnEnable() + { +#if !UNITY_EDITOR + ISaveSystem saveSystem = Game.GetService(); + if (saveSystem != null) + { + if (!saveSystem.HasFile(this)) + saveSystem.AddFile(this); + }else + { + Debug.LogError("Can't find SaveSystem"); + } +#endif + } + protected virtual void OnDisable() + { +#if !UNITY_EDITOR + ISaveSystem saveSystem = Game.GetService(); + if (saveSystem != null) + { + if (saveSystem.HasFile(this)) + saveSystem.RemoveFile(this); + } + else + { + Debug.LogError("Can't find SaveSystem"); + } +#endif + } + protected virtual void Reset() + { +#if UNITY_EDITOR + IStorageService saveSystem = Game.GetService(); + if (saveSystem != null) + { + if (!saveSystem.HasFile(this)) + saveSystem.AddFile(this); + } + else + { + Debug.LogError("Can't find SaveSystem"); + } +#endif + } + + + protected abstract void OnLoaded(); + protected abstract void OnSaved(); + +#if UNITY_EDITOR + public override bool AutoReset(PlayModeStateChange state) + { + if (state == PlayModeStateChange.EnteredPlayMode) + return true; + return base.AutoReset(state); + } + [ContextMenu("Save")] + private void Editor_SaveSelf() + { + var manager = Game.GetService(); + if (manager != null) + { + manager.Save(this); + } + else + { + Debug.LogError($"No {typeof(IStorageService)} found in the scene."); + } + } + [ContextMenu("Load")] + private void Editor_LoadSelf() + { + var manager = Game.GetService(); + if (manager != null) + { + manager.Load(this); + } + else + { + Debug.LogError($"No {typeof(IStorageService)} found in the scene."); + } + } + [ContextMenu("Delete")] + private void Editor_Delete() + { + var manager = Game.GetService(); + if (manager != null) + { + manager.Delete(this); + } + else + { + Debug.LogError($"No {typeof(IStorageService)} found in the scene."); + } + } + [ContextMenu("IsExist")] + private void Editor_IsExist() + { + var manager = Game.GetService(); + if (manager != null) + { + Debug.Log($"[{name}] IsExist: {manager.IsExist(this)}"); + } + else + { + Debug.LogError($"No {typeof(IStorageService)} found in the scene."); + } + } +#endif + } +} \ No newline at end of file diff --git a/Runtime/Pattern/Assets/SaveAsset.cs.meta b/Runtime/Pattern/Assets/SaveAsset.cs.meta new file mode 100644 index 00000000..5b0314eb --- /dev/null +++ b/Runtime/Pattern/Assets/SaveAsset.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 480d36d987d58bf4c9bfae34e36a02bf \ No newline at end of file diff --git a/Runtime/Pattern/DesignPatterns/SharedRootAsset.cs b/Runtime/Pattern/Assets/SharedRootAsset.cs similarity index 100% rename from Runtime/Pattern/DesignPatterns/SharedRootAsset.cs rename to Runtime/Pattern/Assets/SharedRootAsset.cs diff --git a/Runtime/Pattern/DesignPatterns/SharedRootAsset.cs.meta b/Runtime/Pattern/Assets/SharedRootAsset.cs.meta similarity index 100% rename from Runtime/Pattern/DesignPatterns/SharedRootAsset.cs.meta rename to Runtime/Pattern/Assets/SharedRootAsset.cs.meta diff --git a/Runtime/Pattern/DataAssets/TableAsset.cs b/Runtime/Pattern/Assets/TableAsset.cs similarity index 100% rename from Runtime/Pattern/DataAssets/TableAsset.cs rename to Runtime/Pattern/Assets/TableAsset.cs diff --git a/Runtime/Pattern/DataAssets/TableAsset.cs.meta b/Runtime/Pattern/Assets/TableAsset.cs.meta similarity index 100% rename from Runtime/Pattern/DataAssets/TableAsset.cs.meta rename to Runtime/Pattern/Assets/TableAsset.cs.meta diff --git a/Runtime/Pattern/DesignPatterns/Command.cs b/Runtime/Pattern/Components/Command.cs similarity index 50% rename from Runtime/Pattern/DesignPatterns/Command.cs rename to Runtime/Pattern/Components/Command.cs index ccdb5d8f..2b6dfc02 100644 --- a/Runtime/Pattern/DesignPatterns/Command.cs +++ b/Runtime/Pattern/Components/Command.cs @@ -2,21 +2,19 @@ namespace RealMethod { - // A base command you can execute immediately. - public interface ICommand + + [System.Serializable] + public class CPrefab : PrefabCore { - bool Initiate(Object author, Object owner); - void ExecuteCommand(object Executer); - } - + } // Base Command public abstract class Command : MonoBehaviour, ICommand { // Implement ICommand Interface - bool ICommand.Initiate(Object author, Object owner) + bool ICommand.Initiate(Object owner) { - return OnInitiate(author, owner); + return OnInitiate(owner); } void ICommand.ExecuteCommand(object Executer) { @@ -27,15 +25,10 @@ void ICommand.ExecuteCommand(object Executer) } // Abstract Methods - protected abstract bool OnInitiate(Object author, Object owner); - protected abstract void Execute(object Owner); - protected abstract bool CanExecute(object Owner); + protected abstract bool OnInitiate(Object owner); + protected abstract void Execute(object Executer); + protected abstract bool CanExecute(object Executer); } - [System.Serializable] - public class CPrefab : PrefabCore - { - - } } \ No newline at end of file diff --git a/Runtime/Pattern/DesignPatterns/Command.cs.meta b/Runtime/Pattern/Components/Command.cs.meta similarity index 100% rename from Runtime/Pattern/DesignPatterns/Command.cs.meta rename to Runtime/Pattern/Components/Command.cs.meta diff --git a/Runtime/Pattern/Components/WidgetToolkit.cs b/Runtime/Pattern/Components/WidgetToolkit.cs index 967e9c71..70ca721e 100644 --- a/Runtime/Pattern/Components/WidgetToolkit.cs +++ b/Runtime/Pattern/Components/WidgetToolkit.cs @@ -12,7 +12,7 @@ public abstract class WidgetToolkit : MonoBehaviour, IWidget public UIDocument Design { get; private set; } public VisualElement Canvas => Design.rootVisualElement; - protected Hictionary Pages; + protected NameTable Pages; public VisualElement this[string Name] @@ -32,7 +32,7 @@ void IWidget.SceneInitialized(UIManager manager) Design = GetComponent(); - Pages = new Hictionary(); + Pages = new NameTable(); List allElement = Canvas.Query().ToList(); foreach (var ElmName in PageNames) { diff --git a/Runtime/Pattern/DataAssets/ItemAsset.cs b/Runtime/Pattern/DataAssets/ItemAsset.cs deleted file mode 100644 index 591e2859..00000000 --- a/Runtime/Pattern/DataAssets/ItemAsset.cs +++ /dev/null @@ -1,44 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public abstract class ItemAsset : DataAsset, IItem - { - [Header("Item")] - [SerializeField] - protected string itemName; - public string NameID => itemName; - [SerializeField] - protected Texture2D _icon; - public Texture2D Icon => _icon; - - // Implement IItemData Interface - public Sprite GetSpriteIcon() - { - return GetSpriteIcon(new Rect(0, 0, _icon.width, _icon.height), - new Vector2(0.5f, 0.5f) - ); - } - public Sprite GetSpriteIcon(Rect rect, Vector2 pivot) - { - if (_icon != null) - { - return Sprite.Create(_icon, rect, pivot); - } - else - { - Debug.LogWarning("ItemAsset: Icon is not assigned for item '" + itemName + "'."); - return null; - } - } - - -#if UNITY_EDITOR - void IItem.ChangeItemName(string NewName) - { - itemName = NewName; - } -#endif - - } -} \ No newline at end of file diff --git a/Runtime/Pattern/DataAssets/ItemAsset.cs.meta b/Runtime/Pattern/DataAssets/ItemAsset.cs.meta deleted file mode 100644 index 7f41f579..00000000 --- a/Runtime/Pattern/DataAssets/ItemAsset.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: d9e96fd8f2ec59d45a61cdc750523d5e \ No newline at end of file diff --git a/Runtime/Pattern/DesignPatterns.meta b/Runtime/Pattern/DesignPatterns.meta deleted file mode 100644 index 14b73428..00000000 --- a/Runtime/Pattern/DesignPatterns.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 745627a11c3491948b5aa84eab895d79 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Pattern/DesignPatterns/SharedDataAsset.cs b/Runtime/Pattern/DesignPatterns/SharedDataAsset.cs deleted file mode 100644 index 6498c1db..00000000 --- a/Runtime/Pattern/DesignPatterns/SharedDataAsset.cs +++ /dev/null @@ -1,160 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - // SharedDataAsset is a asset that can sore data by diffrent type - public abstract class SharedDataAsset : UniqueAsset, IBlackboard - { - [System.Serializable] - private class BB_Vector2_Dictionary : SerializableDictionary { } - [System.Serializable] - private class BB_Vector3_Dictionary : SerializableDictionary { } - [System.Serializable] - private class BB_Object_Dictionary : SerializableDictionary { } - [System.Serializable] - private class BB_Identity_Dictionary : SerializableDictionary { } - [Header("DataBase")] - [SerializeField, ReadOnly] - private StringBoolDictionary boolData; - [SerializeField, ReadOnly] - private StringByteDictionary byteData; - [SerializeField, ReadOnly] - private StringIntDictionary intData; - [SerializeField, ReadOnly] - private StringFloatDictionary floatData; - [SerializeField, ReadOnly] - private BB_Vector2_Dictionary vector2Data; - [SerializeField, ReadOnly] - private BB_Vector3_Dictionary vector3Data; - [SerializeField, ReadOnly] - private BB_Object_Dictionary objectData; - [SerializeField, ReadOnly] - private StringAssetObjectDictionary assetData; - [SerializeField, ReadOnly] - private BB_Identity_Dictionary idData; - - - public IBlackboard Provider => this; - public System.Action OnBlackBoardChanged; - public System.Action OnValueChanged; - - - - // Implement IBlackboardPure Interface - public void SetBool(string name, bool target) - { - SetValue(boolData, name, target); - } - public bool GetBool(string name) - { - return GetValue(boolData, name); - } - public void SetByte(string name, byte target) - { - SetValue(byteData, name, target); - } - public byte GetByte(string name) - { - return GetValue(byteData, name); - } - public void SetInt(string name, int target) - { - SetValue(intData, name, target); - } - public int GetInt(string name) - { - return GetValue(intData, name); - } - public void SetFloat(string name, float target) - { - SetValue(floatData, name, target); - } - public float GetFloat(string name) - { - return GetValue(floatData, name); - } - - // Implement IBlackboardUnity Interface - public void SetVector2(string name, Vector2 target) - { - SetValue(vector2Data, name, target); - } - public Vector2 GetVector2(string name) - { - return GetValue(vector2Data, name); - } - public void SetVector3(string name, Vector3 target) - { - SetValue(vector3Data, name, target); - } - public Vector3 GetVector3(string name) - { - return GetValue(vector3Data, name); - } - public void SetObject(string name, Object target) - { - SetValue(objectData, name, target); - } - public Object GetObject(string name) - { - return GetValue(objectData, name); - } - - // Implement IBlackboard Interface - public void SetIdentity(string name, IIdentifier target) - { - SetValue(idData, name, target); - } - public IIdentifier GetIdentity(string name) - { - return GetValue(idData, name); - } - public void SetAsset(string name, PrimitiveAsset target) - { - SetValue(assetData, name, target); - } - public PrimitiveAsset GetAsset(string name) - { - return GetValue(assetData, name); - } - - - - protected void SetValue(SerializableDictionary dic, string name, TValue value) - { - dic.Add(name, value); - OnBlackBoardChanged?.Invoke(Provider); - OnValueChanged?.Invoke(name); - } - protected TValue GetValue(SerializableDictionary dic, string name) - { - if (dic.TryGetValue(name, out TValue val)) - { - return val; - } - else - { - Debug.LogWarning($"[{name}]: Variable With name '{name}' didn't find in DataBase"); - return default; - } - } - - -#if UNITY_EDITOR - public override void OnEditorPlay() - { - boolData.Clear(); - byteData.Clear(); - intData.Clear(); - floatData.Clear(); - vector2Data.Clear(); - vector3Data.Clear(); - objectData.Clear(); - assetData.Clear(); - idData.Clear(); - } -#endif - - - } -} \ No newline at end of file diff --git a/Runtime/Pattern/Managers/AudioManager.cs b/Runtime/Pattern/Managers/AudioManager.cs index e075c0bc..2191dc87 100644 --- a/Runtime/Pattern/Managers/AudioManager.cs +++ b/Runtime/Pattern/Managers/AudioManager.cs @@ -10,24 +10,22 @@ public abstract class AudioManager : MixerManager { [Header("Audio")] [SerializeField] - private AudioMixerGroup DefaultGroup; - public AudioMixerGroup defaultGroup => DefaultGroup; + private AudioMixerGroup defaultGroup; + public AudioMixerGroup DefaultGroup => defaultGroup; public ObjectPool soundPool; - protected override void InitiateManager(bool AlwaysLoaded) + // Manager + public override void InitiateManager(Scope owner) { - if (AlwaysLoaded) + base.InitiateManager(owner); + + if (owner.IsGameScope()) { Debug.LogError("You can't use AudioManager in [Game] Scope"); return; } - if (CanBringtoSpawn() && Game.TryFindService(out Spawn SpawnServ)) - { - SpawnServ.BringManager(this); - } - soundPool = new ObjectPool( createFunc: CreateSource, actionOnGet: OnTakeSource, @@ -35,15 +33,7 @@ protected override void InitiateManager(bool AlwaysLoaded) actionOnDestroy: OnDestroySource, collectionCheck: false, defaultCapacity: 10, - maxSize: 500 - ); - } - protected override void InitiateService(Service service) - { - if (CanBringtoSpawn() && service is Spawn SpawnServ) - { - SpawnServ.BringManager(this); - } + maxSize: 500); } // Public Functions @@ -51,7 +41,7 @@ public AudioSource PlaySound(AudioClip clip, Vector3 location, Transform parent { AudioSource source = soundPool.Get(); source.clip = clip; - source.outputAudioMixerGroup = group != null ? group : DefaultGroup; + source.outputAudioMixerGroup = group != null ? group : defaultGroup; source.spatialBlend = 1; source.minDistance = rolloffDistanceMin; source.loop = loop; @@ -75,7 +65,7 @@ public AudioSource PlaySound2D(AudioClip clip, AudioMixerGroup group = null, flo { AudioSource source = soundPool.Get(); source.clip = clip; - source.outputAudioMixerGroup = group != null ? group : DefaultGroup; + source.outputAudioMixerGroup = group != null ? group : defaultGroup; source.spatialBlend = 0; source.minDistance = rolloffDistanceMin; source.loop = loop; @@ -121,9 +111,6 @@ private void OnDestroySource(AudioSource source) Destroy(source.gameObject); } - // Abstract Methods - protected abstract bool CanBringtoSpawn(); - // Enumerator Methods private IEnumerator PauseAfterSecond(AudioSource source, float time) { diff --git a/Runtime/Pattern/Managers/CompositManager.cs b/Runtime/Pattern/Managers/CompositManager.cs index d59914b1..1a632c47 100644 --- a/Runtime/Pattern/Managers/CompositManager.cs +++ b/Runtime/Pattern/Managers/CompositManager.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -33,13 +32,37 @@ public void Pitch(float alpha, float minPitch = -3f, float maxPitch = 3f) } [Header("Composit")] [SerializeField] + private Transform header; + [SerializeField] private AudioMixerGroup DefaultGroup; - private Hictionary Layers = new Hictionary(5); + protected NameTable Layers = new NameTable(5); public int LayerCount => Layers.Count; + // Override Methods + public override void InitiateManager(Scope owner) + { + base.InitiateManager(owner); + + foreach (Transform item in header) + { + AudioSource source = item.GetComponent(); + if (source != null) + { + if (!Layers.ContainsKey(item.name)) + { + Layers.Add(item.name, source); + } + else + { + Debug.LogWarning($"Layer '{item.name}' already exists in the manager."); + } + } + } + } + // Public Functions - public void PlayLayer(string layerName) + public void PlayLayer(Name16 layerName) { if (Layers.ContainsKey(layerName)) { @@ -58,7 +81,7 @@ public void PlayLayer(string layerName) Debug.LogWarning($"Layer '{layerName}' does not exist in the manager."); } } - public void PauseLayer(string layerName) + public void PauseLayer(Name16 layerName) { if (Layers.ContainsKey(layerName)) { @@ -77,25 +100,35 @@ public void PauseLayer(string layerName) Debug.LogWarning($"Layer '{layerName}' does not exist in the manager."); } } - public bool IsValidLayer(string layerName) + public void Pause() + { + foreach (var layer in Layers) + { + if (layer.Value is AudioSource source) + { + source.Pause(); + } + } + } + public bool IsValidLayer(Name16 layerName) { return Layers.ContainsKey(layerName); } - public void AddLayer(string layerName, APrefab prefab) + public void AddLayer(Name16 layerName, APrefab prefab) { if (IsValidLayer(layerName)) { Debug.LogWarning($"Layer '{layerName}' already exists. Use a different name."); return; } - AudioSource source = Instantiate(prefab.asset, transform).GetComponent(); + AudioSource source = Instantiate(prefab, header).GetComponent(); Layers.Add(layerName, source); } public void CreateLayer(AudioClip clip) { CreateLayer(clip.name, clip); } - public void CreateLayer(string layerName, AudioClip clip) + public void CreateLayer(Name16 layerName, AudioClip clip) { if (IsValidLayer(layerName)) { @@ -103,7 +136,7 @@ public void CreateLayer(string layerName, AudioClip clip) return; } GameObject SoundObject = new GameObject("Layer_" + clip.name, new Type[1] { typeof(AudioSource) }); - SoundObject.transform.SetParent(transform); + SoundObject.transform.SetParent(header); AudioSource source = SoundObject.GetComponent(); source.clip = clip; source.outputAudioMixerGroup = DefaultGroup; @@ -113,7 +146,7 @@ public void CreateLayer(string layerName, AudioClip clip) source.loop = true; Layers.Add(layerName, source); } - public void RemoveLayer(string layerName) + public void RemoveLayer(Name16 layerName) { if (Layers.ContainsKey(layerName)) { @@ -125,14 +158,14 @@ public void RemoveLayer(string layerName) Debug.LogWarning($"Layer '{layerName}' does not exist in the manager."); } } - public void FadeInLayer(string layerName, float duration) + public void FadeInLayer(Name16 layerName, float duration) { if (Layers.ContainsKey(layerName)) { AudioSource source = Layers[layerName] as AudioSource; if (source != null) { - StartCoroutine(FadeIn(source, duration)); + StartCoroutine(RM_Audio.FadeIn(source, duration)); } else { @@ -144,14 +177,14 @@ public void FadeInLayer(string layerName, float duration) Debug.LogWarning($"Cannot fade in layer: {layerName} not found."); } } - public void FadeOutLayer(string layerName, float duration) + public void FadeOutLayer(Name16 layerName, float duration) { if (Layers.ContainsKey(layerName)) { AudioSource source = Layers[layerName] as AudioSource; if (source != null) { - StartCoroutine(FadeOut(source, duration)); + StartCoroutine(RM_Audio.FadeOut(source, duration)); } else { @@ -163,7 +196,7 @@ public void FadeOutLayer(string layerName, float duration) Debug.LogWarning($"Cannot fade out layer: {layerName} not found."); } } - public void CrossfadeLayer(string layerA, string layerB, float duration) + public void CrossfadeLayer(Name16 layerA, Name16 layerB, float duration) { if (Layers.ContainsKey(layerA) && Layers.ContainsKey(layerB)) { @@ -171,8 +204,8 @@ public void CrossfadeLayer(string layerA, string layerB, float duration) AudioSource sourceB = Layers[layerB] as AudioSource; if (sourceA != null && sourceB != null) { - StartCoroutine(FadeIn(sourceB, duration)); - StartCoroutine(FadeOut(sourceA, duration)); + StartCoroutine(RM_Audio.FadeIn(sourceB, duration)); + StartCoroutine(RM_Audio.FadeOut(sourceA, duration)); } else { @@ -184,11 +217,22 @@ public void CrossfadeLayer(string layerA, string layerB, float duration) Debug.LogWarning($"Cannot crossfade layers: {layerA} or {layerB} not found."); } } - public void TransitionToSnapshot(AudioMixerSnapshot snapshot, float transitionTime = 1f) + public AudioSource[] GetActiveLayers() { - snapshot?.TransitionTo(transitionTime); + List Result = new List(); + foreach (var layer in Layers) + { + if (layer.Value is AudioSource source) + { + if (source.isPlaying) + { + Result.Add(source); + } + } + } + return Result.ToArray(); } - public T GetLayerComponent(string layerName) where T : AudioBehaviour + public T GetLayer(Name16 layerName) where T : AudioBehaviour { if (Layers.ContainsKey(layerName)) { @@ -200,7 +244,7 @@ public T GetLayerComponent(string layerName) where T : AudioBehaviour return null; } } - public AudioSource GetLayer(string layerName) + public AudioSource GetLayer(Name16 layerName) { if (Layers.ContainsKey(layerName)) { @@ -212,248 +256,140 @@ public AudioSource GetLayer(string layerName) return null; } } - public MusicLerp CreateLerp(string LayerA, string LayerB) - { - if (!Layers.ContainsKey(LayerA) || !Layers.ContainsKey(LayerB)) - { - Debug.LogWarning($"Cannot create lerp: {LayerA} or {LayerB} not found."); - return default; - } - return new MusicLerp((AudioSource)Layers[LayerA], (AudioSource)Layers[LayerB]); - } public AudioBehaviour[] GetLayers() { - return Layers.GetValues().ToArray(); - } - - // Protected Functions - protected void InitiateLayers() - { - foreach (Transform item in transform) - { - AudioSource source = item.GetComponent(); - if (source != null) - { - if (!Layers.ContainsKey(item.name)) - { - Layers.Add(item.name, source); - } - else - { - Debug.LogWarning($"Layer '{item.name}' already exists in the manager."); - } - } - } + return Layers.Values.ToArray(); } - // Enumerator - private IEnumerator FadeIn(AudioSource source, float duration) - { - source.Play(); - source.volume = 0f; // Start volume at 0 - float timer = 0f; - while (timer < duration) - { - float t = timer / duration; - source.volume = Mathf.Lerp(0f, 1f, t); - timer += Time.deltaTime; - yield return null; - } - source.volume = 1f; // Ensure volume is set to 1 at the end - } - private IEnumerator FadeOut(AudioSource source, float duration) + public MusicLerp CreateLerp(Name16 LayerA, Name16 LayerB) { - source.volume = 1f; // Start volume at 1 - float timer = 0f; - while (timer < duration) + if (!Layers.ContainsKey(LayerA) || !Layers.ContainsKey(LayerB)) { - float t = timer / duration; - source.volume = Mathf.Lerp(1f, 0f, t); - timer += Time.deltaTime; - yield return null; + Debug.LogWarning($"Cannot create lerp: {LayerA} or {LayerB} not found."); + return default; } - source.volume = 0f; // Ensure volume is set to 0 at the end - source.Stop(); + return new MusicLerp((AudioSource)Layers[LayerA], (AudioSource)Layers[LayerB]); } - } - - public abstract class CompositManager : CompositManager where T : StateService where J : Enum + public abstract class CompositManager : CompositManager { [Serializable] protected struct MusicState { [SerializeField] - private J State; - public J state => State; - [SerializeField] - private bool CrossWithPreviousState; - [Space] + private bool DeactivePreviousLayers; [SerializeField] - private string[] FadeInLayers; + private Name16[] ActiveLayers; [SerializeField] - private string[] FadeOutLayers; + private bool FadingMethod; + [SerializeField, ConditionalHide("FadingMethod", true, false)] + private float Duration; [Space] [SerializeField] + private bool ApplySnapshot; + [SerializeField, ConditionalHide("ApplySnapshot", true, false)] public AudioMixerSnapshot shot; - [SerializeField] - private float duration; - private CompositManager manager; - - public void Start(CompositManager owner) - { - manager = owner; - } - public void Run(MusicState previousState) + public void Play(CompositManager manager) { - if (manager == null) - { - return; - } - if (CrossWithPreviousState) + if (DeactivePreviousLayers) { - previousState.Reverse(); - } - if (FadeInLayers != null) - { - foreach (var layer in FadeInLayers) + AudioSource[] layers = manager.GetActiveLayers(); + foreach (var layer in layers) { - manager.FadeInLayer(layer, duration); + if (FadingMethod) + { + manager.StartCoroutine(RM_Audio.FadeOut(layer, Duration)); + } + else + { + layer.Stop(); + } + } } - if (FadeOutLayers != null) + + foreach (var layer in ActiveLayers) { - foreach (var layer in FadeOutLayers) + if (FadingMethod) { - manager.FadeOutLayer(layer, duration); + manager.FadeInLayer(layer, Duration); + } + else + { + manager.PauseLayer(layer); } } - if (shot != null) - { - manager.TransitionToSnapshot(shot, duration); - } - } - public void Reverse() - { - if (manager == null) - { - return; - } - if (FadeInLayers != null) + if (ApplySnapshot) { - foreach (var layer in FadeInLayers) - { - manager.FadeOutLayer(layer, duration); - } + manager.TransitionToSnapshot(shot, Duration); } } } - [Header("State")] + [field: SerializeField] + protected bool PlayOnStart { get; private set; } = true; + [field: SerializeField] + public T CurrentState { get; protected set; } [SerializeField] - private MusicState[] StateBehavior; - [SerializeField, Tooltip("Run the default state on initiate, if true, the 'FirstState' in the Service Class will be run Behavior.")] - private bool RunFirstState = false; + protected Map StateBehavior = new Map(); - protected T stateService; - public J currentState => stateService.GetCurrentState(); + public event Action OnMusicChange; - // IGameManager Interface Implementation - protected sealed override void InitiateManager(bool AlwaysLoaded) + // Unity + protected virtual void Start() { - InitiateLayers(); - OnInitiate(AlwaysLoaded); - InitiateMusicStates(); - if (Game.TryFindService(out stateService)) + if (PlayOnStart) { - stateService.OnStateUpdate += OnStateChanged; - if (RunFirstState) - { - if (IsValidState(currentState)) - { - GetMusicState(currentState).Run(default); - } - else - { - Debug.LogWarning($"First state '{currentState}' is not valid in the music state behavior."); - } - } - MusicStateAssigned(); + PlayState(CurrentState, false); } } - protected sealed override void InitiateService(Service service) + + // Public Functions + public void PlayState(T state, bool CompairState = true) { - if (stateService == null) + if (CompairState) { - if (service is T stateserv) + if (CompairStates(state, CurrentState)) { - stateService = stateserv; - stateService.OnStateUpdate += OnStateChanged; - if (IsValidState(currentState)) - { - GetMusicState(currentState).Run(default); - } - else - { - Debug.LogWarning($"First state '{currentState}' is not valid in the music state behavior."); - } - MusicStateAssigned(); + Debug.LogWarning($"State {state} already is playing"); + return; } } - } - - - // Protected Methods - protected virtual void OnStateChanged(StateService service) - { - J NewState = stateService.GetCurrentState(); - if (IsValidState(NewState)) + if (TryFindState(state, out MusicState Music)) { - MusicState NewMusicState = GetMusicState(NewState); - J LastState = stateService.GetPreviousState(); - MusicState LastMusicState = GetMusicState(LastState); - NewMusicState.Run(LastMusicState); + Music.Play(this); + CurrentState = state; + OnMusicChange?.Invoke(CurrentState); } - } - - // Private Methods - private void InitiateMusicStates() - { - List seen = new List(); - - for (int i = 0; i < StateBehavior.Length; i++) + else { - if (seen.Contains(StateBehavior[i].state)) - { - Debug.LogWarning($"Duplicate layer '{StateBehavior[i].state}' found at index {i} (already added at index {seen.IndexOf(StateBehavior[i].state)})"); - } - else - { - StateBehavior[i].Start(this); - seen.Add(StateBehavior[i].state); - } + Debug.LogWarning($"State ({state}) is not valid in the music state behavior."); } } - private bool IsValidState(J state) + public bool IsValidState(T TargetState) { - return StateBehavior.Any(s => s.state.Equals(state)); + return StateBehavior.ContainsKey(TargetState); } - private MusicState GetMusicState(J state) + + // Private Functions + protected bool TryFindState(T TargetState, out MusicState result) { - return StateBehavior.FirstOrDefault(s => s.state.Equals(state)); + if (StateBehavior.ContainsKey(TargetState)) + { + result = StateBehavior[TargetState]; + return true; + } + result = default; + return false; } - - //Abstract Method - protected abstract void OnInitiate(bool AlwaysLoaded); - protected abstract void MusicStateAssigned(); - + // Abstraction Methods + protected abstract bool CompairStates(T State_A, T State_B); } - } \ No newline at end of file diff --git a/Runtime/Pattern/Managers/DataManager.cs b/Runtime/Pattern/Managers/DataManager.cs deleted file mode 100644 index 4735aafe..00000000 --- a/Runtime/Pattern/Managers/DataManager.cs +++ /dev/null @@ -1,410 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public interface IDataFile - { - void InitiateFile(DataManager manager); - void FileLoaded(); - void FileSaved(); - void FileRemoved(); - } - public interface IStorage - { - void StorageCreated(Object author); - void StorageLoaded(Object author); - void StorageClear(); - } - [System.Serializable] - public struct StorageFile where T : IStorage where J : SaveFile - { - [SerializeField] - private bool UseCustomFile; - [SerializeField, ConditionalHide("UseCustomFile", true, false)] - private SaveFile _SaveFile; - public SaveFile file - { - get - { - if (_SaveFile == null) - { - if (!TryGetStorage(out cacheProvider)) - { - Debug.LogWarning($"{this}: Can't get Storage Interface Something is wrong in your 'CustomSavefile' or 'SaveFileClass'"); - return default; - } - } - return _SaveFile; - } - } - private T cacheProvider; - public T provider - { - get - { - if (cacheProvider == null) - { - if (!TryGetStorage(out cacheProvider)) - { - Debug.LogWarning($"{this}: Can't get Storage Interface Something is wrong in your 'CustomSavefile' or 'SaveFileClass'"); - return default; - } - } - return cacheProvider; - } - } - - - // Public Functions - public bool Load(Object author) - { - return Load(author, Game.FindManager()); - } - public bool Load(Object author, DataManager saveManager) - { - if (saveManager == null) - { - Debug.LogWarning($"{this}: Initiate faield we need DataManager"); - return false; - } - - if (saveManager.IsExistFile(file)) - { - saveManager.LoadFile(file); - provider.StorageLoaded(author); - return true; - } - else - { - provider.StorageCreated(author); - return false; - } - } - public void Clear() - { - provider.StorageClear(); - } - - // Private Functions - private bool TryGetStorage(out T _provider) - { - if (UseCustomFile) - { - if (_SaveFile is T customProvider) - { - _provider = customProvider; - return true; - } - else - { - Debug.LogWarning("Storage Interface not implemented in Customfile."); - UseCustomFile = false; - } - } - _SaveFile = ScriptableObject.CreateInstance(); - if (_SaveFile is T autoProvider) - { - _SaveFile.name = $"RM{typeof(J)}"; - _provider = autoProvider; - return true; - } - else - { - Debug.LogError($"Storage Interface not implemented in SaveFileType {typeof(J)}"); - _provider = default; - return false; - } - } - } - - - // DataMaanger Class - public abstract class DataManager : MonoBehaviour, IGameManager - { - - [Header("Basic")] - [SerializeField] - private bool LoadOnInitiate = true; - [SerializeField] - private SaveFile[] StableFiles; - - // Actions - public System.Action OnFileLoaded; - public System.Action OnFileSaved; - - public byte Logindex { get; private set; } - public string[] DataLog { get; private set; } - - // Operators - public SaveFile this[int Index] - { - get => StableFiles[Index]; - protected set => StableFiles[Index] = value; - } - - - - // Implement IGameManager Interface - MonoBehaviour IGameManager.GetManagerClass() - { - return this; - } - void IGameManager.InitiateManager(bool AlwaysLoaded) - { - Logindex = 0; - DataLog = new string[5]; - - foreach (var file in StableFiles) - { - file.provider.InitiateFile(this); - if (LoadOnInitiate) - { - if (IsExistFile(file)) - LoadFile(file); - } - } - } - void IGameManager.ResolveService(Service service, bool active) - { - InitiateService(service); - } - - - // Public Functions - public void Save() - { - if (StableFiles == null) - { - Debug.LogError("StableFiles is not valid"); - return; - } - foreach (var file in StableFiles) - { - if (file == null) - { - Debug.LogError("File is not valid"); - continue; - } - OnSaveFile(file); - file.provider.FileSaved(); - OnFileSaved?.Invoke(file); - } - } - public void SaveFile(int Index) - { - if (StableFiles.IsValidIndex(Index)) - { - SaveFile(StableFiles[Index]); - } - else - { - Debug.LogError("Invalid index passed to SaveFile: " + Index); - } - } - public void SaveFile(SaveFile file) - { - if (file == null) - { - Debug.LogError("File is not valid"); - return; - } - OnSaveFile(file); - file.provider.FileSaved(); - OnFileSaved?.Invoke(file); - } - public void Load() - { - if (StableFiles == null) - { - Debug.LogError("StableFiles is not valid"); - return; - } - foreach (var file in StableFiles) - { - if (file == null) - { - Debug.LogError("File Does not valid"); - continue; - } - OnLoadFile(file); - file.provider.FileLoaded(); - OnFileLoaded?.Invoke(file); - } - } - public void LoadFile(int Index) - { - if (StableFiles.IsValidIndex(Index)) - { - LoadFile(StableFiles[Index]); - } - else - { - Debug.LogError("Invalid index passed to LoadFile: " + Index); - } - } - public void LoadFile(SaveFile file) - { - if (file == null) - { - Debug.LogError("File Does not valid"); - return; - } - - OnLoadFile(file); - file.provider.FileLoaded(); - OnFileLoaded?.Invoke(file); - } - public void DeleteFile(int Index) - { - if (StableFiles.IsValidIndex(Index)) - { - DeleteFile(StableFiles[Index]); - } - else - { - Debug.LogError("Invalid index passed to DeleteFile: " + Index); - } - } - public void DeleteFile(SaveFile file) - { - if (file == null) - { - Debug.LogError("File Does not valid"); - return; - } - - OnDeleteFile(file); - file.provider.FileRemoved(); - } - public bool IsExistFile(int Index) - { - if (StableFiles.IsValidIndex(Index)) - { - return IsExistFile(StableFiles[Index]); - } - else - { - Debug.LogError("Invalid index passed to IsExistFile: " + Index); - return false; - } - } - public bool IsExistFile(SaveFile file) - { - if (file == null) - { - Debug.LogError("File Does not valid"); - return false; - } - return IsExist(file); - } - - - // Protected Function - protected void WriteLog(string message, SaveFile file) - { - if (Application.isPlaying && DataLog != null) - { - if (Logindex == 0) - { - DataLog[0] = $"{System.DateTime.Now} -- {file.name} -- {message}"; - Logindex++; - } - else - { - DataLog[Logindex % DataLog.Length] = $"{System.DateTime.Now} -- {file.name} -- {message}"; - Logindex++; - } - } - } - - - // Abstract Mehtod - protected abstract void InitiateService(Service service); - protected abstract bool IsExist(SaveFile targetfile); - protected abstract void OnDeleteFile(SaveFile targetfile); - protected abstract void OnSaveFile(SaveFile targetfile); - protected abstract void OnLoadFile(SaveFile targetfile); - } - - // Save File Class - public abstract class SaveFile : DataAsset, IDataFile - { - public IDataFile provider => this; - - // Implement IDataPersistence Interface - void IDataFile.InitiateFile(DataManager manager) - { - OnStable(manager); - } - void IDataFile.FileSaved() - { - OnSaved(); - } - void IDataFile.FileLoaded() - { - OnLoaded(); - } - void IDataFile.FileRemoved() - { - OnDeleted(); - } - - - protected abstract void OnStable(DataManager manager); - protected abstract void OnLoaded(); - protected abstract void OnSaved(); - protected abstract void OnDeleted(); - - -#if UNITY_EDITOR - [ContextMenu("ResetToDefault")] - private void Editor_BacktoDefault() - { - OnEditorPlay(); - } - [ContextMenu("Save")] - private void Editor_SaveSelf() - { - var manager = FindFirstObjectByType(); - if (manager != null) - { - manager.SaveFile(this); - } - else - { - Debug.LogError("No DataManager found in the scene."); - } - } - [ContextMenu("Load")] - private void Editor_LoadSelf() - { - var manager = FindFirstObjectByType(); - if (manager != null) - { - manager.LoadFile(this); - } - else - { - Debug.LogError("No DataManager found in the scene."); - } - } - [ContextMenu("Delete")] - private void Editor_Delete() - { - var manager = FindFirstObjectByType(); - if (manager != null) - { - manager.DeleteFile(this); - } - else - { - Debug.LogError("No DataManager found in the scene."); - } - } -#endif - - - - } - -} \ No newline at end of file diff --git a/Runtime/Pattern/Managers/DeveloperManager.cs b/Runtime/Pattern/Managers/DeveloperManager.cs new file mode 100644 index 00000000..58a0dc78 --- /dev/null +++ b/Runtime/Pattern/Managers/DeveloperManager.cs @@ -0,0 +1,248 @@ +#if UNITY_EDITOR || DEVELOPMENT_BUILD +using System.Linq; +using UnityEngine; +#if ENABLE_INPUT_SYSTEM +using UnityEngine.InputSystem; +#endif + +namespace RealMethod +{ + public abstract class DeveloperManager : MonoBehaviour, IGameManager + { + private enum VisiblityModes + { + [DescriptionEnum("WindowsAsset Draw in screen just with OnEnable & OnDisable Component")] + None, + [DescriptionEnum("WindowsAsset Draw in screen with Open() & Close() Functions")] + Manually, + [DescriptionEnum("WindowsAsset Draw in screen with Open & Close Button in Game")] + UI, + [DescriptionEnum("WindowsAsset Draw in screen with [~] Button(Toggle) in Keyboard")] + Input, + } + [Header("Developer")] + [SerializeField] + private Map GUIAssets = new Map(); + [Header("Setting")] + [SerializeField] + private bool isOpen = true; + public bool IsOpen => isOpen; + [SerializeField] + private VisiblityModes ControlMode; + [SerializeField, ConditionalShowByEnum("ControlMode", VisiblityModes.UI)] + private Dir9 ButtonPosition = Dir9.UpRight; + [SerializeField, ConditionalShowByEnum("ControlMode", VisiblityModes.UI)] + private Vector2 Scale = new Vector2(50, 30); + [SerializeField, ConditionalShowByEnum("ControlMode", VisiblityModes.UI)] + private float margin = 0.8f; + [SerializeField, ConditionalShowByEnum("ControlMode", VisiblityModes.Input)] + public InputSystemType inputSystem = InputSystemType.OldInputSystem; + [SerializeField, ConditionalShowByEnum("ControlMode", VisiblityModes.Input), ConditionalHideByEnum("inputSystem", InputSystemType.NewInputSystem)] + public KeyCode oldKey = KeyCode.BackQuote; +#if ENABLE_INPUT_SYSTEM + [SerializeField, ConditionalShowByEnum("ControlMode", VisiblityModes.Input), ConditionalHideByEnum("inputSystem", InputSystemType.OldInputSystem)] + public InputActionReference inputAction; +#endif + + public Rect ButtonRect => RM_GUI.GetButtonRect(ButtonPosition, Scale.x, Scale.y, margin); + + // Unity Methods + private void OnEnable() + { + if (ControlMode == VisiblityModes.Input && inputSystem == InputSystemType.NewInputSystem) + { +#if ENABLE_INPUT_SYSTEM + inputAction.action.Enable(); + inputAction.action.performed += OnUITrigger; +#endif + } + + + foreach (var Asset in GUIAssets) + { + ((ITask)Asset.Key).Active(); + } + } + void Update() + { + if (ControlMode == VisiblityModes.Input && inputSystem == InputSystemType.OldInputSystem) + { + if (Input.GetKeyDown(oldKey)) + { + TriggerVisiblity(); + } + } + } + private void OnGUI() + { + if (ControlMode == VisiblityModes.UI) + { + if (GUI.Button(ButtonRect, IsOpen ? "Open" : "Close")) + { + TriggerVisiblity(); + } + } + + if (IsOpen) + { + for (int i = 0; i < GUIAssets.Count; i++) + { + if (GUIAssets.GetValue(i) == false) + continue; + + IDraw task = GUIAssets.GetKey(i); + + if (task == null) + { + GUIAssets.Remove(i); + continue; + } + + if (task.CanDraw(i)) + task.Draw(i); + } + } + } + private void OnDisable() + { + if (ControlMode == VisiblityModes.Input && inputSystem == InputSystemType.NewInputSystem) + { +#if ENABLE_INPUT_SYSTEM + inputAction.action.performed -= OnUITrigger; + inputAction.action.Disable(); +#endif + } + + foreach (var Asset in GUIAssets) + { + ((ITask)Asset.Key).Deactive(); + } + } + + // Functions + public void SetVisisblityEnable(int Index) + { + if (Index < 0) + { + Debug.LogWarning("Index should not be less than 0 for Change Visisblity"); + return; + } + if (GUIAssets.Count > Index) + { + var key = GUIAssets.Keys.ElementAt(Index); + GUIAssets[key] = true; + } + else + { + Debug.LogWarning($"Can't Find Asset for Index {Index}"); + } + } + public void SetVisisblityDisable(int Index) + { + if (Index < 0) + { + Debug.LogWarning("Index should not be less than 0 for Change Visisblity"); + return; + } + if (GUIAssets.Count > Index) + { + var key = GUIAssets.Keys.ElementAt(Index); + GUIAssets[key] = false; + } + else + { + Debug.LogWarning($"Can't Find Asset for Index {Index}"); + } + } + public void SetVisisblityEnable(GUIAsset asset) + { + if (asset == null) + { + Debug.LogWarning("Asset is not valid for Change Visisblity"); + return; + } + if (GUIAssets.ContainsKey(asset)) + { + GUIAssets[asset] = true; + } + else + { + Debug.LogWarning($"Can't Find Asset for Index {asset}"); + } + } + public void SetVisisblityDisable(GUIAsset asset) + { + if (asset == null) + { + Debug.LogWarning("Asset is not valid for Change Visisblity"); + return; + } + if (GUIAssets.ContainsKey(asset)) + { + GUIAssets[asset] = false; + } + else + { + Debug.LogWarning($"Can't Find Asset for Index {asset}"); + } + } + public void Add(DrawAsset asset) + { + if (asset == null) + { + Debug.LogWarning("Can't Add Asset, in not valid!"); + return; + } + GUIAssets.Add(asset, true); + ((ITask)asset).Active(); + } + public bool Remove(GUIAsset asset) + { + for (int i = 0; i < GUIAssets.Count; i++) + { + GUIAsset target = GUIAssets.GetKey(i); + if (target == asset) + { + ((ITask)target).Deactive(); + return GUIAssets.Remove(target); + } + } + return false; + } + public void Open() + { + if (ControlMode == VisiblityModes.None) + return; + isOpen = true; + } + public void Close() + { + if (ControlMode == VisiblityModes.None) + return; + isOpen = false; + } + public void TriggerVisiblity() + { + if (IsOpen) + { + Close(); + } + else + { + Open(); + } + } + + // Abstract Methods +#if ENABLE_INPUT_SYSTEM + private void OnUITrigger(InputAction.CallbackContext context) + { + TriggerVisiblity(); + } +#endif + public abstract void InitiateManager(Scope owner); + } + + +} +#endif \ No newline at end of file diff --git a/Runtime/Pattern/Managers/DeveloperManager.cs.meta b/Runtime/Pattern/Managers/DeveloperManager.cs.meta new file mode 100644 index 00000000..6d999748 --- /dev/null +++ b/Runtime/Pattern/Managers/DeveloperManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 60721334d77f6f8478942a48479f8cfc \ No newline at end of file diff --git a/Runtime/Pattern/Managers/EnumeratorManager.cs b/Runtime/Pattern/Managers/EnumeratorManager.cs index 66ce41d9..67f87f3c 100644 --- a/Runtime/Pattern/Managers/EnumeratorManager.cs +++ b/Runtime/Pattern/Managers/EnumeratorManager.cs @@ -66,13 +66,9 @@ public MonoBehaviour GetManagerClass() { return this; } - void IGameManager.InitiateManager(bool AlwaysLoaded) + void IGameManager.InitiateManager(Scope owner) { - InitiateManager(AlwaysLoaded); - } - void IGameManager.ResolveService(Service service, bool active) - { - InitiateService(service); + InitiateManager(owner); } @@ -107,8 +103,7 @@ public void Stop(Coroutine coroutine) // Abstract Methods - protected abstract void InitiateManager(bool alwaysLoaded); - protected abstract void InitiateService(Service newService); + protected abstract void InitiateManager(Scope owner); } diff --git a/Runtime/Pattern/Managers/GizmoManager.cs b/Runtime/Pattern/Managers/GizmoManager.cs deleted file mode 100644 index 95db3f0d..00000000 --- a/Runtime/Pattern/Managers/GizmoManager.cs +++ /dev/null @@ -1,61 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public abstract class GizmoManager : MonoBehaviour, IGameManager - { - protected abstract class GUIRenderer - { - public abstract void Start(GizmoManager Manager); - public abstract bool CanRender(); - public abstract void Draw(); - } - - [Header("GUI")] - [SerializeField] private Vector2 defualtposition = new Vector2(10, 10); - public Vector2 DefualtPosition => defualtposition; - - - private GUIRenderer[] RenderBox; - - //IGameManager Interface - MonoBehaviour IGameManager.GetManagerClass() - { - return this; - } - void IGameManager.InitiateManager(bool AlwaysLoaded) - { - if (!AlwaysLoaded) - { - Debug.LogError("You can't use GUIManager in [World] Scope"); - Destroy(this); - } - - RenderBox = GetRenderSlots(); - foreach (var Renderer in RenderBox) - { - Renderer.Start(this); - } - } - - - private void OnGUI() - { - foreach (var Renderer in RenderBox) - { - if (Renderer.CanRender()) - { - Renderer.Draw(); - } - } - } - - - // Abstract Methods - public abstract void ResolveService(Service service, bool active); - protected abstract GUIRenderer[] GetRenderSlots(); - - - } -} - diff --git a/Runtime/Pattern/Managers/GizmoManager.cs.meta b/Runtime/Pattern/Managers/GizmoManager.cs.meta deleted file mode 100644 index 0be36b66..00000000 --- a/Runtime/Pattern/Managers/GizmoManager.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: feda61cf5eb1b684fadf7cf1048a24cf \ No newline at end of file diff --git a/Runtime/Pattern/Managers/HapticManager.cs b/Runtime/Pattern/Managers/HapticManager.cs index 963f4024..26678b43 100644 --- a/Runtime/Pattern/Managers/HapticManager.cs +++ b/Runtime/Pattern/Managers/HapticManager.cs @@ -22,7 +22,7 @@ private class HapticController : IHapticProvider private HapticManager Owner; // Implement IIdentifier Interface - public string NameID => Config.NameID; + public Name16 NameID => Config.NameID; // Implement IHapticProvider Interface public HapticController(HapticManager manager, HapticConfig config) { @@ -65,19 +65,14 @@ public MonoBehaviour GetManagerClass() { return this; } - public void InitiateManager(bool AlwaysLoaded) + public void InitiateManager(Scope owner) { - if (!AlwaysLoaded) + if (owner.IsWorldScope()) { Debug.LogWarning("HapticManager Should initiate in Game Scope"); return; } - if (Game.TryFindService(out Spawn SpawnServ)) - { - SpawnServ.BringManager(this); - } - if (DefaultConfig != null) { foreach (var conf in DefaultConfig) @@ -86,14 +81,6 @@ public void InitiateManager(bool AlwaysLoaded) } } } - public void ResolveService(Service service, bool active) - { - if (service is Spawn spawnservice) - { - spawnservice.BringManager(this); - } - } - // Public Methods public IHapticProvider Produce(HapticConfig config) @@ -110,7 +97,7 @@ public bool Demolish(IHapticProvider target) { foreach (var item in produceList) { - if (item.NameID == target.NameID) + if (item == target) { return produceList.Remove(item); } @@ -147,9 +134,6 @@ public abstract class HapticConfig : ConfigAsset, IIdentifier [SerializeField] private string configName; - // Implement - public string NameID => configName; - private void OnValidate() { configName = name; diff --git a/Runtime/Pattern/Managers/LogManager.cs b/Runtime/Pattern/Managers/LogManager.cs new file mode 100644 index 00000000..538453a7 --- /dev/null +++ b/Runtime/Pattern/Managers/LogManager.cs @@ -0,0 +1,23 @@ +using UnityEngine; + +namespace RealMethod +{ + public class LogManager : MonoBehaviour, IGameManager + { + void IGameManager.InitiateManager(Scope owner) + { + if (owner.IsWorldScope()) + { + Debug.LogError("LogManager should be Initiate in GameScope."); + Destroy(this); + } + } + + + + + + + + } +} \ No newline at end of file diff --git a/Runtime/Pattern/Managers/LogManager.cs.meta b/Runtime/Pattern/Managers/LogManager.cs.meta new file mode 100644 index 00000000..3195380d --- /dev/null +++ b/Runtime/Pattern/Managers/LogManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 964d17416768e4540aca53dd2e600936 \ No newline at end of file diff --git a/Runtime/Pattern/Managers/MixerManager.cs b/Runtime/Pattern/Managers/MixerManager.cs index 14dd3310..3e3ba13a 100644 --- a/Runtime/Pattern/Managers/MixerManager.cs +++ b/Runtime/Pattern/Managers/MixerManager.cs @@ -8,45 +8,33 @@ public abstract class MixerManager : MonoBehaviour, IGameManager { [Header("Mixer")] [SerializeField] - private AudioMixer Mixer; - public AudioMixer mixer => Mixer; + private AudioMixer mixer; + public AudioMixer Mixer => mixer; +#if UNITY_EDITOR [SerializeField] - private StringFloatDictionary Parameter; + private Map Parameter; +#endif - // Operators - public float this[string name] - { - get => Parameter[name]; - set => Parameter[name] = value; - } // IGameManager Interface Implementation - MonoBehaviour IGameManager.GetManagerClass() - { - return this; - } - void IGameManager.InitiateManager(bool AlwaysLoaded) - { - InitiateManager(AlwaysLoaded); - } - void IGameManager.ResolveService(Service service, bool active) + public virtual void InitiateManager(Scope owner) { - InitiateService(service); + } // Unity Methods #if UNITY_EDITOR - private void OnValidate() + protected virtual void OnValidate() { - if (Mixer != null) + if (mixer != null) { Parameter.Clear(); - System.Array parameters = (System.Array)Mixer.GetType().GetProperty("exposedParameters").GetValue(Mixer, null); + System.Array parameters = (System.Array)mixer.GetType().GetProperty("exposedParameters").GetValue(mixer, null); for (int i = 0; i < parameters.Length; i++) { var o = parameters.GetValue(i); string PrametrName = (string)o.GetType().GetField("name").GetValue(o); - Mixer.GetFloat(PrametrName, out float result); + mixer.GetFloat(PrametrName, out float result); Parameter.Add(PrametrName, result); } } @@ -54,25 +42,30 @@ private void OnValidate() #endif // Public Functions - public void Sync() + public void SetParam(string param, float value) { - if (Mixer != null) + mixer.SetFloat(param, value); + } + public float GetParam(string param) + { + if (mixer.GetFloat(param, out float result)) { - foreach (var param in Parameter) - { - Mixer.SetFloat(param.Key, param.Value); - } + return result; } else { - Debug.LogError("AudioMixers Not Valid!"); + Debug.LogError($"Can't find any value with param:({param})"); + return 0; } - } - - // Abstract Method - protected abstract void InitiateManager(bool AlwaysLoaded); - protected abstract void InitiateService(Service service); + public bool TryGetParam(string param, out float result) + { + return mixer.GetFloat(param, out result); + } + public void TransitionToSnapshot(AudioMixerSnapshot snapshot, float transitionTime = 1f) + { + snapshot?.TransitionTo(transitionTime); + } } diff --git a/Runtime/Pattern/Managers/SaveManager.cs b/Runtime/Pattern/Managers/SaveManager.cs new file mode 100644 index 00000000..970a9959 --- /dev/null +++ b/Runtime/Pattern/Managers/SaveManager.cs @@ -0,0 +1,1153 @@ +using System.Runtime.Serialization.Formatters.Binary; +using System.Collections.Generic; +using System.Xml.Serialization; +using System.Reflection; +using System.IO; +using UnityEngine; +using System.Linq; +using System.ComponentModel; + +namespace RealMethod +{ + [System.Serializable] + public enum SaveFileStructure + { + [DescriptionEnum("Always read/write one fixed file")] + SingleFile, + [DescriptionEnum("Each save item is saved separately")] + MultiFile, + [DescriptionEnum("Save multiple items but merge them into one output file")] + MergedFile + } + [System.Serializable] + public enum SaveFormat + { + [DescriptionEnum("Didn't Store any data just call OnSave&OnLoad Event")] + None = 0, + PlayerPrefs = 1, + TEXT = 2, + XML = 3, + JSON = 4, + Binary = 5, + Custom = 6, + } + public interface ISaveMethod + { + SaveFormat Format { get; } + string Path { get; } + BindingFlags FieldFlags { get; } + BindingFlags PropertieFlags { get; } + } + public interface IMergeFile : ISaveFile + { + void Write(string fileName, string variableName, System.Type variableType, object variableValue); + object Read(string fileName, string variableName, System.Type variableType); + } + + + + public abstract class SaveManager : MonoBehaviour, IGameManager, IStorageService + { + [Header("Mode")] + [SerializeField] + protected SaveFileStructure Mode = SaveFileStructure.MultiFile; + [Space] + [SerializeField, ConditionalShowByEnum("Mode", SaveFileStructure.MergedFile)] + private BindingFlags MergedFieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + [SerializeField, ConditionalShowByEnum("Mode", SaveFileStructure.MergedFile)] + private BindingFlags MergedPropertieFlags = BindingFlags.Default; + public bool IsInSingleFile => Mode == SaveFileStructure.SingleFile; + // Actions + public event System.Action OnLoaded; + public event System.Action OnSaved; + public event System.Action OnDeleted; + + + + + + // Implement IGameManager Interface + public virtual void InitiateManager(Scope owner) + { + if (Mode != SaveFileStructure.MultiFile) + { + IFile provider = CreateMainFile(); + ISaveMethod method = GetMethod(provider); + if (method.Format == SaveFormat.None) + { + OnLoad(provider, method); + } + else + { + if (IsExistFile(provider, method)) + { + OnLoad(provider, method); + } + } + } + } + + + // Implement ISaveSystem Interface + /// + /// The file that created by savesystem for merging all file selected in sytem to one file or SingleFile + /// + public IFile MainSaveFile + { + get + { + if (Mode == SaveFileStructure.MultiFile) + { + Debug.LogWarning("MainSaveFile Just created in SingleFile & MergedFile"); + return null; + } + else + { + return GetMainFile(); + } + } + } + public bool IsExist(IFile file) + { + if (!CanContinue("check isExist")) + return false; + + if (!Validate(file)) + return false; + + return IsExistFile(file, GetMethod(file)); + } + public void Save(IFile file) + { + if (!CanContinue("Save")) + return; + + if (!Validate(file)) + return; + + try + { + OnSave(file, GetMethod(file)); + } + catch (System.Exception ex) + { + Debug.LogError(ex); + return; + } + file.Self.InvokeSaveEvent(); + OnSaved?.Invoke(file); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + WriteLog($"Save({GetMethod(file).Format}) Class({file.Self.GetType()})"); +#endif + } + public void Load(IFile file) + { + if (!CanContinue("Load")) + return; + + if (!Validate(file)) + return; + + try + { + OnLoad(file, GetMethod(file)); + } + catch (System.Exception ex) + { + Debug.LogError(ex); + return; + } + file.Self.InvokeLoadEvent(); + OnLoaded?.Invoke(file); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + WriteLog($"Load({GetMethod(file).Format}) Class({file.Self.GetType()})"); +#endif + } + public void Delete(IFile file) + { + if (!Validate(file)) + return; + + try + { + OnDelete(file, GetMethod(file)); + } + catch (System.Exception ex) + { + Debug.LogError(ex); + return; + } + OnDeleted?.Invoke(file); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + WriteLog($"Delete({GetMethod(file).Format}) Class({file.Self.GetType()})"); +#endif + } + [ContextMenu("Save")] + /// + /// Save all file or Specific file that implemented + /// + void ISaveService.Save() + { + IFile[] files = GetAllFiles(); + if (files != null) + { + switch (Mode) + { + case SaveFileStructure.SingleFile: + if (!Validate(MainSaveFile)) + return; + + try + { + OnSave(MainSaveFile, GetMethod(MainSaveFile)); + } + catch (System.Exception ex) + { + Debug.LogError(ex); + return; + } + MainSaveFile.Self.InvokeSaveEvent(); + OnSaved?.Invoke(MainSaveFile); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + WriteLog($"Save[SingleFile]({GetMethod(MainSaveFile).Format}) Class({MainSaveFile.Self.GetType()})"); +#endif + break; + case SaveFileStructure.MultiFile: + foreach (var file in files) + { + Save(file); + } + break; + case SaveFileStructure.MergedFile: + foreach (var file in files) + { + WriteToMergeFile(file, MergedFieldFlags, MergedPropertieFlags); + } + + + if (!Validate(MainSaveFile)) + return; + + try + { + OnSave(MainSaveFile, GetMethod(MainSaveFile)); + } + catch (System.Exception ex) + { + Debug.LogError(ex); + return; + } + MainSaveFile.Self.InvokeSaveEvent(); + OnSaved?.Invoke(MainSaveFile); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + WriteLog($"Save[MergedFile]({GetMethod(MainSaveFile).Format}) Class({MainSaveFile.Self.GetType()})"); +#endif + break; + } + } + } + [ContextMenu("Load")] + /// + /// Load all file or specific file that implemented + /// + void ISaveService.Load() + { + IFile[] files = GetAllFiles(); + if (files != null) + { + switch (Mode) + { + case SaveFileStructure.SingleFile: + if (!Validate(MainSaveFile)) + return; + + try + { + OnLoad(MainSaveFile, GetMethod(MainSaveFile)); + } + catch (System.Exception ex) + { + Debug.LogError(ex); + return; + } + MainSaveFile.Self.InvokeLoadEvent(); + OnLoaded?.Invoke(MainSaveFile); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + WriteLog($"Load({GetMethod(MainSaveFile).Format}) Class({MainSaveFile.Self.GetType()})"); +#endif + break; + case SaveFileStructure.MultiFile: + foreach (var file in files) + { + Save(file); + } + break; + case SaveFileStructure.MergedFile: + foreach (var file in files) + { + ReadFromMergeFile(file, MergedFieldFlags, MergedPropertieFlags); + } + + + if (!Validate(MainSaveFile)) + return; + + try + { + OnLoad(MainSaveFile, GetMethod(MainSaveFile)); + } + catch (System.Exception ex) + { + Debug.LogError(ex); + return; + } + MainSaveFile.Self.InvokeLoadEvent(); + OnLoaded?.Invoke(MainSaveFile); +#if UNITY_EDITOR || DEVELOPMENT_BUILD + WriteLog($"Load({GetMethod(MainSaveFile).Format}) Class({MainSaveFile.Self.GetType()})"); +#endif + break; + } + } + } + /// + /// use for adding file to filelist in savemsystem. + /// if you want to use saveall or geting file with name + /// + /// target file you want adding + /// return true if can add + public abstract bool AddFile(IFile file); + /// + /// use for removing file to filelist in savesystem + /// + /// target file you want removing + /// return true if can remove + public abstract bool RemoveFile(IFile file); + /// + /// Determines whether the specified file already exists in the file list. + /// Checks by object reference unless IFile implementations override equality. + /// + /// The file instance to check. + /// True if the file is found in the list; otherwise false. + public abstract bool HasFile(IFile file); + + + // Methods + protected virtual bool CanContinue(string message) + { + if (Mode == SaveFileStructure.MultiFile) + { + return true; + } + Debug.LogError($"You can't {message} when SaveMode is {Mode}"); + return false; + } + protected virtual bool Validate(IFile file) + { + if (file == null && file.Self != null) + { + Debug.LogError("File Does not valid"); + return false; + } + return true; + } + protected virtual ISaveMethod GetMethod(IFile file) + { + if (file != null && file.Self.HasImplementInterface(out ISaveMethod method)) + { + return method; + } + else + { + if (this is ISaveMethod provider) + { + return provider; + } + else + { + throw new System.InvalidOperationException($"You Should Implement {typeof(ISaveMethod)}, in SameManager Class for save / load files"); + } + } + } + protected virtual void WriteToMergeFile(IFile file, BindingFlags fieldFlags, BindingFlags propertyFlags) + { + object FileObject = file.Self; + IMergeFile mergefile = GetMainFile(); + foreach (var field in FileObject.GetFields(fieldFlags)) + { + mergefile.Write(file.FileName, field.Name, field.FieldType, field.GetValue(FileObject)); + } + foreach (var propery in FileObject.GetProperties(propertyFlags)) + { + mergefile.Write(file.FileName, propery.Name, propery.PropertyType, propery.GetValue(FileObject)); + } + } + protected virtual void ReadFromMergeFile(IFile file, BindingFlags fieldFlags, BindingFlags propertyFlags) + { + object FileObject = file.Self; + IMergeFile mergefile = GetMainFile(); + foreach (var field in FileObject.GetFields(fieldFlags)) + { + field.SetValue(FileObject, mergefile.Read(file.FileName, field.Name, field.FieldType)); + } + foreach (var propery in FileObject.GetProperties(propertyFlags)) + { + propery.SetValue(FileObject, mergefile.Read(file.FileName, propery.Name, propery.PropertyType)); + } + } + + + // Abstract Mehtod + protected abstract bool IsExistFile(IFile file, ISaveMethod Method); + protected abstract void OnSave(IFile file, ISaveMethod Method); + protected abstract void OnLoad(IFile file, ISaveMethod Method); + protected abstract void OnDelete(IFile file, ISaveMethod Method); + protected abstract IFile CreateMainFile(); + protected abstract T GetMainFile() where T : IFile; + public abstract IFile[] GetAllFiles(); + + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + protected virtual void WriteLog(string message) + { + Debug.Log($"{System.DateTime.Now} -- {message}"); + } +#endif + } + public abstract class SaveManager_Method : SaveManager, ISaveMethod + { + protected enum SaveState + { + IsExist = 0, + Save = 1, + Load = 2, + Delete = 3 + } + [Header("SaveMethod")] + [SerializeField] + private SaveFormat fromat; + [SerializeField, ConditionalHideByEnum("fromat", SaveFormat.None, SaveFormat.PlayerPrefs)] + private bool CustomPath = false; + [SerializeField, ConditionalHideByEnum("fromat", SaveFormat.None, SaveFormat.PlayerPrefs), ConditionalHide("CustomPath", true, false)] + private string FilePath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop); + [SerializeField, ConditionalShowByEnum("fromat", SaveFormat.PlayerPrefs, SaveFormat.TEXT, SaveFormat.Custom)] + private BindingFlags FieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + [SerializeField, ConditionalShowByEnum("fromat", SaveFormat.PlayerPrefs, SaveFormat.TEXT, SaveFormat.Custom)] + private BindingFlags PropertieFlags = BindingFlags.Default; + + + // Implement ISaveMethod Interface + SaveFormat ISaveMethod.Format => fromat; + string ISaveMethod.Path => FilePath; + BindingFlags ISaveMethod.FieldFlags => FieldFlags; + BindingFlags ISaveMethod.PropertieFlags => PropertieFlags; + + + // SaveManager Methods + protected override bool IsExistFile(IFile file, ISaveMethod Method) + { + switch (Method.Format) + { + case SaveFormat.None: + Debug.LogWarning("SaveSystem can't check IsExistFile with None format"); + return false; + case SaveFormat.Binary: + return File.Exists(GetPath(file, Method)); + case SaveFormat.XML: + return File.Exists(GetPath(file, Method)); + case SaveFormat.JSON: + return File.Exists(GetPath(file, Method)); + case SaveFormat.TEXT: + return File.Exists(GetPath(file, Method)); + case SaveFormat.PlayerPrefs: + return PlayerPrefs.HasKey(file.FileName); + case SaveFormat.Custom: + return CustomSavefile(file, Method, SaveState.IsExist); + default: + Debug.LogWarning($"The {Method.Format} is not implement"); + return false; + } + } + protected override void OnSave(IFile file, ISaveMethod Method) + { + object fileObject = file.Self; + + switch (Method.Format) + { + case SaveFormat.None: + if (fileObject is not ISaveable) + { + Debug.LogError($"Your file({fileObject}) with name({file.FileName}) should implement ISave Interface"); + } + break; + case SaveFormat.Binary: + BinaryFormatter bf = new BinaryFormatter(); +#pragma warning disable SYSLIB0011 // Suppress BinaryFormatter warning (only use in trusted context) + using (var stream = new FileStream(GetPath(file, Method), FileMode.Create)) + { + try + { + bf.Serialize(stream, fileObject); + } + catch (System.Exception e) + { + Debug.LogError($"Failed to serialize {file.FileName} to {GetPath(file, Method)}: {e}"); + return; + } + } +#pragma warning restore SYSLIB0011 + break; + case SaveFormat.XML: + var xml = new XmlSerializer(fileObject.GetType()); + using (var stream = new FileStream(GetPath(file, Method), FileMode.Create)) + { + xml.Serialize(stream, fileObject); + } + break; + case SaveFormat.JSON: + string jsoncontent = JsonUtility.ToJson(fileObject, true); + File.WriteAllText(GetPath(file, Method), jsoncontent); + break; + case SaveFormat.TEXT: + List lines = new List(); + FieldInfo[] T_fields = fileObject.GetFields(Method.FieldFlags); + PropertyInfo[] T_properties = fileObject.GetProperties(Method.PropertieFlags); + foreach (FieldInfo field in T_fields) + { + lines.Add($"{field.Name}={field.GetValue(file)}"); + } + foreach (PropertyInfo property in T_properties) + { + lines.Add($"{property.Name}={property.GetValue(file)}"); + } + File.WriteAllLines(GetPath(file, Method), lines); + break; + case SaveFormat.PlayerPrefs: + FieldInfo[] PP_fields = fileObject.GetFields(Method.FieldFlags); + PropertyInfo[] PP_properties = fileObject.GetProperties(Method.PropertieFlags); + foreach (FieldInfo field in PP_fields) + { + Set_PlayerPrefsInfo(field, fileObject); + } + foreach (PropertyInfo property in PP_properties) + { + Set_PlayerPrefsInfo(property, fileObject); + } + PlayerPrefs.SetString(file.FileName, System.DateTime.Now.ToString()); + PlayerPrefs.Save(); + break; + case SaveFormat.Custom: + CustomSavefile(file, Method, SaveState.Save); + break; + default: + Debug.LogWarning($"The {Method.Format} is not implement"); + break; + } + } + protected override void OnLoad(IFile file, ISaveMethod Method) + { + object fileObject = file.Self; + + switch (Method.Format) + { + case SaveFormat.None: + if (fileObject is not ISaveable) + { + Debug.LogError($"Your file({fileObject}) with name({file.FileName}) should implement ISave Interface"); + } + break; + case SaveFormat.Binary: + var bf = new BinaryFormatter(); +#pragma warning disable SYSLIB0011 + using (var stream = new FileStream(GetPath(file, Method), FileMode.Open)) + { + fileObject = bf.Deserialize(stream); + + } +#pragma warning restore SYSLIB0011 + break; + case SaveFormat.XML: + var xml = new XmlSerializer(file.GetType()); + using (var stream = new FileStream(GetPath(file, Method), FileMode.Open)) + { + fileObject = xml.Deserialize(stream); + } + break; + case SaveFormat.JSON: + string jsoncontent; + try + { + jsoncontent = File.ReadAllText(GetPath(file, Method)); + JsonUtility.FromJsonOverwrite(jsoncontent, fileObject); + } + catch (System.Exception e) + { + Debug.LogError($"Failed to read from {GetPath(file, Method)} with exception {e}"); + return; + } + break; + case SaveFormat.TEXT: + FieldInfo[] T_fields = fileObject.GetFields(Method.FieldFlags); + PropertyInfo[] T_properties = fileObject.GetProperties(Method.PropertieFlags); + foreach (string line in File.ReadLines(GetPath(file, Method))) + { + string[] parts = line.Split("="); + if (parts.Length < 2) continue; + string lineName = parts[0]; + string lineValue = parts[1]; + foreach (FieldInfo info in T_fields) + { + if (info.Name == lineName) + { + object value = null; + System.Type type = info.FieldType; + try + { + if (type == typeof(int)) + value = int.Parse(lineValue); + else if (type == typeof(float)) + value = float.Parse(lineValue); + else if (type == typeof(bool)) + value = bool.Parse(lineValue); + else if (type == typeof(string)) + value = lineValue; + else if (type.IsEnum) + value = System.Enum.Parse(type, lineValue); + else if (type == typeof(byte)) + value = byte.Parse(lineValue); + else + Debug.LogWarning($"Unsupported type: {type.Name}"); + info.SetValue(file, value); + } + catch (System.Exception ex) + { + Debug.LogWarning($"Failed to set value for {info.Name}: {ex.Message}"); + } + } + } + foreach (PropertyInfo property in T_properties) + { + if (property.Name == lineName) + { + object value = null; + System.Type type = property.PropertyType; + try + { + if (type == typeof(int)) + value = int.Parse(lineValue); + else if (type == typeof(float)) + value = float.Parse(lineValue); + else if (type == typeof(bool)) + value = bool.Parse(lineValue); + else if (type == typeof(string)) + value = lineValue; + else if (type.IsEnum) + value = System.Enum.Parse(type, lineValue); + else if (type == typeof(byte)) + value = byte.Parse(lineValue); + else + Debug.LogWarning($"Unsupported type: {type.Name}"); + property.SetValue(file, value); + } + catch (System.Exception ex) + { + Debug.LogWarning($"Failed to set value for {property.Name}: {ex.Message}"); + } + } + } + } + break; + case SaveFormat.PlayerPrefs: + FieldInfo[] PP_fields = fileObject.GetFields(Method.FieldFlags); + PropertyInfo[] PP_properties = fileObject.GetProperties(Method.PropertieFlags); + foreach (FieldInfo field in PP_fields) + { + Get_PlayerPrefsInfo(field, fileObject); + } + foreach (PropertyInfo property in PP_properties) + { + Get_PlayerPrefsInfo(property, fileObject); + } + break; + case SaveFormat.Custom: + CustomSavefile(file, Method, SaveState.Load); + break; + default: + Debug.LogWarning($"The {Method.Format} is not implement"); + break; + } + } + protected override void OnDelete(IFile file, ISaveMethod Method) + { + object fileObject = file.Self; + + switch (Method.Format) + { + case SaveFormat.None: + Debug.LogWarning("SaveSystem can't delete with None format"); + break; + case SaveFormat.Binary: + File.Delete(GetPath(file, Method)); + break; + case SaveFormat.XML: + File.Delete(GetPath(file, Method)); + break; + case SaveFormat.JSON: + File.Delete(GetPath(file, Method)); + break; + case SaveFormat.TEXT: + File.Delete(GetPath(file, Method)); + break; + case SaveFormat.PlayerPrefs: + FieldInfo[] PP_fields = fileObject.GetFields(Method.FieldFlags); + PropertyInfo[] PP_properties = fileObject.GetProperties(Method.PropertieFlags); + foreach (FieldInfo field in PP_fields) + { + PlayerPrefs.DeleteKey(field.Name); + } + foreach (PropertyInfo property in PP_properties) + { + PlayerPrefs.DeleteKey(property.Name); + } + break; + case SaveFormat.Custom: + CustomSavefile(file, Method, SaveState.Delete); + break; + default: + Debug.LogWarning($"The {Method.Format} is not implement"); + break; + } + } + + // Methods + protected virtual string GetPath(IFile file, ISaveMethod method) + { + string filename = file.FileName; + string filetype = GetFileType(method); + + if (CustomPath) + { + return method.Path + "/" + filename + filetype; + } + else + { + return Application.persistentDataPath + "/" + filename + filetype; + } + } + protected virtual string GetFileType(ISaveMethod method) + { + return method.Format == SaveFormat.TEXT ? ".txt" : + method.Format == SaveFormat.Binary ? ".RSave" : + method.Format == SaveFormat.XML ? ".xml" : + method.Format == SaveFormat.JSON ? ".json" : ""; + } + + // Private Method + private void Set_PlayerPrefsInfo(MemberInfo info, object source) + { + string key = info.Name; + object value = GetValueInfo(info, source); + + if (value is int intValue) + { + PlayerPrefs.SetInt(key, intValue); + } + else if (value is float floatValue) + { + PlayerPrefs.SetFloat(key, floatValue); + } + else if (value is string stringValue) + { + PlayerPrefs.SetString(key, stringValue); + } + else if (value is bool boolValue) + { + PlayerPrefs.SetInt(key, boolValue ? 1 : 0); + } + else if (value is System.Enum enumvalue) + { + PlayerPrefs.SetInt(key, System.Convert.ToInt32(enumvalue)); + } + else if (value is byte bytevalue) + { + PlayerPrefs.SetInt(key, bytevalue); + } + else if (value is Vector2 v2Value) + { + RM_Save.SetVector2(key, v2Value); + } + else if (value is Vector3 v3Value) + { + RM_Save.SetVector3(key, v3Value); + } + else if (value is Quaternion quatValue) + { + RM_Save.SetQuaternion(key, quatValue); + } + else if (value is Transform transValue) + { + RM_Save.SetTransform(key, transValue); + } + else if (value is UniqueAsset asset) + { + RM_Save.SetAsset(key, asset); + } + else if (value is IList Intlist) + { + RM_Save.SetArray(key, Intlist.ToArray()); + } + else if (value is IList FloatList) + { + RM_Save.SetArray(key, FloatList.ToArray()); + } + else if (value is IList StringList) + { + RM_Save.SetArray(key, StringList.ToArray()); + } + else if (value is IList BoolList) + { + RM_Save.SetArray(key, BoolList.ToArray()); + } + else if (value is IList EnumList) + { + RM_Save.SetArray(key, EnumList.ToArray()); + } + else if (value is IList ByteList) + { + RM_Save.SetArray(key, ByteList.ToArray()); + } + else if (value is IList V3List) + { + RM_Save.SetArray(key, V3List.ToArray()); + } + else if (value is IList V2List) + { + RM_Save.SetArray(key, V2List.ToArray()); + } + else if (value is int[] IntArray) + { + RM_Save.SetArray(key, IntArray); + } + else if (value is float[] FloatArray) + { + RM_Save.SetArray(key, FloatArray); + } + else if (value is string[] StringArray) + { + RM_Save.SetArray(key, StringArray); + } + else if (value is bool[] BoolArray) + { + RM_Save.SetArray(key, BoolArray); + } + else if (value is System.Enum[] EnumArray) + { + RM_Save.SetArray(key, EnumArray); + } + else if (value is byte[] ByteArray) + { + RM_Save.SetArray(key, ByteArray); + } + else if (value is Vector3[] V3Array) + { + RM_Save.SetArray(key, V3Array); + } + else if (value is Vector2[] V2Array) + { + RM_Save.SetArray(key, V2Array); + } + else + { + Debug.LogWarning($"Unsupported type for PlayerPrefs: {value?.GetType().Name} (Key: {key})"); + } + + } + private void Get_PlayerPrefsInfo(MemberInfo info, object source) + { + string key = info.Name; + System.Type type = GetInfoType(info); + + if (!PlayerPrefs.HasKey(key)) return; + + if (type == typeof(int)) + { + SetValueInfo(info, source, PlayerPrefs.GetInt(key)); + } + else if (type == typeof(float)) + { + SetValueInfo(info, source, PlayerPrefs.GetFloat(key)); + } + else if (type == typeof(string)) + { + SetValueInfo(info, source, PlayerPrefs.GetString(key)); + } + else if (type == typeof(bool)) + { + SetValueInfo(info, source, PlayerPrefs.GetInt(key) == 1); + } + else if (type == typeof(System.Enum)) + { + SetValueInfo(info, source, PlayerPrefs.GetInt(key)); + } + else if (type == typeof(byte)) + { + SetValueInfo(info, source, PlayerPrefs.GetInt(key)); + } + else if (type == typeof(Vector2)) + { + SetValueInfo(info, source, RM_Save.GetVector2(key)); + } + else if (type == typeof(Vector3)) + { + SetValueInfo(info, source, RM_Save.GetVector3(key)); + } + else if (type == typeof(Quaternion)) + { + SetValueInfo(info, source, RM_Save.GetQuaternion(key)); + } + else if (type == typeof(Transform)) + { + Transform t = (Transform)GetValueInfo(info, source); + RM_Save.GetTransform(key, t); + } + else if (type == typeof(UniqueAsset)) + { + SetValueInfo(info, source, RM_Save.GetAsset(key)); + } + else if (type == typeof(List)) + { + SetValueInfo(info, source, RM_Save.GetArray(key).ToList()); + } + else if (type == typeof(List)) + { + SetValueInfo(info, source, RM_Save.GetArray(key).ToList()); + } + else if (type == typeof(List)) + { + SetValueInfo(info, source, RM_Save.GetArray(key).ToList()); + } + else if (type == typeof(List)) + { + SetValueInfo(info, source, RM_Save.GetArray(key).ToList()); + } + else if (type == typeof(List)) + { + SetValueInfo(info, source, RM_Save.GetArray(key).ToList()); + } + else if (type == typeof(List)) + { + SetValueInfo(info, source, RM_Save.GetArray(key).ToList()); + } + else if (type == typeof(List)) + { + SetValueInfo(info, source, RM_Save.GetArray(key).ToList()); + } + else if (type == typeof(List)) + { + SetValueInfo(info, source, RM_Save.GetArray(key).ToList()); + } + else if (type == typeof(int[])) + { + SetValueInfo(info, source, RM_Save.GetArray(key)); + } + else if (type == typeof(float[])) + { + SetValueInfo(info, source, RM_Save.GetArray(key)); + } + else if (type == typeof(string[])) + { + SetValueInfo(info, source, RM_Save.GetArray(key)); + } + else if (type == typeof(bool[])) + { + SetValueInfo(info, source, RM_Save.GetArray(key)); + } + else if (type == typeof(System.Enum[])) + { + SetValueInfo(info, source, RM_Save.GetArray(key)); + } + else if (type == typeof(byte[])) + { + SetValueInfo(info, source, RM_Save.GetArray(key)); + } + else if (type == typeof(Vector2[])) + { + SetValueInfo(info, source, RM_Save.GetArray(key)); + } + else if (type == typeof(Vector3[])) + { + SetValueInfo(info, source, RM_Save.GetArray(key)); + } + } + private object GetValueInfo(MemberInfo info, object source) + { + if (info is FieldInfo field) + { + return field.GetValue(source); + } + else if (info is PropertyInfo property) + { + return property.GetValue(source); + } + else + { + Debug.LogError("Something wrong MemeberInfo has not correct valid"); + return null; + } + } + private void SetValueInfo(MemberInfo info, object source, T value) + { + if (info is FieldInfo field) + { + field.SetValue(source, value); + } + else if (info is PropertyInfo property) + { + property.SetValue(source, value); + } + else + { + Debug.LogError("Something wrong MemeberInfo has not correct valid"); + return; + } + } + private System.Type GetInfoType(MemberInfo info) + { + if (info is FieldInfo field) + { + return field.FieldType; + } + else if (info is PropertyInfo property) + { + return property.PropertyType; + } + else + { + Debug.LogError("Something wrong MemeberInfo has not correct valid"); + return null; + } + } + + + // Abstract Mehtod + protected abstract bool CustomSavefile(IFile file, ISaveMethod Method, SaveState state); + + +#if UNITY_EDITOR || DEVELOPMENT_BUILD + [ContextMenu("PrintPath")] + private void PrintPath() + { + if (fromat == SaveFormat.PlayerPrefs) + { + Debug.Log("PlayerPrefs store by OS [Not Specefic location]"); + return; + } + + string filetype = fromat == SaveFormat.TEXT ? ".txt" : + fromat == SaveFormat.Binary ? ".RSave" : + fromat == SaveFormat.XML ? ".xml" : + fromat == SaveFormat.JSON ? ".json" : ""; + + if (CustomPath) + { + Debug.Log(FilePath + "/FileName" + filetype); + } + else + { + Debug.Log(Application.persistentDataPath + "/FileName" + filetype); + } + } +#endif + + } + public abstract class SaveManager_Storage : SaveManager_Method + { + [Header("Details")] + [SerializeField, ConditionalShowByEnum("Mode", SaveFileStructure.SingleFile)] + private FileAsset SingeFileAsset; + [SerializeField, ConditionalShowByEnum("Mode", SaveFileStructure.MergedFile)] + private SoftType MergeFileClass; + private object MySaveFile; + public readonly List FileList = new List(3); + + + // SaveManager Methods + protected override IFile CreateMainFile() + { + if (Mode == SaveFileStructure.MergedFile) + { + MySaveFile = System.Activator.CreateInstance(MergeFileClass); + } + if (Mode == SaveFileStructure.SingleFile) + { + if (SingeFileAsset != null) + { + MySaveFile = ScriptableObject.CreateInstance(SingeFileAsset.GetType()); + } + else + { + Debug.LogWarning("SingleFileAsset is not valid"); + // Mode = SaveFileStructure.MultiFile; + } + } + + if (MySaveFile is IFile provider) + { + return provider; + } + else + { + Debug.LogError("Your MainFile should implement IFile interface"); + return null; + } + } + protected override T GetMainFile() + { + return (T)MySaveFile; + } + public override bool HasFile(IFile file) + { + return FileList.Contains(file); + } + public override bool AddFile(IFile file) + { + if (file == null) + { + WriteLog($"File not valid"); + return false; + } + + if (FileList.Contains(file))// reference comparison + { + WriteLog($"File({file.FileName}) already added"); + return false; + } + + if (Mode == SaveFileStructure.MultiFile) + { + if (IsExist(file)) + { + Load(file); + } + } + + FileList.Add(file); + return true; + } + public override bool RemoveFile(IFile file) + { + if (file == null) + { + WriteLog($"File not valid"); + return false; + } + + return FileList.Remove(file); // removes same reference + } + public override IFile[] GetAllFiles() + { + return FileList.ToArray(); + } + } + +} \ No newline at end of file diff --git a/Runtime/Pattern/Managers/SaveManager.cs.meta b/Runtime/Pattern/Managers/SaveManager.cs.meta new file mode 100644 index 00000000..52814668 --- /dev/null +++ b/Runtime/Pattern/Managers/SaveManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9923681aac3097a46b06fbdfa85c89ac \ No newline at end of file diff --git a/Runtime/Pattern/Managers/TaskManager.cs b/Runtime/Pattern/Managers/TaskManager.cs new file mode 100644 index 00000000..e5df6566 --- /dev/null +++ b/Runtime/Pattern/Managers/TaskManager.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace RealMethod +{ + public interface ITask : ITask, ITick where T : IHandle + { + string ID => this.GetType().ToString(); + T Controller { get; } + } + + public abstract class TaskManager : MonoBehaviour, IGameManager + { + protected readonly List Tasks = new List(); + public int Count => Tasks != null ? Tasks.Count : 0; + + // Implement IGameManager Interface + void IGameManager.InitiateManager(Scope owner) + { + InitiateManager(owner); + } + + // Abstract Methods + protected abstract void InitiateManager(Scope owner); + } + public abstract class TaskManager : TaskManager where J : IHandle + { + + public abstract J Create(F Task, bool AutoStart = false) where F : class; + public abstract J FindByName(Name16 TaskName); + public abstract bool Destroy(J motion); + } + public abstract class TaskManager : TaskManager where T : ITask where J : IHandle + { + [Header("Setting")] + [SerializeField] + private bool EnableTick = true; + + + public event Action OnTaskAdded; + public event Action OnTaskRemoved; + + + // Unity Method + private void Update() + { + if (EnableTick == false) + return; + + float delta = Time.deltaTime; + foreach (var task in Tasks) + { + if (task is T provider) + provider.Tick(delta); + } + } + + // Function + public override J Create(F Task, bool autoStart = false) where F : class + { + if (TryCreateNewInstance(Task, out F TaskObject)) + { + J Provider = AddTask(TaskObject); + if (Provider != null) + { + if (autoStart) + AutoStart(Provider); + return Provider; + } + else + { + return default; + } + } + else + { + Debug.LogWarning($"Can't create instance with Type({typeof(F)})"); + return default; + } + } + public override J FindByName(Name16 TaskName) + { + foreach (var task in Tasks) + { + if (task.HasNameID(TaskName)) + { + if (task is J provider) + { + return provider; + } + else + { + Debug.LogWarning($"Task({task}) should implement {typeof(J)}"); + return default; + } + } + } + return default; + } + public override bool Destroy(J motion) + { + return RemoveTask(motion); + } + + // Method + protected J AddTask(object Task) + { + if (Task == null) + { + Debug.LogWarning($"Task is not valid"); + return default; + } + + if (Task is T provider) + { + Tasks.Add(Task); + provider.Active(); + OnTaskAdded?.Invoke(provider.Controller); + Task.InvokeSpawnEvent(); + return provider.Controller; + } + else + { + Debug.LogWarning($"Task({Task}) should implement {typeof(T)}"); + return default; + } + } + protected bool RemoveTask(T task) + { + if (Tasks.Contains(task)) + { + task.Deactive(); + OnTaskRemoved?.Invoke(task.Controller); + return Tasks.Remove(task); + } + else + { + return false; + } + } + protected bool RemoveTask(J behavior) + { + foreach (object task in Tasks) + { + if (task is T provider) + { + if (provider.Controller.IsSame(behavior)) + { + provider.Deactive(); + OnTaskRemoved?.Invoke(provider.Controller); + provider.InvokeDespawnEvent(); + return Tasks.Remove(provider); + } + } + } + return false; + } + + // Abstract Methods + protected abstract bool TryCreateNewInstance

(object ClassType, out P result) where P : class; + protected abstract void AutoStart(J Handle); + } + +} \ No newline at end of file diff --git a/Runtime/Pattern/Managers/TaskManager.cs.meta b/Runtime/Pattern/Managers/TaskManager.cs.meta new file mode 100644 index 00000000..3d489629 --- /dev/null +++ b/Runtime/Pattern/Managers/TaskManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 93918933848831043b4d95e4f18fd91b \ No newline at end of file diff --git a/Runtime/Pattern/Managers/TickManager.cs b/Runtime/Pattern/Managers/TickManager.cs deleted file mode 100644 index e01fb488..00000000 --- a/Runtime/Pattern/Managers/TickManager.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace RealMethod -{ - public abstract class TickManager : MonoBehaviour, IGameManager where T : ITick - { - [Header("Tick")] - [SerializeField] - private UpdateMethod updateMethod = UpdateMethod.Update; - [SerializeField] - private int baseCapacity = 10; - - protected List units { get; private set; } - public int Count => units != null ? units.Count : 0; - - // Implement IGameManager Interface - MonoBehaviour IGameManager.GetManagerClass() - { - return this; - } - void IGameManager.InitiateManager(bool AlwaysLoaded) - { - units = new List(baseCapacity); - InitiateManager(AlwaysLoaded); - } - void IGameManager.ResolveService(Service service, bool active) - { - InitiateService(service); - } - - // Unity Methods - private void LateUpdate() - { - if (updateMethod == UpdateMethod.LateUpdate) - { - callUnits(); - } - } - private void Update() - { - if (updateMethod == UpdateMethod.Update) - { - callUnits(); - } - } - private void FixedUpdate() - { - if (updateMethod == UpdateMethod.FixedUpdate) - { - callUnits(); - } - } - - // Public Functions - public bool IsValid(T unit) - { - return units.Contains(unit); - } - public T[] GetAllTasks() - { - return units.ToArray(); - } - - // Private Functions - private void callUnits() - { - float delta = Time.deltaTime; - for (int i = 0; i < units.Count; i++) - { - var unit = units[i]; - if (CheckUnit(unit)) - unit.Tick(delta); - } - } - - // Abstract Methods - protected abstract void InitiateManager(bool alwaysLoaded); - protected abstract void InitiateService(Service service); - protected abstract bool CheckUnit(T unit); - } -} \ No newline at end of file diff --git a/Runtime/Pattern/Managers/TickManager.cs.meta b/Runtime/Pattern/Managers/TickManager.cs.meta deleted file mode 100644 index 3d6c48fc..00000000 --- a/Runtime/Pattern/Managers/TickManager.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 87611a023127fcc4b90c043e9956d2d3 \ No newline at end of file diff --git a/Runtime/Pattern/Managers/UIManager.cs b/Runtime/Pattern/Managers/UIManager.cs index 9a350824..30ec57e3 100644 --- a/Runtime/Pattern/Managers/UIManager.cs +++ b/Runtime/Pattern/Managers/UIManager.cs @@ -10,11 +10,11 @@ public abstract class UIManager : MonoBehaviour, IGameManager { public enum UIMethod { - [EnumDescription("IMGUI (Legacy - Editor Only)")] + [DescriptionEnum("IMGUI (Legacy - Editor Only)")] IMGUI, - [EnumDescription("uGUI - Canvas-based UI for runtime")] + [DescriptionEnum("uGUI - Canvas-based UI for runtime")] uGUI, - [EnumDescription("UI Toolkit - Modern retained UI system")] + [DescriptionEnum("UI Toolkit - Modern retained UI system")] UI_Toolkit } @@ -24,22 +24,18 @@ public enum UIMethod [SerializeField] private UIMethod method = UIMethod.uGUI; public UIMethod Method => method; - [SerializeField, ShowInInspectorByEnum("method", 2)] + [SerializeField, ConditionalShowByEnum("method", 2)] private PanelSettings UISetting; // Actions public System.Action OnFadeIn; public System.Action OnFadeOut; // Private Variable - private Hictionary Layers = new Hictionary(5); + private NameTable Layers = new NameTable(5); // Implement IGameManager Interface - MonoBehaviour IGameManager.GetManagerClass() - { - return this; - } - void IGameManager.InitiateManager(bool alwaysLoaded) + void IGameManager.InitiateManager(Scope owner) { if (header == null) { @@ -73,11 +69,7 @@ void IGameManager.InitiateManager(bool alwaysLoaded) } } - InitiateManager(alwaysLoaded); - } - void IGameManager.ResolveService(Service service, bool active) - { - InitiateService(service); + InitiateManager(owner); } @@ -85,8 +77,12 @@ void IGameManager.ResolveService(Service service, bool active) #if UNITY_EDITOR private void OnValidate() { - if (gameObject.layer != 5) - gameObject.layer = 5; + if (header != null) + { + if (header.gameObject.layer != 5) + header.gameObject.layer = 5; + } + } #endif @@ -133,11 +129,11 @@ public T CreateLayer(string name, Object creator = null) where T : MonoBehavi { if (creator != null) { - widget.GetWidgetClass().SendSpawnEvent(creator); + widget.GetWidgetClass().InvokeSpawnEvent(creator); } else { - widget.GetWidgetClass().SendSpawnEvent(this, SendMessageOptions.DontRequireReceiver); + widget.GetWidgetClass().InvokeSpawnEvent(this, SendMessageOptions.DontRequireReceiver); } } return TargetClass; @@ -188,11 +184,11 @@ public T CreateLayer(string name, VisualTreeAsset UIAsset, Object creator = n { if (creator != null) { - widget.GetWidgetClass().SendSpawnEvent(creator); + widget.GetWidgetClass().InvokeSpawnEvent(creator); } else { - widget.GetWidgetClass().SendSpawnEvent(this, SendMessageOptions.DontRequireReceiver); + widget.GetWidgetClass().InvokeSpawnEvent(this, SendMessageOptions.DontRequireReceiver); } } return TargetClass; @@ -204,14 +200,14 @@ public T CreateLayer(string name, VisualTreeAsset UIAsset, Object creator = n } public GameObject AddLayer(string name, UPrefab Prefab, Object spawner = null) { - GameObject SpawnedObject = Instantiate(Prefab.asset, header.position, Quaternion.identity, header); + GameObject SpawnedObject = Instantiate(Prefab, header.position, Quaternion.identity, header); if (spawner != null) { - SpawnedObject.SendSpawnEvent(spawner); + SpawnedObject.InvokeSpawnEvent(spawner); } else { - SpawnedObject.SendSpawnEvent(this, SendMessageOptions.DontRequireReceiver); + SpawnedObject.InvokeSpawnEvent(this, SendMessageOptions.DontRequireReceiver); } SpawnedObject.name = name; Layers.Add(name, SpawnedObject); @@ -224,14 +220,14 @@ public T AddLayer(string name, UPrefab Prefab, Object spawner = null) where T Debug.LogError($"Prefab should has Widget Class Component"); return null; } - GameObject SpawnedObject = Instantiate(Prefab.asset, header.position, Quaternion.identity, header); + GameObject SpawnedObject = Instantiate(Prefab, header.position, Quaternion.identity, header); if (spawner != null) { - SpawnedObject.SendSpawnEvent(spawner); + SpawnedObject.InvokeSpawnEvent(spawner); } else { - SpawnedObject.SendSpawnEvent(this, SendMessageOptions.DontRequireReceiver); + SpawnedObject.InvokeSpawnEvent(this, SendMessageOptions.DontRequireReceiver); } SpawnedObject.name = name; Layers.Add(name, SpawnedObject); @@ -261,11 +257,11 @@ public bool RemoveLayer(string name, Object despawner = null) { if (despawner != null) { - Target.SendDespawnEvent(despawner); + Target.InvokeDespawnEvent(despawner); } else { - Target.SendDespawnEvent(this, SendMessageOptions.DontRequireReceiver); + Target.InvokeDespawnEvent(this, SendMessageOptions.DontRequireReceiver); } Destroy(Target); } @@ -528,9 +524,9 @@ public T FindClassInLayers() where T : class { T Reslut = null; IWidget TargetWidget; - foreach (var Lay in Layers.GetValues()) + foreach (var Lay in Layers) { - TargetWidget = Lay.GetComponent(); + TargetWidget = Lay.Value.GetComponent(); if (TargetWidget == null) { continue; @@ -550,8 +546,7 @@ public T FindClassInLayers() where T : class } // Abstract Methods - protected abstract void InitiateManager(bool alwaysLoaded); - protected abstract void InitiateService(Service newService); + protected abstract void InitiateManager(Scope owner); //Enumerators private IEnumerator FadeIn(CanvasGroup canvas, float fadeDuration) @@ -620,9 +615,5 @@ private IEnumerator FadeOut(CanvasGroup canvas, float fadeDuration, System.Actio } - public interface IWidget - { - MonoBehaviour GetWidgetClass(); - void SceneInitialized(UIManager manager); - } + } diff --git a/Runtime/Pattern/Services/InputService.cs b/Runtime/Pattern/Services/InputService.cs index 65f80e91..4d87e43a 100644 --- a/Runtime/Pattern/Services/InputService.cs +++ b/Runtime/Pattern/Services/InputService.cs @@ -3,31 +3,37 @@ namespace RealMethod { - public abstract class InputService : Service + public abstract class InputService : GameModule { private InputActionAsset CurrentInputAsset; - protected sealed override void OnStart(object Author) + protected override void OnBegin() { if (TryFindInputAsset(out InputActionAsset newAsset)) { ReplaceInputAsset(newAsset); } } - protected sealed override void OnNewWorld() + protected override void OnWorldChanged() { if (TryFindInputAsset(out InputActionAsset newAsset)) { ReplaceInputAsset(newAsset); } } - protected sealed override void OnEnd(object Author) + protected override void OnEnd() { if (CurrentInputAsset != null) { OnDisposeInputAsset(CurrentInputAsset); } } +#if UNITY_EDITOR + protected override string GetInspectorInfo() + { + return CurrentInputAsset.name; + } +#endif public void ReplaceInputAsset(InputActionAsset asset) @@ -64,6 +70,8 @@ protected virtual bool TryFindInputAsset(out InputActionAsset asset) protected abstract void OnAcquireInputAsset(InputActionAsset asset); protected abstract void OnDisposeInputAsset(InputActionAsset asset); + + } diff --git a/Runtime/Pattern/Services/RuleService.cs b/Runtime/Pattern/Services/RuleService.cs index 45d60d48..a0247b68 100644 --- a/Runtime/Pattern/Services/RuleService.cs +++ b/Runtime/Pattern/Services/RuleService.cs @@ -2,22 +2,33 @@ namespace RealMethod { - public abstract class RuleService : Service + public interface IRuleService : IService { - public Action OnAddedRule; - public Action OnFinishRule; - private Hictionary> Rules; + bool InEffect(string rule); + bool IsValid(string rule); + void BindRule(string Name, Action callback); + event Action OnAddedRule; + event Action OnFinishRule; + } + + + public abstract class RuleService : GameModule, IRuleService + { + public event Action OnAddedRule; + public event Action OnFinishRule; + private NameTable> Rules; public RuleService() { - Rules = new Hictionary>(5); + Rules = new NameTable>(5); } - protected override void OnNewWorld() + + protected override void OnWorldChanged() { - foreach (var item in Rules.GetValues()) + foreach (var item in Rules) { - item.Check(); + item.Value.Check(); } } @@ -37,9 +48,9 @@ public void Check(string rule) } public void UpdateRules() { - foreach (Observer item in Rules.GetValues()) + foreach (var item in Rules) { - item.Check(); + item.Value.Check(); } } public bool InEffect(string rule) diff --git a/Runtime/Pattern/Services/StateService.cs b/Runtime/Pattern/Services/StateService.cs index 0b46d999..12e15e6c 100644 --- a/Runtime/Pattern/Services/StateService.cs +++ b/Runtime/Pattern/Services/StateService.cs @@ -3,7 +3,7 @@ namespace RealMethod { - public abstract class StateService : Service + public abstract class StateService : GameModule { protected byte currentState { get; private set; } protected byte previousState { get; private set; } @@ -16,14 +16,13 @@ public StateService(byte firstState) } // StateService Methods - protected sealed override void OnNewWorld() + protected override void OnWorldChanged() { if (CanResetforNewWorld(Game.World)) { ResetToDefault(); } } - // Public Functions public bool SetState(byte target) { diff --git a/Runtime/ReadySet/Commands/Execut/C_Death.cs b/Runtime/ReadySet/Commands/Execut/C_Death.cs index 9fe2519c..d46712fd 100644 --- a/Runtime/ReadySet/Commands/Execut/C_Death.cs +++ b/Runtime/ReadySet/Commands/Execut/C_Death.cs @@ -11,15 +11,10 @@ public sealed class C_Death : Command private bool UseExecuter = true; [SerializeField, ConditionalHide("UseExecuter", true, true)] private GameObject Target; - [Header("Method")] - [SerializeField] - private bool WithInterface = true; - [SerializeField] - private bool WithSendMessage = false; // Base ExecutCommand Methods - protected override bool OnInitiate(Object author, Object owner) + protected override bool OnInitiate(Object owner) { return true; } @@ -27,12 +22,12 @@ protected override bool CanExecute(object Owner) { return enabled; } - protected override void Execute(object Owner) + protected override void Execute(object Executer) { if (UseExecuter) { - if (Owner is MonoBehaviour Mono) + if (Executer is MonoBehaviour Mono) { ApplyDeath(Mono.gameObject); } @@ -56,25 +51,7 @@ private void ApplyDeath(GameObject target) return; } - // Interface - if (WithInterface) - { - IDamage interfce = target.GetComponent(); - if (interfce != null) - { - interfce.Die(); - } - else - { - Debug.LogError($"IDamage interface not found on the {target}."); - } - } - - // SendMessage - if (WithSendMessage) - { - target.SendMessage("Die", SendMessageOptions.RequireReceiver); - } + target.Death(); } } diff --git a/Runtime/ReadySet/Commands/Execut/C_Event.cs b/Runtime/ReadySet/Commands/Execut/C_Event.cs index 81154518..be19f787 100644 --- a/Runtime/ReadySet/Commands/Execut/C_Event.cs +++ b/Runtime/ReadySet/Commands/Execut/C_Event.cs @@ -9,23 +9,23 @@ public sealed class C_Event : Command public UnityEvent OnExecute; // ExecutCommand Methods - protected override bool OnInitiate(Object author, Object owner) + protected override bool OnInitiate( Object owner) { return true; } - protected override bool CanExecute(object Owner) + protected override bool CanExecute(object Executer) { return enabled; } - protected override void Execute(object Owner) + protected override void Execute(object Executer) { - if (Owner is MonoBehaviour MyOwner) + if (Executer is MonoBehaviour MyOwner) { OnExecute?.Invoke(MyOwner); } else { - Debug.LogError("Event_com.Execute: Owner is not a MonoBehaviour. Event not invoked."); + Debug.LogError("Event_com.Execute: Executer is not a MonoBehaviour. Event not invoked."); } } } diff --git a/Runtime/ReadySet/Commands/Execut/C_EventCollider.cs b/Runtime/ReadySet/Commands/Execut/C_EventCollider.cs index 100dfb47..2f1bf7bf 100644 --- a/Runtime/ReadySet/Commands/Execut/C_EventCollider.cs +++ b/Runtime/ReadySet/Commands/Execut/C_EventCollider.cs @@ -9,23 +9,23 @@ public sealed class C_EventCollider : Command public UnityEvent OnTrigger; // ExecutCommand Methods - protected override bool OnInitiate(Object author, Object owner) + protected override bool OnInitiate(Object owner) { return true; } - protected override bool CanExecute(object Owner) + protected override bool CanExecute(object Executer) { return enabled; } - protected override void Execute(object Owner) + protected override void Execute(object Executer) { - if (Owner is Collider col) + if (Executer is Collider col) { OnTrigger?.Invoke(col); } else { - Debug.LogError("EventCollider_com.Execute: Owner is not a Collider. Event not invoked."); + Debug.LogError("EventCollider_com.Execute: Executer is not a Collider. Event not invoked."); } } } diff --git a/Runtime/ReadySet/Commands/Execut/C_Fracture.cs b/Runtime/ReadySet/Commands/Execut/C_Fracture.cs index 5333b70d..dcb74145 100644 --- a/Runtime/ReadySet/Commands/Execut/C_Fracture.cs +++ b/Runtime/ReadySet/Commands/Execut/C_Fracture.cs @@ -37,7 +37,7 @@ public sealed class C_Fracture : Command // ExecutCommand Methods - protected override bool OnInitiate(UnityEngine.Object author, UnityEngine.Object owner) + protected override bool OnInitiate(UnityEngine.Object owner) { if (HealthyObject) HealthyObject.SetActive(true); @@ -45,19 +45,19 @@ protected override bool OnInitiate(UnityEngine.Object author, UnityEngine.Object DamagedObject.SetActive(false); return true; } - protected override bool CanExecute(object Owner) + protected override bool CanExecute(object Executer) { return enabled; } - protected override void Execute(object Owner) + protected override void Execute(object Executer) { - if (Owner is Collider col) + if (Executer is Collider col) { Fracture(col); return; } - if (Owner is Transform trans) + if (Executer is Transform trans) { Fracture(trans); } diff --git a/Runtime/ReadySet/Commands/Execut/C_Haptic.cs b/Runtime/ReadySet/Commands/Execut/C_Haptic.cs index c1cb3c79..b5f716ce 100644 --- a/Runtime/ReadySet/Commands/Execut/C_Haptic.cs +++ b/Runtime/ReadySet/Commands/Execut/C_Haptic.cs @@ -10,16 +10,16 @@ public sealed class C_Haptic : Command private HapticManager manager; // Command Methods - protected override bool OnInitiate(Object author, Object owner) + protected override bool OnInitiate(Object owner) { - manager = Game.FindManager(); + manager = Game.GetManager(); return manager != null; } - protected override bool CanExecute(object Owner) + protected override bool CanExecute(object Executer) { return enabled && manager != null; } - protected override void Execute(object Owner) + protected override void Execute(object Executer) { foreach (var conf in configs) { diff --git a/Runtime/ReadySet/Commands/Execut/C_Notify.cs b/Runtime/ReadySet/Commands/Execut/C_Notify.cs index 518862b4..4d7106e4 100644 --- a/Runtime/ReadySet/Commands/Execut/C_Notify.cs +++ b/Runtime/ReadySet/Commands/Execut/C_Notify.cs @@ -56,16 +56,16 @@ private enum TimerBehavior // ExecutCommand Methods - protected override bool OnInitiate(Object author, Object owner) + protected override bool OnInitiate(Object owner) { NotifyStatus = new bool[notify.Length]; return true; } - protected override bool CanExecute(object Owner) + protected override bool CanExecute(object Executer) { return enabled; } - protected override void Execute(object Owner) + protected override void Execute(object Executer) { StartTimer(); } diff --git a/Runtime/ReadySet/Commands/Execut/C_ScneLoader.cs b/Runtime/ReadySet/Commands/Execut/C_ScneLoader.cs index f557d3f1..cbb5ba58 100644 --- a/Runtime/ReadySet/Commands/Execut/C_ScneLoader.cs +++ b/Runtime/ReadySet/Commands/Execut/C_ScneLoader.cs @@ -17,18 +17,18 @@ private enum LoadMethod [Header("Assets")] [SerializeField] private LoadMethod method = LoadMethod.SceneAsset; - [SerializeField, ShowInInspectorByEnum("method", 0)] + [SerializeField, ConditionalShowByEnum("method", 0)] private int sceneIndex; - [SerializeField, ShowInInspectorByEnum("method", 1)] + [SerializeField, ConditionalShowByEnum("method", 1)] private string sceneName; - [SerializeField, ShowInInspectorByEnum("method", 2)] - private SceneReference sceneAsset; - [SerializeField, ShowInInspectorByEnum("method", 3)] - private WorldSceneConfig worldAsset; + [SerializeField, ConditionalShowByEnum("method", 2)] + private SceneAsset sceneAsset; + [SerializeField, ConditionalShowByEnum("method", 3)] + private WorldAsset worldAsset; [Header("Setting")] - [SerializeField, ShowInInspectorByEnum("method", 0, 1)] + [SerializeField, ConditionalShowByEnum("method", 0, 1)] private bool IsAsync = false; - [SerializeField, ShowInInspectorByEnum("method", 0, 1)] + [SerializeField, ConditionalShowByEnum("method", 0, 1)] private LoadSceneMode LoadType = LoadSceneMode.Single; public Action OnAsyncSceneLoaded; @@ -36,15 +36,15 @@ private enum LoadMethod // ExecutCommand Methods - protected override bool OnInitiate(UnityEngine.Object author, UnityEngine.Object owner) + protected override bool OnInitiate(UnityEngine.Object owner) { return true; } - protected override bool CanExecute(object Owner) + protected override bool CanExecute(object Executer) { return enabled; } - protected override void Execute(object Owner) + protected override void Execute(object Executer) { switch (method) { diff --git a/Runtime/ReadySet/Commands/Execut/C_Spawner.cs b/Runtime/ReadySet/Commands/Execut/C_Spawner.cs index 4941320d..9899971f 100644 --- a/Runtime/ReadySet/Commands/Execut/C_Spawner.cs +++ b/Runtime/ReadySet/Commands/Execut/C_Spawner.cs @@ -16,22 +16,22 @@ public sealed class C_Spawner : Command [SerializeField] private Prefab PrefabAsset; // ExecutCommand Methods - protected override bool OnInitiate(Object author, Object owner) + protected override bool OnInitiate(Object owner) { return true; } - protected override bool CanExecute(object Owner) + protected override bool CanExecute(object Executer) { return enabled; } - protected override void Execute(object Owner) + protected override void Execute(object Executer) { if (PrefabAsset == null) return; if (AutoAttach) { - if (Owner is MonoBehaviour Mono) + if (Executer is MonoBehaviour Mono) { Transform target = Spawn.Prefab(PrefabAsset, Mono.transform); if (!SelfPose) diff --git a/Runtime/ReadySet/Components/Method/PlayerStarterComponent.cs b/Runtime/ReadySet/Components/Method/PlayerStarterComponent.cs new file mode 100644 index 00000000..afddb9ec --- /dev/null +++ b/Runtime/ReadySet/Components/Method/PlayerStarterComponent.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace RealMethod +{ + [AddComponentMenu("RealMethod/Method/PlayerStarter")] + public sealed class PlayerStarterComponent : PlayerStarter + { + + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Components/Method/PlayerStarterComponent.cs.meta b/Runtime/ReadySet/Components/Method/PlayerStarterComponent.cs.meta new file mode 100644 index 00000000..95d243cc --- /dev/null +++ b/Runtime/ReadySet/Components/Method/PlayerStarterComponent.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bd7492c4fc6b670479f8f302f507dd22 \ No newline at end of file diff --git a/Runtime/ReadySet/Components/Method/RuleEvent.cs b/Runtime/ReadySet/Components/Method/RuleEvent.cs index 3a230c05..80566714 100644 --- a/Runtime/ReadySet/Components/Method/RuleEvent.cs +++ b/Runtime/ReadySet/Components/Method/RuleEvent.cs @@ -14,12 +14,13 @@ public sealed class RuleEvent : MonoBehaviour [SerializeField] private UnityEvent RuleEffect; - private RuleService ruleServ; + private IRuleService ruleServ; public bool IsServiceRegistered => ruleServ != null; private void Awake() { - if (Game.TryFindService(out ruleServ)) + ruleServ = Game.GetService(); + if (ruleServ != null) { if (ruleServ.IsValid(Rule)) { diff --git a/Runtime/ReadySet/Components/Physic/CommandTrigger2D.cs b/Runtime/ReadySet/Components/Physic/CommandTrigger2D.cs index cb1c99cb..7dd735b8 100644 --- a/Runtime/ReadySet/Components/Physic/CommandTrigger2D.cs +++ b/Runtime/ReadySet/Components/Physic/CommandTrigger2D.cs @@ -10,7 +10,7 @@ private void Awake() { foreach (var command in GetComponents()) { - command.Initiate(null, this); + command.Initiate(this); } } diff --git a/Runtime/ReadySet/Components/Physic/CommandTrigger3D.cs b/Runtime/ReadySet/Components/Physic/CommandTrigger3D.cs index a75c6deb..8a484deb 100644 --- a/Runtime/ReadySet/Components/Physic/CommandTrigger3D.cs +++ b/Runtime/ReadySet/Components/Physic/CommandTrigger3D.cs @@ -10,7 +10,7 @@ private void Awake() { foreach (var command in GetComponents()) { - command.Initiate(null, this); + command.Initiate(this); } } diff --git a/Runtime/ReadySet/Components/Time/DestroyAfterDelay.cs b/Runtime/ReadySet/Components/Time/DestroyAfterDelay.cs index de8cfde6..c14b6847 100644 --- a/Runtime/ReadySet/Components/Time/DestroyAfterDelay.cs +++ b/Runtime/ReadySet/Components/Time/DestroyAfterDelay.cs @@ -3,12 +3,12 @@ namespace RealMethod { [AddComponentMenu("RealMethod/Time/DestroyAfterDelay")] - public sealed class DestroyAfterDelay : MonoBehaviour, IInitializableWithArgument + public sealed class DestroyAfterDelay : MonoBehaviour, ISpawnWithArgument { public float Delay = 5; // Implement IInitializableWithArgument Interface - public void Initialize(float argument) + public void OnSpawn(float argument) { Delay = argument; } diff --git a/Runtime/ReadySet/Components/UI/UI_GameSetting.cs b/Runtime/ReadySet/Components/UI/UI_GameSetting.cs index c4241be3..5e2954ea 100644 --- a/Runtime/ReadySet/Components/UI/UI_GameSetting.cs +++ b/Runtime/ReadySet/Components/UI/UI_GameSetting.cs @@ -6,8 +6,8 @@ namespace RealMethod { [Serializable] - public class SelectableElement : SerializableDictionary { } - public interface ISettingStorage : IStorage + public class SelectableElement : Map { } + public interface ISettingStorage : IFile { bool IsSettingDirty { get; } void OnFileSynced(); @@ -25,10 +25,10 @@ public sealed class UI_GameSetting : MonoBehaviour private SelectableElement UIElements; [Header("Save")] [SerializeField] - private StorageFile Storage; + private Storage Storage; - public bool isFileDirty => Storage.provider.IsSettingDirty; - public SaveFile file => Storage.file; + public bool isFileDirty => Storage.File.IsSettingDirty; + public ISettingStorage file => Storage.File; public bool isInSync { get; private set; } = false; // Unity Methods @@ -60,11 +60,11 @@ private void Awake() private void OnEnable() { // Sacan all variable in save file - Scaning.Scan(Storage.file); + Scaning.Scan(Storage.File); } private void Start() { - Storage.Load(this); + Storage.Refresh(); SyncUI(); } private void OnDisable() @@ -84,28 +84,28 @@ public void SyncFile(Selectable element) } foreach (FieldInfo field in Scaning.GetFields()) { - object value = field.GetValue(Storage.file); + object value = field.GetValue(Storage.File); switch (value) { case float f: if (element is Slider slide) { if (field.Name == label) - field.SetValue(Storage.file, slide.value); + field.SetValue(Storage.File, slide.value); } break; case int i: if (element is Dropdown dropdown) { if (field.Name == label) - field.SetValue(Storage.file, dropdown.value); + field.SetValue(Storage.File, dropdown.value); } break; case bool b: if (element is Toggle toggle) { if (field.Name == label) - field.SetValue(Storage.file, toggle.isOn); + field.SetValue(Storage.File, toggle.isOn); } break; default: @@ -113,7 +113,7 @@ public void SyncFile(Selectable element) break; } } - Storage.provider.OnFileSynced(); + Storage.File.OnFileSynced(); isInSync = false; } public void SyncFile() @@ -126,25 +126,25 @@ public void SyncFile() { if (element.Key == fileData[i].Name) { - object value = fileData[i].GetValue(Storage.file); + object value = fileData[i].GetValue(Storage.File); switch (value) { case float fl: if (element.Value is Slider slide) { - fileData[i].SetValue(Storage.file, slide.value); + fileData[i].SetValue(Storage.File, slide.value); } break; case int iin: if (element.Value is Dropdown dropdown) { - fileData[i].SetValue(Storage.file, dropdown.value); + fileData[i].SetValue(Storage.File, dropdown.value); } break; case bool bo: if (element.Value is Toggle toggle) { - fileData[i].SetValue(Storage.file, toggle.isOn); + fileData[i].SetValue(Storage.File, toggle.isOn); } break; default: @@ -154,7 +154,7 @@ public void SyncFile() } } } - Storage.provider.OnFileSynced(); + Storage.File.OnFileSynced(); isInSync = false; } [ContextMenu("Sync_UI")] @@ -168,7 +168,7 @@ public void SyncUI() { if (element.Key == fileData[i].Name) { - object value = fileData[i].GetValue(Storage.file); + object value = fileData[i].GetValue(Storage.File); switch (value) { case float fl: @@ -243,29 +243,29 @@ private void OnToggleChanged(bool value) } } - public abstract class SettingFile : SaveFile, ISettingStorage + public abstract class SettingFile : SaveFileAsset, ISettingStorage { protected bool IsDirty { get; private set; } // Implement ISettingStorage Interface public bool IsSettingDirty => IsDirty; - void IStorage.StorageCreated(UnityEngine.Object author) - { - SetupSettingData(); - } - void IStorage.StorageLoaded(UnityEngine.Object author) - { - ApplySettingData(); - } + // void IStorage.StorageCreated(UnityEngine.Object author) + // { + // SetupSettingData(); + // } + // void IStorage.StorageLoaded(UnityEngine.Object author) + // { + // ApplySettingData(); + // } void ISettingStorage.OnFileSynced() { IsDirty = true; ApplySettingData(); } - void IStorage.StorageClear() - { - OnResetSetting(); - } + // void IStorage.StorageClear() + // { + // OnResetSetting(); + // } // Protected Method protected sealed override void OnSaved() diff --git a/Runtime/ReadySet/Components/Visual/EffectPlayer.cs b/Runtime/ReadySet/Components/Visual/EffectPlayer.cs index f8700d55..0ea64ee8 100644 --- a/Runtime/ReadySet/Components/Visual/EffectPlayer.cs +++ b/Runtime/ReadySet/Components/Visual/EffectPlayer.cs @@ -25,7 +25,7 @@ private void Awake() ICommand[] CommandInitators = GetComponents(); foreach (var com in CommandInitators) { - com.Initiate(this, this); + com.Initiate(this); } } private void OnEnable() diff --git a/Runtime/ReadySet/DefaultsClass/DefaultGame.cs b/Runtime/ReadySet/DefaultsClass/DefaultGame.cs deleted file mode 100644 index 764b121b..00000000 --- a/Runtime/ReadySet/DefaultsClass/DefaultGame.cs +++ /dev/null @@ -1,27 +0,0 @@ - -using UnityEngine; - -namespace RealMethod -{ - [AddComponentMenu("RealMethod/Essential/DefultGame")] - public sealed class DefultGame : Game - { - protected override void GameInitialized() - { - Debug.Log("DefultGame Initialized"); - } - protected override void GameStarted() - { - Debug.Log("DefultGame Started"); - } - protected override void GameWorldSynced(World NewWorld) - { - Debug.Log($"DefultGame Synced to {NewWorld}"); - } - protected override void GameClosed() - { - Debug.Log("DefultGame Closed"); - } - - } -} diff --git a/Runtime/ReadySet/DefaultsClass/DefaultGame.cs.meta b/Runtime/ReadySet/DefaultsClass/DefaultGame.cs.meta deleted file mode 100644 index 00d5c8db..00000000 --- a/Runtime/ReadySet/DefaultsClass/DefaultGame.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: a9b35df15c1e89149aac0cecec223892 \ No newline at end of file diff --git a/Runtime/ReadySet/DefaultsClass/DefaultGameConfig.cs.meta b/Runtime/ReadySet/DefaultsClass/DefaultGameConfig.cs.meta deleted file mode 100644 index a5c7c23f..00000000 --- a/Runtime/ReadySet/DefaultsClass/DefaultGameConfig.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 6e2afeeef06adef459b7e9f845f1f27d \ No newline at end of file diff --git a/Runtime/ReadySet/DefaultsClass/DefaultGameService.cs b/Runtime/ReadySet/DefaultsClass/DefaultGameService.cs deleted file mode 100644 index 79b3c9fb..00000000 --- a/Runtime/ReadySet/DefaultsClass/DefaultGameService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public sealed class DefaultGameService : GameService - { - protected override void OnStart(object Author) - { - Debug.Log("DefaultService Started"); - } - protected override void OnNewWorld() - { - } - protected override void OnNewAdditiveWorld(World target) - { - - } - protected override void OnEnd(object Author) - { - Debug.Log("DefaultService Ended"); - } - } -} \ No newline at end of file diff --git a/Runtime/ReadySet/DefaultsClass/DefaultGameService.cs.meta b/Runtime/ReadySet/DefaultsClass/DefaultGameService.cs.meta deleted file mode 100644 index 8e1d1fa5..00000000 --- a/Runtime/ReadySet/DefaultsClass/DefaultGameService.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 1fb3607f9f50dff45825e72bce5f8c09 \ No newline at end of file diff --git a/Runtime/ReadySet/Managers/ActionManager.cs b/Runtime/ReadySet/Managers/ActionManager.cs new file mode 100644 index 00000000..94c0bf30 --- /dev/null +++ b/Runtime/ReadySet/Managers/ActionManager.cs @@ -0,0 +1,59 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + + public interface IAction : IHandle + { + void Starter(); + } + public interface IActionTask : ITask + { + + } + + public sealed class ActionClass : SoftType + { + + } + + + + [AddComponentMenu("RealMethod/Manager/ActionManager")] + public sealed class ActionManager : TaskManager + { + [Header("Action")] + private SoftType[] DefaultActions; + + // TaskMaanger Methods + protected override void InitiateManager(Scope owner) + { + if (DefaultActions != null) + { + for (int i = 0; i < DefaultActions.Length; i++) + { + Create(DefaultActions[i]); + } + } + } + protected override bool TryCreateNewInstance

(object ClassType, out P result) + { + if (ClassType is ActionClass ActionType) + { + result = ActionType.Type.CreateInstance() as P; + return true; + } + else + { + result = null; + return false; + } + } + protected override void AutoStart(IAction Handle) + { + Handle.Starter(); + } + + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Managers/TaskManager.cs.meta b/Runtime/ReadySet/Managers/ActionManager.cs.meta similarity index 100% rename from Runtime/ReadySet/Managers/TaskManager.cs.meta rename to Runtime/ReadySet/Managers/ActionManager.cs.meta diff --git a/Runtime/ReadySet/Managers/CoroutineManager.cs b/Runtime/ReadySet/Managers/CoroutineManager.cs index 59b001a5..29a9efb2 100644 --- a/Runtime/ReadySet/Managers/CoroutineManager.cs +++ b/Runtime/ReadySet/Managers/CoroutineManager.cs @@ -1,21 +1,13 @@ +using UnityEngine; + namespace RealMethod { + [AddComponentMenu("RealMethod/Manager/CoroutineManager")] public class CoroutineManager : EnumeratorManager { // EnumeratorManager Methods - protected override void InitiateManager(bool alwaysLoaded) - { - if (Game.TryFindService(out Spawn SpawnServ)) - { - SpawnServ.BringManager(this); - } - } - protected override void InitiateService(Service service) + protected override void InitiateManager(Scope owner) { - if (service is Spawn spawnservice) - { - spawnservice.BringManager(this); - } } } diff --git a/Runtime/ReadySet/Managers/DevManager.cs b/Runtime/ReadySet/Managers/DevManager.cs new file mode 100644 index 00000000..6b64a33a --- /dev/null +++ b/Runtime/ReadySet/Managers/DevManager.cs @@ -0,0 +1,16 @@ +#if UNITY_EDITOR || DEVELOPMENT_BUILD +using System.Reflection; +using UnityEngine; + +namespace RealMethod +{ + [AddComponentMenu("RealMethod/Manager/DeveloperManager")] + public class DevManager : DeveloperManager + { + // DeveloperManager Methods + public override void InitiateManager(Scope owner) + { + } + } +} +#endif \ No newline at end of file diff --git a/Runtime/ReadySet/Managers/DevManager.cs.meta b/Runtime/ReadySet/Managers/DevManager.cs.meta new file mode 100644 index 00000000..82c30f3d --- /dev/null +++ b/Runtime/ReadySet/Managers/DevManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ab9dc0e8c357282459cab65d10fb9e49 \ No newline at end of file diff --git a/Runtime/ReadySet/Managers/HUDManager.cs b/Runtime/ReadySet/Managers/HUDManager.cs index adfb47a0..fd74d8d9 100644 --- a/Runtime/ReadySet/Managers/HUDManager.cs +++ b/Runtime/ReadySet/Managers/HUDManager.cs @@ -7,19 +7,8 @@ public sealed class HUDManager : UIManager { // UIManager Methods - protected override void InitiateManager(bool alwaysLoaded) + protected override void InitiateManager(Scope owner) { - if (Game.TryFindService(out Spawn SpawnServ)) - { - SpawnServ.BringManager(this); - } - } - protected override void InitiateService(Service newService) - { - if (newService is Spawn spawnservice) - { - spawnservice.BringManager(this); - } } } diff --git a/Runtime/ReadySet/Managers/MotionManager.cs b/Runtime/ReadySet/Managers/MotionManager.cs index 394399bc..da89f9ac 100644 --- a/Runtime/ReadySet/Managers/MotionManager.cs +++ b/Runtime/ReadySet/Managers/MotionManager.cs @@ -1,104 +1,259 @@ - using UnityEngine; namespace RealMethod { - public interface IMotion : IBehaviourAction , ITick + public interface IMotion : IHandleBehaviourAction + { + } + public interface IMotionTask : ITask { } - public sealed class MotionManager : TickManager + public abstract class MotionAsset : CloneAsset, IMotion, IMotionTask { - [Header("Motion")] + [Header("Task")] [SerializeField] - private MotionAsset[] DefaultMotions; + private bool infinit = false; + [SerializeField, ConditionalHide("infinit", true, true)] + private float baseDuration = 5; + public bool IsEnable { get; private set; } - // TickManager Methods - protected override void InitiateManager(bool alwaysLoaded) + + // Private Variable + private bool islive = false; + private bool isRunning = true; + private float residuary = -1; + private float lifetime = -1; + + + // Implement ITask Interface + void ITask.Active() { - if (DefaultMotions != null) + IsEnable = true; + OnEnable(); + } + void ITask.Deactive() + { + Finish(); + IsEnable = false; + OnDisable(); + } + // Implement ITask Interface + IMotion ITask.Controller => this; + // Implement ITick Interface + void ITick.Tick(float deltaTime) + { + // Check Initiate + if (!IsEnable) { - for (int i = 0; i < DefaultMotions.Length; i++) + Debug.LogError("First You Sould Validate"); + return; + } + + // Check Started + if (!islive) + { + return; + } + + // Gate for Puse Updating Command + if (!CanUpdate()) + { + return; + } + + // Handel Lifetime Command + if (residuary > 0) + { + // Calculate Time + residuary -= Time.deltaTime; + } + else + { + if (!infinit) + { + // Stop Command Teime over + residuary = 0; + Finish(); + return; + } + } + + OnUpdate(deltaTime); + } + // Implement IHandleBehaviour Interface + bool IHandleBehaviour.IsStarted => islive; + void IHandleBehaviour.Start() + { + lifetime = infinit ? 0 : baseDuration; + if (IsEnable) + { + if (!islive) { - Create(DefaultMotions[i], this); + residuary = lifetime; + OnBegin(); + islive = true; } } + else + { + Debug.LogError("First You Sould Active Task"); + } } - protected override void InitiateService(Service service) + void IHandleBehaviour.Stop() { + if (IsEnable) + { + if (islive) + { + islive = false; + OnEnd(); + } + } + else + { + Debug.LogError("First You Sould Initiate Command with ICommandInitiator"); + } } - protected override bool CheckUnit(MotionAsset unit) + void IHandleBehaviour.Clear() { - return true; + Finish(); + IsEnable = false; } - - public IMotion Create(MotionAsset motion, Object author) + // Implement IHandleBehaviourCycle Interface + bool IHandleBehaviourCycle.IsFinished => !islive; + bool IHandleBehaviourCycle.IsInfinit => infinit; + float IHandleBehaviourCycle.RemainingTime => residuary; + float IHandleBehaviourCycle.ElapsedTime => lifetime - residuary; + float IHandleBehaviourCycle.NormalizedTime => residuary / lifetime; + void IHandleBehaviourCycle.Start(float overrideTime) { - var TargetMotion = Instantiate(motion); - IMotion provider = TargetMotion; - provider.Start(); - units.Add(TargetMotion); - return provider; + lifetime = overrideTime; + if (IsEnable) + { + if (!islive) + { + residuary = lifetime; + OnBegin(); + islive = true; + } + } + else + { + Debug.LogError("First You Sould Initiate Behaviour"); + } } - public bool Delete() + // Implement IHandleBehaviourAction Interface + bool IHandleBehaviourAction.IsPaused => !isRunning; + void IHandleBehaviourAction.Pause() { - return true; + isRunning = false; + OnPause(); } - } - - public abstract class MotionAsset : DataAsset, IMotion - { - // Implement ITick Interface - void ITick.Tick(float deltaTime) + void IHandleBehaviourAction.Resume() { - Debug.Log(name); + isRunning = true; + OnResume(); } - // Implement IBehaviour Interface - bool IBehaviour.IsStarted => throw new System.NotImplementedException(); - void IBehaviour.Start() + void IHandleBehaviourAction.Reset() { - Debug.Log("Hello"); + ResetToDefault(); + isRunning = true; + OnReset(); } - void IBehaviour.Stop() + void IHandleBehaviourAction.Restart(float Duration) { - throw new System.NotImplementedException(); + ResetToDefault(); + isRunning = true; + OnReset(); + if (Duration > 0) + { + ((IHandleBehaviourCycle)this).Start(Duration); + } + else + { + ((IHandleBehaviourCycle)this).Start(); + } } - void IBehaviour.Clear() + + + // Method + protected void Finish() { - throw new System.NotImplementedException(); + if (islive) + ((IHandleBehaviour)this).Stop(); } - // Implement IBehaviourCycle Interface - bool IBehaviourCycle.IsFinished => throw new System.NotImplementedException(); - bool IBehaviourCycle.IsInfinit => throw new System.NotImplementedException(); - float IBehaviourCycle.RemainingTime => throw new System.NotImplementedException(); - float IBehaviourCycle.ElapsedTime => throw new System.NotImplementedException(); - float IBehaviourCycle.NormalizedTime => throw new System.NotImplementedException(); - void IBehaviourCycle.Start(float overrideTime) + protected void Reset() { - throw new System.NotImplementedException(); + IsEnable = false; + ResetToDefault(); } - // Implement IBehaviourAction Interface - bool IBehaviourAction.IsPaused => throw new System.NotImplementedException(); - void IBehaviourAction.Pause() + private void ResetToDefault() { - throw new System.NotImplementedException(); + islive = false; + isRunning = true; + lifetime = -1; + residuary = -1; } - void IBehaviourAction.Resume() + protected virtual bool CanUpdate() + { + return isRunning; + } + + + // Abstract Methods + protected abstract void OnEnable(); + protected abstract void OnBegin(); + protected abstract void OnUpdate(float deltaTime); + protected abstract void OnPause(); + protected abstract void OnResume(); + protected abstract void OnReset(); + protected abstract void OnEnd(); + protected abstract void OnDisable(); + } + + + [AddComponentMenu("RealMethod/Manager/MotionManager")] + public sealed class MotionManager : TaskManager + { + [Header("Motion")] + [SerializeField] + private MotionAsset[] DefaultMotions; + + + + // TickManager Methods + protected override void InitiateManager(Scope owner) { - throw new System.NotImplementedException(); + if (DefaultMotions != null) + { + for (int i = 0; i < DefaultMotions.Length; i++) + { + Create(DefaultMotions[i]); + } + } } - void IBehaviourAction.Reset() + protected override bool TryCreateNewInstance

(object ClassType, out P result) { - throw new System.NotImplementedException(); + if (ClassType is PrimitiveAsset asset) + { + result = ScriptableObject.Instantiate(asset) as P; + return true; + } + else + { + result = null; + return false; + } } - void IBehaviourAction.Restart(float Duration) + protected override void AutoStart(IMotion Handle) { - throw new System.NotImplementedException(); + Handle.Start(); } - } + } diff --git a/Runtime/ReadySet/Managers/MusicManager.cs b/Runtime/ReadySet/Managers/MusicManager.cs index 520e34d2..1f553074 100644 --- a/Runtime/ReadySet/Managers/MusicManager.cs +++ b/Runtime/ReadySet/Managers/MusicManager.cs @@ -3,96 +3,56 @@ namespace RealMethod { [AddComponentMenu("RealMethod/Manager/MusicManager")] - public sealed class MusicManager : CompositManager + public sealed class MusicManager : CompositManager { - [Header("Music")] + [Header("MusicList")] [SerializeField] - private AudioClip[] CreateLayers; - [SerializeField] - private bool AddServiceOnInitiate = false; + private Map Clips = new Map(); - protected override void OnInitiate(bool AlwaysLoaded) + // GameManager + public override void InitiateManager(Scope owner) { - foreach (var clip in CreateLayers) + base.InitiateManager(owner); + foreach (var clip in Clips) { - CreateLayer(clip); + CreateLayer(clip.Key, clip.Value); } - if (AddServiceOnInitiate) - Game.AddService(this); - } - protected override void MusicStateAssigned() - { } - } - - public enum DefaulMusicLayer - { - Default, - Menu, - StartGame, - Level, - Cutscene, - Victory, - Defeat, - GameOver, - Tutorial, - Loading, - Exploration, - Combat, - Dialogue, - Quest, - Fight, - BossFight, - Puzzle, - Hint, - Mission, - Story, - Chase, - Damaged, - Racing, - Pause, - Inventory, - EndGame, - } - - public sealed class DefaulMusicState : StateService - { - public DefaulMusicState() : base(DefaulMusicLayer.Default) // Replace default(StateList) with an actual enum value if needed + // Unity Methods + private void OnEnable() { - + Game.State.OnStateChanged += OnStateChange; } - - // Service Methods - protected override void OnStart(object Author) + protected override void Start() { + if (PlayOnStart) + { + CurrentState = Game.State; + } + base.Start(); } - protected override void OnEnd(object Author) + private void OnDisable() { - + Game.State.OnStateChanged -= OnStateChange; } - // StateService Methods - protected override DefaulMusicLayer DefaultState() + // CompositManager Methods + protected override bool CompairStates(GlobalEnum State_A, GlobalEnum State_B) { - return DefaulMusicLayer.Default; + return State_A == State_B; } - public override bool CanSwitch(DefaulMusicLayer A, DefaulMusicLayer B) + + // Functions + private void OnStateChange(GlobalEnum a, GlobalEnum b) { - if (A == B) + if (IsValidState(b)) { - return false; + PlayState(b); } - return true; } - protected override bool CanResetforNewWorld(World NewWorld) - { - return false; - } - } - } \ No newline at end of file diff --git a/Runtime/ReadySet/Managers/PrintManager.cs b/Runtime/ReadySet/Managers/PrintManager.cs deleted file mode 100644 index cbf5c3f9..00000000 --- a/Runtime/ReadySet/Managers/PrintManager.cs +++ /dev/null @@ -1,429 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using UnityEngine; - -namespace RealMethod -{ - - [Serializable] - public class LogData - { - public string message; - public float duration; - public float x, y; - public int size; - public Color TextColor; - public LogType messagetype; - public Vector2 position => new Vector2(x, y); - - public LogData(string Message) - { - message = Message; - duration = 2f; - x = -1; - y = -1; - size = 1; - TextColor = Color.black; - messagetype = LogType.Log; - } - - public LogData(string Message, LogType type) - { - message = Message; - duration = 2f; - x = -1; - y = -1; - size = 1; - TextColor = GetColor(type); - messagetype = type; - } - public LogData(string Message, bool Console) - { - message = Message; - duration = 2f; - x = -1; - y = -1; - size = 1; - TextColor = Color.cyan; - messagetype = LogType.Log; - } - - public LogData(string Message, float Duration) - { - message = Message; - duration = Duration; - x = -1; - y = -1; - size = 1; - TextColor = Color.cyan; - messagetype = LogType.Log; - } - public LogData(string Message, float Duration, LogType type) - { - message = Message; - duration = Duration; - x = -1; - y = -1; - size = 1; - TextColor = GetColor(type); - messagetype = type; - } - public LogData(string Message, float Duration, bool Console) - { - message = Message; - duration = Duration; - x = -1; - y = -1; - size = 1; - TextColor = Color.cyan; - messagetype = LogType.Exception; - } - - public LogData(string Message, float Duration, Color TargetColor) - { - message = Message; - duration = Duration; - x = -1; - y = -1; - size = 1; - TextColor = TargetColor; - messagetype = LogType.Log; - } - - public LogData(string Message, Color TargetColor) - { - message = Message; - duration = 2f; - x = -1; - y = -1; - size = 1; - TextColor = TargetColor; - messagetype = LogType.Log; - } - - public LogData(string Message, float Duration, float X, float Y) - { - message = Message; - duration = Duration; - x = X; - y = Y; - size = 1; - TextColor = Color.cyan; - messagetype = LogType.Log; - } - public LogData(string Message, float Duration, float X, float Y, Color TargetColor) - { - message = Message; - duration = Duration; - x = X; - y = Y; - size = 1; - TextColor = TargetColor; - messagetype = LogType.Log; - } - - public LogData(string Message, float X, float Y) - { - message = Message; - duration = 2f; - x = X; - y = Y; - size = 1; - TextColor = Color.cyan; - messagetype = LogType.Log; - } - - public LogData(string Message, float Duration, float X, float Y, int Size) - { - message = Message; - duration = Duration; - x = X; - y = Y; - size = Size; - TextColor = Color.cyan; - messagetype = LogType.Log; - } - - public LogData(string Message, float X, float Y, int Size, bool Console, LogType type) - { - message = Message; - duration = 2f; - x = X; - y = Y; - size = Size > 0 ? Size : 1; - TextColor = Color.cyan; - messagetype = type; - } - - public LogData(string Message, float Duration, float X, float Y, int Size, Color TargetColor) - { - message = Message; - duration = Duration; - x = X; - y = Y; - size = Size > 0 ? Size : 1; - TextColor = TargetColor; - messagetype = LogType.Log; - } - public LogData(string Message, float Duration, float X, float Y, int Size, LogType type) - { - message = Message; - duration = Duration; - x = X; - y = Y; - size = Size > 0 ? Size : 1; - TextColor = GetColor(type); - messagetype = type; - } - - - private Color GetColor(LogType type) - { - switch (type) - { - case LogType.Log: - return Color.cyan; - case LogType.Warning: - return Color.yellow; - case LogType.Error: - return Color.red; - case LogType.Assert: - return Color.black; - case LogType.Exception: - return Color.white; - default: - return Color.blue; - } - } - } - [Serializable] - public class ButtonData - { - [SerializeField] string Name = "Button"; - [SerializeField] string Description = "This is a tooltip for the button"; - - [SerializeField] object TargetObject; - [SerializeField] string MethodName; - bool IsFunctionMethod = false; - [SerializeField] object[] MethodParametr; - - public ButtonData(string name, string description, object targetObject, string methodName, object[] methodParametr) - { - Name = name; - Description = description; - TargetObject = targetObject; - MethodName = methodName; - IsFunctionMethod = true; - MethodParametr = methodParametr; - } - - public ButtonData(string name, string description, object targetObject, string methodName) - { - Name = name; - Description = description; - TargetObject = targetObject; - MethodName = methodName; - } - - public ButtonData(string name, object targetObject, string methodName) - { - Name = name; - TargetObject = targetObject; - MethodName = methodName; - } - - public bool ButtonPressed() - { - bool Result; - if (IsFunctionMethod) - { - Type type = TargetObject.GetType(); - MethodInfo method = type.GetMethod(MethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - - if (method != null) - { - method.Invoke(TargetObject, MethodParametr); - Result = true; - } - else - { - Print.LogWarning("Method " + MethodName + " not found on " + TargetObject); - Result = false; - } - } - else - { - // Get the type of the target object - Type type = TargetObject.GetType(); - - // Find the method with the specified name - MethodInfo method = type.GetMethod(MethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - - if (method != null) - { - // Invoke the method on the target object - method.Invoke(TargetObject, null); - Result = true; - } - else - { - Print.LogWarning("Method " + MethodName + " not found on " + TargetObject); - Result = false; - } - } - - return Result; - } - public string GetName() - { - return Name; - } - public string GetDescription() - { - return Description; - } - - } - - [AddComponentMenu("RealMethod/Manager/PrintManager")] - public sealed class PrintManager : GizmoManager - { - private class LogRender : GUIRenderer - { - private PrintManager MyOWner; - public override void Start(GizmoManager Manager) - { - MyOWner = Manager as PrintManager; - } - public override bool CanRender() - { - return MyOWner.Logs.Count > 0; - } - public override void Draw() - { - for (int i = 0; i < MyOWner.Logs.Count; i++) - { - DrawLog(MyOWner.Logs[i], i); - } - } - - private void DrawLog(LogData log, int index) - { - int w = Screen.width * log.size; - int h = Screen.height * log.size; - float Xpos = log.position.x > 0 ? log.position.x : MyOWner.DefualtPosition.x; - float Ypos = log.position.y > 0 ? log.position.y : MyOWner.DefualtPosition.y + (index * MyOWner.PrintSpace); - - GUIStyle style = new GUIStyle(); - Rect rect = new Rect(Xpos, Ypos, w, h * 2 / 100); - style.alignment = TextAnchor.UpperLeft; - style.fontSize = h * 2 / 100; - style.normal.textColor = log.TextColor; - GUI.Label(rect, log.message, style); - } - } - private class ButtonRender : GUIRenderer - { - private PrintManager MyOWner; - - public override void Start(GizmoManager Manager) - { - MyOWner = Manager as PrintManager; - } - public override bool CanRender() - { - return MyOWner.Buttons.Count > 0; - } - public override void Draw() - { - RectOffset padding = GUI.skin.button.padding; - RectOffset margin = GUI.skin.button.margin; - - // TODO: The height calculation should be done more correctly. - Rect viewRect = new Rect(0, 0, MyOWner.ButtonSize.x, - ((MyOWner.ButtonSize.y + (padding.vertical + margin.vertical)) * MyOWner.Buttons.Count) - MyOWner.ButtonSize.y); - - - MyOWner.ScrollPosition = GUI.BeginScrollView( - position: new Rect(Screen.width - MyOWner.ButtonSize.x - MyOWner.ButtonMargin, 10, MyOWner.ButtonSize.x + MyOWner.ButtonMargin, Screen.height - 10), - scrollPosition: MyOWner.ScrollPosition, - viewRect: viewRect, - alwaysShowHorizontal: false, - alwaysShowVertical: false - ); - - for (int i = 0; i < MyOWner.Buttons.Count; i++) - { - if (GUI.Button(new Rect(0, 50 * i, MyOWner.ButtonSize.x, MyOWner.ButtonSize.y), MyOWner.Buttons[i].GetName())) - { - MyOWner.Buttons[i].ButtonPressed(); - } - } - GUI.EndScrollView(); - } - } - - - [Header("Log")] - public float PrintSpace = 20; - [Header("Button")] - [SerializeField] - private Vector2 ScrollPosition = Vector2.zero; - [SerializeField] - private Vector2 ButtonSize = new Vector2(200, 40); - [SerializeField] - private float ButtonMargin = 20; - [Header("Advance")] - [SerializeField, ReadOnly] - private List Logs = new List(); - [SerializeField, ReadOnly] - private List Buttons = new List(); - - - public override void ResolveService(Service service, bool active) - { - } - protected override GUIRenderer[] GetRenderSlots() - { - return new GUIRenderer[2] { new LogRender(), new ButtonRender() }; - } - - public void Add(LogData Log) - { - if (Log.duration > 0) - { - StartCoroutine(RemoveLog(Log)); - } - Logs.Add(Log); - } - public void Add(ButtonData Button) - { - Buttons.Add(Button); - } - public void Clear() - { - Logs.Clear(); - Buttons.Clear(); - } - - - // Enumerators - private IEnumerator RemoveLog(LogData log) - { - yield return new WaitForSeconds(log.duration); - Logs.Remove(log); - } - - } - - -} - - - - - - - diff --git a/Runtime/ReadySet/Managers/PrintManager.cs.meta b/Runtime/ReadySet/Managers/PrintManager.cs.meta deleted file mode 100644 index 2c40ebd5..00000000 --- a/Runtime/ReadySet/Managers/PrintManager.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9de82d8783153344b91caba717ca0ce4 \ No newline at end of file diff --git a/Runtime/ReadySet/Managers/SaveManager.cs b/Runtime/ReadySet/Managers/SaveManager.cs deleted file mode 100644 index 6e7d3a0b..00000000 --- a/Runtime/ReadySet/Managers/SaveManager.cs +++ /dev/null @@ -1,365 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Runtime.Serialization.Formatters.Binary; -using System.Xml.Serialization; -using UnityEngine; - -namespace RealMethod -{ - [Serializable] - public enum SaveMethod - { - PlayerPrefs, - TEXT, - XML, - JSON, - Binary, - } - - [AddComponentMenu("RealMethod/Manager/SaveManager")] - public sealed class SaveManager : DataManager - { - [Header("Behavior")] - [SerializeField] private SaveMethod Format; - public SaveMethod format => Format; - [SerializeField, HideInInspectorByEnum("Format", 0)] - private bool CustomPath = false; - [SerializeField, ConditionalHide("CustomPath", true, false)] - private string FilePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - [SerializeField, ShowInInspectorByEnum("Format", 0, 1)] - private bool PublicField = true; - [SerializeField, ShowInInspectorByEnum("Format", 0, 1)] - private bool ProtectedField = false; - [SerializeField, ShowInInspectorByEnum("Format", 0, 1)] - private bool PrivateField = false; - [SerializeField, ShowInInspectorByEnum("Format", 0, 1)] - private bool SerializeField = false; - - - // DataManager Methods - protected override void InitiateService(Service service) - { - - } - protected override bool IsExist(SaveFile file) - { - switch (Format) - { - case SaveMethod.Binary: - return File.Exists(GetPath(file)); - case SaveMethod.XML: - return File.Exists(GetPath(file)); - case SaveMethod.JSON: - return File.Exists(GetPath(file)); - case SaveMethod.TEXT: - return File.Exists(GetPath(file)); - case SaveMethod.PlayerPrefs: - return PlayerPrefs.HasKey(file.name); - default: - Debug.LogWarning($"The {Format} is not implement"); - return false; - } - } - protected override void OnSaveFile(SaveFile file) - { - switch (Format) - { - case SaveMethod.Binary: - BinaryFormatter bf = new BinaryFormatter(); -#pragma warning disable SYSLIB0011 // Suppress BinaryFormatter warning (only use in trusted context) - using (var stream = new FileStream(GetPath(file), FileMode.Create)) - { - try - { - bf.Serialize(stream, file); - } - catch (Exception e) - { - Debug.LogError($"Failed to serialize {file.name} to {GetPath(file)}: {e}"); - return; - } - } -#pragma warning restore SYSLIB0011 - break; - case SaveMethod.XML: - var xml = new XmlSerializer(file.GetType()); - using (var stream = new FileStream(GetPath(file), FileMode.Create)) - { - xml.Serialize(stream, file); - } - break; - case SaveMethod.JSON: - string jsoncontent = JsonUtility.ToJson(file, true); - File.WriteAllText(GetPath(file), jsoncontent); - break; - case SaveMethod.TEXT: - List lines = new List(); - foreach (FieldInfo field in ScanFieldsFile(file)) - { - lines.Add($"{field.Name}={field.GetValue(file)}"); - } - File.WriteAllLines(GetPath(file), lines); - break; - case SaveMethod.PlayerPrefs: - foreach (FieldInfo field in ScanFieldsFile(file)) - { - PlayerPrefsSetValueByField(field, file); - } - PlayerPrefs.SetString(file.name, DateTime.Now.ToString()); - PlayerPrefs.Save(); - break; - default: - Debug.LogWarning($"The {Format} is not implement"); - break; - } - WriteLog($"Save ({Format})", file); - } - protected override void OnLoadFile(SaveFile file) - { - switch (Format) - { - case SaveMethod.Binary: - var bf = new BinaryFormatter(); -#pragma warning disable SYSLIB0011 - using (var stream = new FileStream(GetPath(file), FileMode.Open)) - { - file = (SaveFile)bf.Deserialize(stream); - } -#pragma warning restore SYSLIB0011 - break; - case SaveMethod.XML: - var xml = new XmlSerializer(file.GetType()); - using (var stream = new FileStream(GetPath(file), FileMode.Open)) - { - file = (SaveFile)xml.Deserialize(stream); - } - break; - case SaveMethod.JSON: - string jsoncontent; - try - { - jsoncontent = File.ReadAllText(GetPath(file)); - JsonUtility.FromJsonOverwrite(jsoncontent, file); - } - catch (Exception e) - { - Debug.LogError($"Failed to read from {GetPath(file)} with exception {e}"); - return; - } - break; - case SaveMethod.TEXT: - FieldInfo[] fields = ScanFieldsFile(file); - foreach (string line in File.ReadLines(GetPath(file))) - { - string[] parts = line.Split("="); - if (parts.Length < 2) continue; - string lineName = parts[0]; - string lineValue = parts[1]; - foreach (FieldInfo info in fields) - { - if (info.Name == lineName) - { - object value = null; - Type type = info.FieldType; - try - { - if (type == typeof(int)) - value = int.Parse(lineValue); - else if (type == typeof(float)) - value = float.Parse(lineValue); - else if (type == typeof(bool)) - value = bool.Parse(lineValue); - else if (type == typeof(string)) - value = lineValue; - else if (type.IsEnum) - value = Enum.Parse(type, lineValue); - else if (type == typeof(byte)) - value = byte.Parse(lineValue); - else - Debug.LogWarning($"Unsupported type: {type.Name}"); - info.SetValue(file, value); - } - catch (Exception ex) - { - Debug.LogWarning($"Failed to set value for {info.Name}: {ex.Message}"); - } - } - } - } - break; - case SaveMethod.PlayerPrefs: - foreach (FieldInfo field in ScanFieldsFile(file)) - { - PlayerPrefsGetValueByField(field, file); - } - break; - default: - Debug.LogWarning($"The {Format} is not implement"); - break; - } - WriteLog($"Load ({Format})", file); - } - protected override void OnDeleteFile(SaveFile file) - { - switch (Format) - { - case SaveMethod.Binary: - File.Delete(GetPath(file)); - break; - case SaveMethod.XML: - File.Delete(GetPath(file)); - break; - case SaveMethod.JSON: - File.Delete(GetPath(file)); - break; - case SaveMethod.TEXT: - File.Delete(GetPath(file)); - break; - case SaveMethod.PlayerPrefs: - foreach (FieldInfo field in ScanFieldsFile(file)) - { - PlayerPrefs.DeleteKey(field.Name); - } - PlayerPrefs.DeleteKey(file.name); - break; - default: - Debug.LogWarning($"The {Format} is not implement"); - break; - } - WriteLog($"Delete ({Format})", file); - } - - // Private Functions - private string GetPath(SaveFile file) - { - string filename = file.name; - string filetype = Format == SaveMethod.TEXT ? ".txt" : - Format == SaveMethod.Binary ? ".RSave" : - Format == SaveMethod.XML ? ".xml" : - Format == SaveMethod.JSON ? ".json" : ""; - - if (CustomPath) - { - return FilePath + "/" + filename + filetype; - } - else - { - return Application.persistentDataPath + "/" + filename + filetype; - } - } - private FieldInfo[] ScanFieldsFile(SaveFile file) - { - List Result = new List(); - Type type = file.GetType(); - BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; - - FieldInfo[] fields = type.GetFields(flags); - - foreach (FieldInfo field in fields) - { - if (field.IsPublic) - { - if (PublicField) - { - Result.Add(field); - continue; - } - } - if (field.IsFamily) - { - if (ProtectedField) - { - Result.Add(field); - continue; - } - } - if (field.IsPrivate) - { - if (PrivateField) - { - Result.Add(field); - continue; - } - } - if (SerializeField) - { - if (field.GetCustomAttribute() != null) - { - Result.Add(field); - continue; - } - } - } - - return Result.ToArray(); - } - private void PlayerPrefsSetValueByField(FieldInfo field, object source) - { - string key = field.Name; - object value = field.GetValue(source); - - if (value is int intValue) - { - PlayerPrefs.SetInt(key, intValue); - } - else if (value is float floatValue) - { - PlayerPrefs.SetFloat(key, floatValue); - } - else if (value is string stringValue) - { - PlayerPrefs.SetString(key, stringValue); - } - else if (value is bool boolValue) - { - PlayerPrefs.SetInt(key, boolValue ? 1 : 0); - } - else if (value is Enum enumvalue) - { - PlayerPrefs.SetInt(key, Convert.ToInt32(enumvalue)); - } - else if (value is byte bytevalue) - { - PlayerPrefs.SetInt(key, bytevalue); - } - else - { - Debug.LogWarning($"Unsupported type for PlayerPrefs: {value?.GetType().Name} (Key: {key})"); - } - } - private void PlayerPrefsGetValueByField(FieldInfo field, object source) - { - string key = field.Name; - - if (!PlayerPrefs.HasKey(key)) return; - - if (field.FieldType == typeof(int)) - { - field.SetValue(source, PlayerPrefs.GetInt(key)); - } - else if (field.FieldType == typeof(float)) - { - field.SetValue(source, PlayerPrefs.GetFloat(key)); - } - else if (field.FieldType == typeof(string)) - { - field.SetValue(source, PlayerPrefs.GetString(key)); - } - else if (field.FieldType == typeof(bool)) - { - field.SetValue(source, PlayerPrefs.GetInt(key) == 1); - } - else if (field.FieldType == typeof(Enum)) - { - field.SetValue(source, PlayerPrefs.GetInt(key) == 1); - } - else if (field.FieldType == typeof(byte)) - { - field.SetValue(source, PlayerPrefs.GetInt(key) == 1); - } - } - - } -} \ No newline at end of file diff --git a/Runtime/ReadySet/Managers/ScreenManager.cs b/Runtime/ReadySet/Managers/ScreenManager.cs index daf58439..188c4c46 100644 --- a/Runtime/ReadySet/Managers/ScreenManager.cs +++ b/Runtime/ReadySet/Managers/ScreenManager.cs @@ -21,23 +21,11 @@ public sealed class ScreenManager : UIManager public IInformer Informer { get; private set; } // UIManager Methods - protected override void InitiateManager(bool alwaysLoaded) + protected override void InitiateManager(Scope owner) { - Game.Service.OnSceneLoading += (value) => OnLoadScne?.Invoke(value); - Game.Service.OnSceneLoadingProcess += (value) => OnLoading?.Invoke(value); - if (Game.TryFindService(out Spawn SpawnServ)) - { - SpawnServ.BringManager(this); - } + Game.Bridge.OnSceneLoading += (value) => OnLoadScne?.Invoke(value); + Game.Bridge.OnSceneLoadingProcess += (value) => OnLoading?.Invoke(value); } - protected override void InitiateService(Service newService) - { - if (newService is Spawn spawnservice) - { - spawnservice.BringManager(this); - } - } - public void SetInformer(IInformer messanger) { Informer = messanger; diff --git a/Runtime/ReadySet/Managers/SoundManager.cs b/Runtime/ReadySet/Managers/SoundManager.cs index c675968d..7e009c66 100644 --- a/Runtime/ReadySet/Managers/SoundManager.cs +++ b/Runtime/ReadySet/Managers/SoundManager.cs @@ -5,10 +5,5 @@ namespace RealMethod [AddComponentMenu("RealMethod/Manager/SoundManager")] public sealed class SoundManager : AudioManager { - // AudioManager Methods - protected override bool CanBringtoSpawn() - { - return true; - } } } \ No newline at end of file diff --git a/Runtime/ReadySet/Managers/StorageManager.cs b/Runtime/ReadySet/Managers/StorageManager.cs new file mode 100644 index 00000000..7120d6dc --- /dev/null +++ b/Runtime/ReadySet/Managers/StorageManager.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace RealMethod +{ + [AddComponentMenu("RealMethod/Manager/SaveManager")] + public sealed class StorageManager : SaveManager_Storage + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD + [SerializeField] + private bool Log = true; + protected override void WriteLog(string message) + { + if (Log) + { + base.WriteLog(message); + } + } +#endif + + // SaveManager Method + protected override bool CustomSavefile(IFile file, ISaveMethod Method, SaveState state) + { + Debug.LogWarning("Didn't Implement any CustomSaving"); + return false; + } + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Managers/SaveManager.cs.meta b/Runtime/ReadySet/Managers/StorageManager.cs.meta similarity index 100% rename from Runtime/ReadySet/Managers/SaveManager.cs.meta rename to Runtime/ReadySet/Managers/StorageManager.cs.meta diff --git a/Runtime/ReadySet/Presets/BlackboardAsset.meta b/Runtime/ReadySet/Presets/BlackboardAsset.meta deleted file mode 100644 index 81e0d219..00000000 --- a/Runtime/ReadySet/Presets/BlackboardAsset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 62f1695444e933c4a91e447b85a2378a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/ReadySet/Presets/BlackboardAsset/BlackboardAsset.cs b/Runtime/ReadySet/Presets/BlackboardAsset/BlackboardAsset.cs deleted file mode 100644 index 802017f1..00000000 --- a/Runtime/ReadySet/Presets/BlackboardAsset/BlackboardAsset.cs +++ /dev/null @@ -1,21 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - [CreateAssetMenu(fileName = "Blackboard", menuName = "RealMethod/Misc/Blackboard", order = 1)] - public sealed class BlackboardAsset : SharedDataAsset - { - [Header("Blackboard")] - [SerializeField] - private bool ResetOnPlay = false; - - -#if UNITY_EDITOR - public override void OnEditorPlay() - { - if (ResetOnPlay) - base.OnEditorPlay(); - } -#endif - } -} \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/BlackboardAsset/BlackboardAsset.cs.meta b/Runtime/ReadySet/Presets/BlackboardAsset/BlackboardAsset.cs.meta deleted file mode 100644 index a1205901..00000000 --- a/Runtime/ReadySet/Presets/BlackboardAsset/BlackboardAsset.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: f5ea7694f7fc6e041a03d91d630b159a \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/Task.meta b/Runtime/ReadySet/Presets/Class.meta similarity index 100% rename from Runtime/ReadySet/Presets/Task.meta rename to Runtime/ReadySet/Presets/Class.meta diff --git a/Runtime/ReadySet/Managers/TaskManager.cs b/Runtime/ReadySet/Presets/Class/ActionSlot.cs similarity index 55% rename from Runtime/ReadySet/Managers/TaskManager.cs rename to Runtime/ReadySet/Presets/Class/ActionSlot.cs index 5e6196fc..e4bcbfca 100644 --- a/Runtime/ReadySet/Managers/TaskManager.cs +++ b/Runtime/ReadySet/Presets/Class/ActionSlot.cs @@ -1,140 +1,51 @@ +using System; using UnityEngine; namespace RealMethod { - public delegate void TaskCallback(bool enable); - public interface ITask : ITick - { - void Enable(Object author); - void Disable(Object author); - } - - [AddComponentMenu("RealMethod/Manager/TaskManager")] - public sealed class TaskManager : TickManager + public abstract class ActionSlot : IAction, IActionTask, IHandleBehaviourAction { [Header("Task")] [SerializeField] - private TaskAsset[] DefaultTasks; - - // TickManager Methods - protected override void InitiateManager(bool alwaysLoaded) - { - if (Game.TryFindService(out Spawn SpawnServ)) - { - SpawnServ.BringManager(this); - } - - if (DefaultTasks != null) - { - for (int i = 0; i < DefaultTasks.Length; i++) - { - Add(DefaultTasks[i], this); - } - } - } - protected override void InitiateService(Service service) - { - if (service is Spawn spawnservice) - { - spawnservice.BringManager(this); - } - } - protected override bool CheckUnit(ITask unit) - { - return true; - } - - - // Public Functions - public void Add(ITask task, Object author) - { - task.Enable(author); - units.Add(task); - } - public bool Remove(ITask task, Object author) - { - if (units.Contains(task)) - { - task.Disable(author); - units.Remove(task); - return true; - } - else - { - return false; - } - } - } - - public abstract class TaskAsset : DataAsset, ITask - { - private event TaskCallback onTaskStatus; - public bool IsEnable { get; private set; } - - // Implement ITask Interface - void ITask.Enable(Object author) - { - IsEnable = true; - OnTaskEnable(author); - onTaskStatus?.Invoke(true); - } - void ITick.Tick(float delta) - { - OnTaskUpdate(delta); - } - void ITask.Disable(Object author) - { - IsEnable = false; - OnTaskDisable(author); - onTaskStatus?.Invoke(false); - } - - // Abstract Methods - protected abstract void OnTaskEnable(Object author); - protected abstract void OnTaskUpdate(float delta); - protected abstract void OnTaskDisable(Object author); - -#if UNITY_EDITOR - public override void OnEditorPlay() - { - IsEnable = false; - } -#endif - } - public abstract class TaskBehaviour : TaskAsset, IBehaviourAction - { - [Header("Task")] + private Name16 name; [SerializeField] private bool infinit = false; [SerializeField, ConditionalHide("infinit", true, true)] private float baseDuration = 5; - - // Public Variable - public System.Action OnStarted; - public System.Action OnPaused; - public System.Action OnResumed; - public System.Action OnFinished; - - // Protected Variable - protected Object Author { get; private set; } + public bool IsEnable { get; private set; } // Private Variable + private bool islive = false; private bool isValidated; private float lifetime = -1; private float residuary = -1; - private bool islive = false; private bool isRunning = true; - // TaskAsset Methods - protected sealed override void OnTaskEnable(Object author) + // Actions Delegate + public event Action OnStarted; + public event Action OnPaused; + public event Action OnResumed; + public event Action OnFinished; + + + // Implement ITask Interface + void ITask.Active() { - Author = author; + IsEnable = true; isValidated = true; - OnInitiate(); - ((IBehaviour)this).Start(); + OnEnable(); + } + void ITask.Deactive() + { + IsEnable = false; + isValidated = false; + OnDisable(); } - protected sealed override void OnTaskUpdate(float delta) + // Implement ITask Interface + IAction ITask.Controller => this; + // Implement ITick Interface + void ITick.Tick(float delta) { // Check Initiate if (!isValidated) @@ -172,18 +83,16 @@ protected sealed override void OnTaskUpdate(float delta) } } - OnUpdate(); + OnUpdate(delta); } - protected sealed override void OnTaskDisable(Object author) + // Implement IAction Interface + void IAction.Starter() { - isValidated = false; - Author = null; + throw new NotImplementedException(); } - - // Implement IBehaviour Interface public bool IsStarted => islive; - void IBehaviour.Start() + void IHandleBehaviour.Start() { lifetime = infinit ? 0 : baseDuration; if (isValidated) @@ -201,7 +110,7 @@ void IBehaviour.Start() Debug.LogError("First You Sould Initiate Behaviour"); } } - void IBehaviour.Stop() + void IHandleBehaviour.Stop() { if (isValidated) { @@ -217,11 +126,10 @@ void IBehaviour.Stop() Debug.LogError("First You Sould Initiate Command with ICommandInitiator"); } } - void IBehaviour.Clear() + void IHandleBehaviour.Clear() { Finish(); isValidated = false; - Author = null; } // Implement IBehaviourCycle Interface public bool IsInfinit => infinit; @@ -229,7 +137,7 @@ void IBehaviour.Clear() public float ElapsedTime => lifetime - residuary; public float NormalizedTime => residuary / lifetime; public bool IsFinished => !islive; - void IBehaviourCycle.Start(float overrideTime) + void IHandleBehaviourCycle.Start(float overrideTime) { lifetime = overrideTime; if (isValidated) @@ -249,36 +157,36 @@ void IBehaviourCycle.Start(float overrideTime) } // Implement IBehaviourAction Interface public bool IsPaused => !isRunning; - void IBehaviourAction.Pause() + void IHandleBehaviourAction.Pause() { isRunning = false; OnPause(); OnPaused?.Invoke(this); } - void IBehaviourAction.Resume() + void IHandleBehaviourAction.Resume() { isRunning = true; OnResume(); OnResumed?.Invoke(this); } - void IBehaviourAction.Reset() + void IHandleBehaviourAction.Reset() { ResetTaskValues(); isRunning = true; OnReset(); } - void IBehaviourAction.Restart(float Duration) + void IHandleBehaviourAction.Restart(float Duration) { ResetTaskValues(); isRunning = true; OnReset(); if (Duration > 0) { - ((IBehaviourCycle)this).Start(Duration); + ((IHandleBehaviourCycle)this).Start(Duration); } else { - ((IBehaviour)this).Start(); + ((IHandleBehaviour)this).Start(); } } @@ -287,8 +195,10 @@ void IBehaviourAction.Restart(float Duration) public void Finish() { if (islive) - ((IBehaviour)this).Stop(); + ((IHandleBehaviour)this).Stop(); } + + // Methods private void ResetTaskValues() { islive = false; @@ -300,25 +210,22 @@ protected virtual bool CanUpdate() { return isRunning; } + protected virtual void Reset() + { + IsEnable = false; + ResetTaskValues(); + } // Abstract Methods - protected abstract void OnInitiate(); + protected abstract void OnEnable(); protected abstract void OnBegin(); - protected abstract void OnUpdate(); + protected abstract void OnUpdate(float delta); protected abstract void OnPause(); protected abstract void OnResume(); protected abstract void OnReset(); protected abstract void OnEnd(); - -#if UNITY_EDITOR - public sealed override void OnEditorPlay() - { - base.OnEditorPlay(); - ResetTaskValues(); - } -#endif - + protected abstract void OnDisable(); } diff --git a/Runtime/ReadySet/Presets/Class/ActionSlot.cs.meta b/Runtime/ReadySet/Presets/Class/ActionSlot.cs.meta new file mode 100644 index 00000000..ddbcaacd --- /dev/null +++ b/Runtime/ReadySet/Presets/Class/ActionSlot.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0f1be7d745ee1e9409a6fc9c89f463a9 \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/Class/RetriggerDelay.cs b/Runtime/ReadySet/Presets/Class/RetriggerDelay.cs new file mode 100644 index 00000000..5a8ffa5f --- /dev/null +++ b/Runtime/ReadySet/Presets/Class/RetriggerDelay.cs @@ -0,0 +1,56 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +public class RetriggerDelay +{ + private static int _nextId; + public int Id { get; } + + private CancellationTokenSource _cts; + private readonly float _delay; + private bool _isRunning; + + public event Action OnCompleted; + + public RetriggerDelay(float delay) + { + Id = ++_nextId; + _delay = delay; + } + + public async void Trigger() + { + // Cancel any previous delay + _cts?.Cancel(); + + _cts = new CancellationTokenSource(); + var token = _cts.Token; + + _isRunning = true; + + try + { + // Convert seconds → milliseconds + await Task.Delay((int)(_delay * 1000f), token); + + if (!token.IsCancellationRequested) + { + _isRunning = false; + OnCompleted?.Invoke(this); // notifies external system to destroy/remove + } + } + catch (TaskCanceledException) + { + // Expected when retriggered + } + } + + public void Cancel() + { + _cts?.Cancel(); + _isRunning = false; + } + + public bool IsRunning => _isRunning; +} diff --git a/Runtime/ReadySet/Presets/Task/RetriggerableDelayTask.cs.meta b/Runtime/ReadySet/Presets/Class/RetriggerDelay.cs.meta similarity index 100% rename from Runtime/ReadySet/Presets/Task/RetriggerableDelayTask.cs.meta rename to Runtime/ReadySet/Presets/Class/RetriggerDelay.cs.meta diff --git a/Runtime/ReadySet/Presets/DrawAsset.cs b/Runtime/ReadySet/Presets/DrawAsset.cs new file mode 100644 index 00000000..6fec7e55 --- /dev/null +++ b/Runtime/ReadySet/Presets/DrawAsset.cs @@ -0,0 +1,25 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + [CreateAssetMenu(fileName = "Draw", menuName = "RealMethod/Develop/DrawAsset", order = 1)] + public sealed class DrawAsset : GUIAsset + { + public event Action OnButtonClicked; + public event Action OnToggleChanged; + + + // GUIAsset Methods + public override void OnButtonClick(string ButtonName) + { + OnButtonClicked?.Invoke(ButtonName); + } + public override void OnToggleChange(string ToggleName, bool Val) + { + OnToggleChanged?.Invoke(ToggleName, Val); + } + + + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/DrawAsset.cs.meta b/Runtime/ReadySet/Presets/DrawAsset.cs.meta new file mode 100644 index 00000000..8d893470 --- /dev/null +++ b/Runtime/ReadySet/Presets/DrawAsset.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cfe184d5f05c3b4489c49c11fd28f8ac \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/EventAssets.meta b/Runtime/ReadySet/Presets/EventAssets.meta new file mode 100644 index 00000000..d9aaf74b --- /dev/null +++ b/Runtime/ReadySet/Presets/EventAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ff804b2662bedbc4a84d89dfe1020b8c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ReadySet/Presets/EventAssets/EventAsset.cs b/Runtime/ReadySet/Presets/EventAssets/EventAsset.cs new file mode 100644 index 00000000..a27b2d6c --- /dev/null +++ b/Runtime/ReadySet/Presets/EventAssets/EventAsset.cs @@ -0,0 +1,52 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + [CreateAssetMenu(fileName = "EventAsset", menuName = "RealMethod/Delegate/Event", order = 1)] + public class EventAsset : DelegateAsset + { + private event Action _event; + + public override void Invoke() + { + _event?.Invoke(); + } + public override void AddListener(T listener) + { + if (listener is Action provider) + { + _event += provider; + } + else + { + Debug.LogWarning($"The listener should be {typeof(Action)} for binding, AddListener Faild!"); + } + } + public override void RemoveListener(T listener) + { + if (listener is Action provider) + { + _event -= provider; + } + else + { + Debug.LogWarning($"The listener should be {typeof(Action)} for binding, AddListener Faild!"); + } + } + + + + // -------- Operator Overloads -------- + public static EventAsset operator +(EventAsset asset, Action listener) + { + asset._event += listener; + return asset; + } + public static EventAsset operator -(EventAsset asset, Action listener) + { + asset._event -= listener; + return asset; + } + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/EventAssets/EventAsset.cs.meta b/Runtime/ReadySet/Presets/EventAssets/EventAsset.cs.meta new file mode 100644 index 00000000..58f35f35 --- /dev/null +++ b/Runtime/ReadySet/Presets/EventAssets/EventAsset.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: afe46b0903a8c654d91c6b06a2bf66ba \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/EventAssets/EventAsset_Bool.cs b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Bool.cs new file mode 100644 index 00000000..8f04014b --- /dev/null +++ b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Bool.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace RealMethod +{ + [CreateAssetMenu(fileName = "EventAsset_Bool", menuName = "RealMethod/Delegate/EventAsset_Bool", order = 1)] + public sealed class EventAsset_Bool : EventAsset + { + + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/EventAssets/EventAsset_Bool.cs.meta b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Bool.cs.meta new file mode 100644 index 00000000..ee639988 --- /dev/null +++ b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Bool.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cc70a3838fde1884a96551fb79c459cd \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/EventAssets/EventAsset_Float.cs b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Float.cs new file mode 100644 index 00000000..c6f71e3d --- /dev/null +++ b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Float.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace RealMethod +{ + [CreateAssetMenu(fileName = "Event_Float", menuName = "RealMethod/Delegate/Event_Float", order = 1)] + public sealed class EventAsset_Float : EventAsset + { + + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/EventAssets/EventAsset_Float.cs.meta b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Float.cs.meta new file mode 100644 index 00000000..3a4c6d72 --- /dev/null +++ b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Float.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f4073eb9c78ffe7409ae092c2d31536f \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/EventAssets/EventAsset_Int.cs b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Int.cs new file mode 100644 index 00000000..52da6a84 --- /dev/null +++ b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Int.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace RealMethod +{ + [CreateAssetMenu(fileName = "Event_Int", menuName = "RealMethod/Delegate/Event_Int", order = 1)] + public sealed class EventAsset_Int : EventAsset + { + + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/EventAssets/EventAsset_Int.cs.meta b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Int.cs.meta new file mode 100644 index 00000000..fc1df30c --- /dev/null +++ b/Runtime/ReadySet/Presets/EventAssets/EventAsset_Int.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d02c747e423451242bc2b0292b38e1f2 \ No newline at end of file diff --git a/Runtime/ReadySet/Presets/PoolAsset/AudioPool.cs b/Runtime/ReadySet/Presets/PoolAsset/AudioPool.cs index 9e056712..62cbcc3e 100644 --- a/Runtime/ReadySet/Presets/PoolAsset/AudioPool.cs +++ b/Runtime/ReadySet/Presets/PoolAsset/AudioPool.cs @@ -6,7 +6,7 @@ namespace RealMethod { [CreateAssetMenu(fileName = "AudioPool", menuName = "RealMethod/Pool/AudioPool", order = 1)] - public sealed class AudioPool : PoolAsset , IPoolSpawner + public sealed class AudioPool : PoolAsset, IPoolSpawner { [Header("Setting")] [SerializeField] @@ -21,7 +21,7 @@ public sealed class AudioPool : PoolAsset , IPoolSpawner OnSpawn; + public event Action OnSpawned; // Private Variable @@ -87,7 +87,7 @@ public AudioSource Spawn(int index) public AudioSource Spawn() { AudioSource result = Request(); - OnSpawn?.Invoke(result); + OnSpawned?.Invoke(result); return result; } @@ -109,8 +109,7 @@ private AudioClip GetRandomClip() // Base PoolAsset Methods protected override void OnRootInitiate(Transform Root) { - AudioManager audiomanager = Game.World.GetManager(); - if (audiomanager != null) + if (Game.World.TryFindGameManager(out AudioManager audiomanager)) { Root.SetParent(audiomanager.transform); } @@ -192,14 +191,11 @@ protected override IEnumerator PostProcess(AudioSource Comp) return PoolBack(Comp); } -#if UNITY_EDITOR - // Base DataAsset Methods - public override void OnEditorPlay() + protected override void Reset() { - base.OnEditorPlay(); + base.Reset(); UseCacheData = 0; } -#endif // IEnumerator private IEnumerator PoolBack(AudioSource source) diff --git a/Runtime/ReadySet/Presets/PoolAsset/ParticlePool.cs b/Runtime/ReadySet/Presets/PoolAsset/ParticlePool.cs index b53afaed..d2adf7b4 100644 --- a/Runtime/ReadySet/Presets/PoolAsset/ParticlePool.cs +++ b/Runtime/ReadySet/Presets/PoolAsset/ParticlePool.cs @@ -6,7 +6,7 @@ namespace RealMethod { [CreateAssetMenu(fileName = "ParticlePool", menuName = "RealMethod/Pool/ParticlePool", order = 1)] - public sealed class ParticlePool : PoolAsset , IPoolSpawner + public sealed class ParticlePool : PoolAsset, IPoolSpawner { [Header("Setting")] [SerializeField] @@ -14,7 +14,8 @@ public sealed class ParticlePool : PoolAsset , IPoolSpawner OnSpawn; + public event Action OnSpawned; + // Private Variable private byte UseCacheData = 0; //0:NoCashing 1:CachePosition 2:CachePosition&Rotation 3:CacheTransform @@ -48,7 +49,7 @@ public ParticleSystem Spawn(Vector3 location) public ParticleSystem Spawn() { ParticleSystem result = Request(); - OnSpawn?.Invoke(result); + OnSpawned?.Invoke(result); return result; } @@ -93,14 +94,12 @@ protected override IEnumerator PostProcess(ParticleSystem Comp) return PoolBack(Comp); } -#if UNITY_EDITOR - // Base DataAsset Methods - public override void OnEditorPlay() + + protected override void Reset() { - base.OnEditorPlay(); + base.Reset(); UseCacheData = 0; } -#endif // IEnumerator diff --git a/Runtime/ReadySet/Presets/PoolAsset/PrefabPool.cs b/Runtime/ReadySet/Presets/PoolAsset/PrefabPool.cs index 5b92d3f2..bde10e60 100644 --- a/Runtime/ReadySet/Presets/PoolAsset/PrefabPool.cs +++ b/Runtime/ReadySet/Presets/PoolAsset/PrefabPool.cs @@ -16,7 +16,7 @@ public sealed class PrefabPool : PoolAsset, IPoolSpawner, private float duration = 2; //Actions - public Action OnSpawn; + public event Action OnSpawned; // Private Variable @@ -74,14 +74,14 @@ public Transform Spawn(float overrideDuration) { CacheDuration = overrideDuration; Transform result = Request(); - OnSpawn?.Invoke(result); + OnSpawned?.Invoke(result); return result; } public Transform Spawn() { CacheDuration = duration; Transform result = Request(); - OnSpawn?.Invoke(result); + OnSpawned?.Invoke(result); return result; } public void Despawn() @@ -149,15 +149,14 @@ protected override IEnumerator PostProcess(Transform Comp) return autoDespawn ? PoolBack(Comp) : null; } -#if UNITY_EDITOR - // Base DataAsset Methods - public override void OnEditorPlay() + + protected override void Reset() { - base.OnEditorPlay(); + base.Reset(); UseCacheData = 0; CacheDuration = 0; } -#endif + // IEnumerator private IEnumerator PoolBack(Transform Transf) { diff --git a/Runtime/ReadySet/Presets/Task/RetriggerableDelayTask.cs b/Runtime/ReadySet/Presets/Task/RetriggerableDelayTask.cs deleted file mode 100644 index 404d1f9d..00000000 --- a/Runtime/ReadySet/Presets/Task/RetriggerableDelayTask.cs +++ /dev/null @@ -1,62 +0,0 @@ - - -using RealMethod; -using UnityEngine; - -namespace RealMethod -{ - public class RetriggerableDelay : ITask - { - private float _delay; - private System.Action _onElapsed; - private float _endTime; - private bool _running; - private Object MyAuthor; - - public RetriggerableDelay(float delay, System.Action onElapsed) - { - _delay = delay; - _onElapsed = onElapsed; - } - - // Implement ITask Interface - void ITask.Enable(Object author) - { - MyAuthor = author; - _endTime = Time.time + _delay; - _running = true; - } - void ITask.Disable(Object author) - { - MyAuthor = null; - } - // Implement ITick Interface - void ITick.Tick(float deltaTime) - { - if (_running && Time.time >= _endTime) - { - _running = false; - _onElapsed?.Invoke(); - if (MyAuthor != null) - Despawn.Task(this, MyAuthor); - } - } - - - ///

- /// Restart the delay countdown. - /// - public void Trigger() - { - _endTime = Time.time + _delay; - _running = true; - } - /// Cancel without firing. - public void Cancel() => _running = false; - - - - } - - -} \ No newline at end of file diff --git a/Runtime/ReadySet/Services/DebugModule.cs b/Runtime/ReadySet/Services/DebugModule.cs new file mode 100644 index 00000000..272551e3 --- /dev/null +++ b/Runtime/ReadySet/Services/DebugModule.cs @@ -0,0 +1,212 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace RealMethod +{ + public sealed class DebugModule : GameModule, ILogHandler, IDebugService + { + private class LogLine : IDrawTask + { + private DebugModule MyOwner; + private string MyMessage; + private LogType MyType; + private Vector2 MyOffcet; + private float ActiveTime; + + + public Vector2 Pivot => MyOwner.Pivot; + public float Space => ((IDebugService)MyOwner).PrintSpace; + private int Size => MyOwner.Size; + public bool IsFinished => !(Time.time - ActiveTime <= Duration); + public float Duration + { + get + { + switch (MyType) + { + case LogType.Log: + return 5; + case LogType.Warning: + return 10; + case LogType.Error: + return 15; + case LogType.Assert: + return 20; + case LogType.Exception: + return 25; + default: + return 0; + } + } + } + public Color Color + { + get + { + switch (MyType) + { + case LogType.Log: + return Color.cyan; + case LogType.Warning: + return Color.yellow; + case LogType.Error: + return Color.red; + case LogType.Assert: + return Color.white; + case LogType.Exception: + return Color.blue; + default: + return Color.black; + } + } + } + + + + public LogLine(DebugModule owner, string message, LogType type) + { + MyOwner = owner; + MyMessage = message; + MyType = type; + MyOffcet = Vector2.zero; + ActiveTime = 0; + } + public LogLine(DebugModule owner, string message, LogType type, Vector2 offcet) + { + MyOwner = owner; + MyMessage = message; + MyType = type; + MyOffcet = offcet; + ActiveTime = 0; + } + + // Implemetn ITask Interface + void ITask.Active() + { + ActiveTime = Time.time; + } + void ITask.Deactive() + { + MyOwner.RemoveLog(this); + } + // Implement IDraw Interface + bool IDraw.CanDraw(int Index) + { + return !IsFinished; + } + void IDraw.Draw(int Index) + { + int w = Screen.width * Size; + int h = Screen.height * Size; + float Xpos = Pivot.x + MyOffcet.x; + float Ypos = Pivot.y + MyOffcet.y + (Index * Space); + + GUIStyle style = new GUIStyle(); + Rect rect = new Rect(Xpos, Ypos, w, h * 2 / 100); + style.alignment = TextAnchor.UpperLeft; + style.fontSize = h * 2 / 100; + style.normal.textColor = Color; + GUI.Label(rect, MyMessage, style); + } + // Implement IDrawTask Interface + int IDrawTask.Priority => 0; + bool IDrawTask.IsExpired() + { + return IsFinished; + } + DrawMode IDrawTask.GetDrawMode() + { + return DrawMode.GUI; + } + + } + private Vector2 Pivot = new Vector2(10, 10); + private int Size = 1; + private List Lines = new List(10); + private ILogHandler defaultLogHandler; + + + // Implement ILogHandler Interfacwe + void ILogHandler.LogFormat(LogType logType, Object context, string format, params object[] args) + { + string message = string.Format(format, args); + + // Send message to screen system + LogLine NewLine = new LogLine(this, message, logType); + Lines.Add(NewLine); + Game.Draw(NewLine); + + // Still send message to Unity console + if (defaultLogHandler != null) + { + defaultLogHandler.LogFormat(logType, context, format, args); + } + else + { + Debug.unityLogger.logHandler.LogFormat(logType, context, format, args); + } + OnLogWrited?.Invoke(logType, format); + } + void ILogHandler.LogException(System.Exception exception, Object context) + { + // Send message to screen system + LogLine NewLine = new LogLine(this, exception.Message, LogType.Exception); + Lines.Add(NewLine); + Game.Draw(NewLine); + + defaultLogHandler.LogException(exception, context); + OnLogWrited?.Invoke(LogType.Exception, exception.Message); + } + // Implement IGUIService Interface + Vector2 IGUIService.PrintPivot => Pivot; + int IGUIService.PrintSize => Size; + void IGUIService.SetPivot(Vector2 pivot) + { + Pivot = pivot; + } + void IGUIService.SetSize(int size) + { + Size = size; + } + // Implement IDebugService Interface + float IDebugService.PrintSpace => Screen.height / 40; + public event System.Action OnLogWrited; + + + + // Module Methods + protected override void OnBegin() + { + defaultLogHandler = Debug.unityLogger.logHandler; + Debug.unityLogger.logHandler = this; + } + protected override void OnWorldChanged() + { + // Nothing + } + protected override void OnEnd() + { + Debug.unityLogger.logHandler = defaultLogHandler; + Lines.Clear(); + } + + + + + // Methods + private void RemoveLog(LogLine line) + { + Lines.Remove(line); + } + + + +#if UNITY_EDITOR + protected override string GetInspectorInfo() + { + return $"Lines ({Lines.Count})"; + } +#endif + + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Services/DebugModule.cs.meta b/Runtime/ReadySet/Services/DebugModule.cs.meta new file mode 100644 index 00000000..770cd703 --- /dev/null +++ b/Runtime/ReadySet/Services/DebugModule.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 41df5dfaa2fc5e046b734051776e6912 \ No newline at end of file diff --git a/Runtime/ReadySet/Services/Despawn.cs b/Runtime/ReadySet/Services/Despawn.cs new file mode 100644 index 00000000..189286ee --- /dev/null +++ b/Runtime/ReadySet/Services/Despawn.cs @@ -0,0 +1,297 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace RealMethod +{ + /// + /// Despawn is a sealed static class used to instantiate gameplay objects such as + /// prefabs, UI elements, audio sources, and other spawnable types. + /// + /// This class automatically locates the required manager instances from the + /// World scope. When a new spawn request is made, Despawn will: + /// 1) Look for a cached manager of the requested type. + /// 2) If missing, it will attempt to find the manager inside World. + /// 3) The found manager is cached internally for reuse to avoid repeated lookups. + /// + /// Developers may register their own managers manually if needed. + /// This is useful when: + /// • A custom manager needs to be used before Despawn's automatic discovery. + /// • Multiple child managers inherit from an abstract base manager. + /// (Example: UIManager → ScreenManager / HUDManager) + /// Despawn will always pick the FIRST accessible base type (UIManager), + /// unless the developer registers a specific child manager earlier. + /// + /// Important notes: + /// • Despawn is a sealed class and cannot be inherited or modified. + /// • Spawn’s methods work only with the corresponding manager types + /// (UIManager, AudioManager, ScreenManager, TaskManager, HapticManager, EnumeratorManager & ..). + /// • When scenes change, World scope clears all managers. Despawn will also + /// lose cached references and re-discover managers on the next request. + /// Developers must ensure their managers are available in World before + /// calling Despawn. + /// + /// To manually register a manager early: + /// Game.World.SpawnService.AddManager(customManager); + /// This guarantees Despawn will use the developer‑provided manager instead of + /// auto-discovering one. + /// + /// Overall, Despawn provides a fast, centralized, and manager‑aware spawning + /// system that intelligently reuses previously found managers and adapts to + /// scene changes. + /// + public sealed class Despawn : Context, IBridge, IInspectorInfo + { + private Dictionary GameManagers; + private Dictionary WorldManagers; + + // Implement IBridge Interface + void IBridge.OnWorldChanged(World world) + { + WorldManagers.Clear(); + Debug.Log("ChangeWorld Spawn"); + } + + protected override void OnBegin() + { + // Check if you game not initialized + if (!Game.IsGameInitialized) + { + Debug.LogWarning($"Game doesn't initialized !"); + return; + } + Game.Bridge.Bind(this); + GameManagers = new(); + WorldManagers = new(); + Debug.Log("Begin Spawn"); + } + protected override void OnEnd() + { + Game.Bridge.Unbind(this); + GameManagers = null; + WorldManagers = null; + Debug.Log("End Spawn"); + } + + private static T Get(ScopeTarget context = ScopeTarget.Both) where T : Component, IGameManager + { + System.Type type = typeof(T); + + switch (context) + { + case ScopeTarget.World: + if (Instance.WorldManagers.ContainsKey(type)) + { + return (T)Instance.WorldManagers[type].Component; + } + else + { + if (Game.World.TryFindGameManager(out T manager)) + { + Instance.WorldManagers.Add(type, manager); + return manager; + } + } + break; + case ScopeTarget.Game: + if (Instance.GameManagers.ContainsKey(type)) + { + return (T)Instance.GameManagers[type].Component; + } + else + { + if (Game.Instance.TryFindGameManager(out T manager)) + { + Instance.GameManagers.Add(type, manager); + return manager; + } + } + break; + case ScopeTarget.Both: + if (Instance.WorldManagers.ContainsKey(type)) + { + return (T)Instance.WorldManagers[type].Component; + } + else if (Instance.GameManagers.ContainsKey(type)) + { + return (T)Instance.GameManagers[type].Component; + } + else if (Game.World.TryFindGameManager(out T manager1)) + { + Instance.WorldManagers.Add(type, manager1); + return manager1; + } + else if (Game.Instance.TryFindGameManager(out T manager2)) + { + Instance.GameManagers.Add(type, manager2); + return manager2; + } + break; + } + + Debug.LogError($"{Instance}:Failed to spawn, Manager({typeof(T).Name}) is not available. [{context} Context]"); + return null; + } + + +#if UNITY_EDITOR + string IInspectorInfo.GetInfo() + { + return $"GameManagers ({GameManagers.Count}) , WorldManagers ({WorldManagers.Count})"; + } +#endif + + + // UI + public static bool Widget(string Name, Object despawner = null, bool debug = true, ScopeTarget Scope = ScopeTarget.Both) + { + if (Get(Scope) == null) + { + if (debug) + Debug.LogWarning("Despawn UIManager is not available."); + return false; + } + + return Get(Scope).RemoveLayer(Name, despawner); + } + public static bool Widget(MonoBehaviour Comp, Object despawner = null, bool debug = true, ScopeTarget Scope = ScopeTarget.Both) + { + if (Get(Scope) == null) + { + if (debug) + Debug.LogWarning("Despawn UIManager is not available."); + return false; + } + + return Get(Scope).RemoveLayer(Comp, despawner); + } + + // Prefab + public static bool GameObject(GameObject target, Object despawner = null, bool debug = true) + { + if (target != null) + { + if (despawner != null) + { + target.InvokeDespawnEvent(despawner); + } + Object.Destroy(target); + return true; + } + else + { + if (debug) + Debug.LogWarning("Despawn target is not available."); + return false; + } + } + + // Pool + public static bool Pool(PoolAsset asset, bool debug = true) where T : Component + { + if (asset is IPoolDespawner pooler) + { + pooler.Despawn(); + return true; + } + else + { + if (debug) + Debug.LogWarning("PoolAsset does not implement IPoolDespawner."); + return false; + } + } + public static bool Pool(PoolAsset asset, T target, bool debug = true) where T : Component + { + if (asset is IPoolDespawner pooler) + { + pooler.Despawn(target); + return true; + } + else + { + if (debug) + Debug.LogWarning("PoolAsset does not implement IPoolDespawner."); + return false; + } + } + + // Realmethod + public static bool Asset(T target, Object despawner = null, bool debug = true) where T : PrimitiveAsset + { + if (target != null) + { + Object.Destroy(target); + target.InvokeDespawnEvent(despawner); + return true; + } + else + { + if (debug) + Debug.LogWarning($"Asset is not Valid!"); + return false; + } + } + public static bool Service(ScopeTarget Scope = ScopeTarget.Game) where T : GameService, new() + { + if (GetScope(Scope).TryFindModule(out T result)) + { + result.InvokeUnreqisterEvent(); + return GetScope(Scope).RemoveModule(); + } + + return false; + } + + + // Task + public static bool Task(T task) where T : IHandle + { + TaskManager manager = Get>(); + if (manager == null) + return false; + return manager.Destroy(task); + } + + // Enumerator + public static bool Coroutine(Coroutine coroutine, bool debug = true) + { + if (Get() == null) + { + if (debug) + Debug.LogWarning("TaskManager is not available."); + return false; + } + + Get().Stop(coroutine); + return true; + } + + // Haptic + public static bool Haptic(IHapticProvider provider, bool debug = true) + { + if (Get() == null) + { + if (debug) + Debug.LogWarning("HapticManager is not available."); + return false; + } + return Get().Demolish(provider); + } + + + + private static Scope GetScope(ScopeTarget Scope) + { + switch (Scope) + { + case ScopeTarget.Game: + return Game.Instance; + case ScopeTarget.World: + return Game.World; + default: + Debug.LogWarning("Your ScopeTarget should be World or Game"); + return null; + } + } + } +} \ No newline at end of file diff --git a/Runtime/ReadySet/Services/Despawn.cs.meta b/Runtime/ReadySet/Services/Despawn.cs.meta new file mode 100644 index 00000000..23e6071d --- /dev/null +++ b/Runtime/ReadySet/Services/Despawn.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4d4786c83f476584184bb4cc13d2e042 \ No newline at end of file diff --git a/Runtime/ReadySet/Services/NetworkService.cs b/Runtime/ReadySet/Services/NetworkService.cs index 82633024..5b9c081f 100644 --- a/Runtime/ReadySet/Services/NetworkService.cs +++ b/Runtime/ReadySet/Services/NetworkService.cs @@ -5,7 +5,7 @@ namespace RealMethod { - public sealed class NetworkService : Service + public sealed class NetworkService : GameModule { //Const Variable private const string webImage = "http://upload.wikimedia.org/wikipedia/commons/c/c5/Moraine_Lake_17092005.jpg"; @@ -15,16 +15,15 @@ public sealed class NetworkService : Service private const string xmlApi = "http://api.openweathermap.org/data/2.5/weather?q=Chicago,us&mode=xml&APPID="; - - protected override void OnStart(object Author) + protected override void OnBegin() { throw new NotImplementedException(); } - protected override void OnNewWorld() + protected override void OnWorldChanged() { throw new NotImplementedException(); } - protected override void OnEnd(object Author) + protected override void OnEnd() { throw new NotImplementedException(); } @@ -81,7 +80,6 @@ public IEnumerator DownloadImage(Action callback) callback(DownloadHandlerTexture.GetContent(request)); } - } diff --git a/Runtime/ReadySet/Services/PrintService.cs b/Runtime/ReadySet/Services/PrintService.cs deleted file mode 100644 index 4ad7ad48..00000000 --- a/Runtime/ReadySet/Services/PrintService.cs +++ /dev/null @@ -1,77 +0,0 @@ -using UnityEngine; - -namespace RealMethod -{ - public sealed class Print : Service - { - private static Print CacheInstance = null; - public static Print Instance - { - get - { - if (CacheInstance != null) - { - return CacheInstance; - } - else - { - if (Game.TryFindService(out Print CacheInstance)) - { - return CacheInstance; - } - CacheInstance = Game.AddService(null); - return CacheInstance; - } - } - } - public static PrintManager Manager => Instance.Printer; - - private PrintManager Printer; - - protected override void OnStart(object Author) - { - Printer = Game.Instance.GetManager(); - if (Printer == null) - { - Printer = Game.Instance.gameObject.AddComponent(); - IGameManager manager = Printer; - manager.InitiateManager(true); - } - } - protected override void OnNewWorld() - { - Printer.Clear(); - } - protected override void OnEnd(object Author) - { - Object.Destroy(Printer); - CacheInstance = null; - } - - public static void Log(string message, Color color, float duration = 2) - { - Manager.Add(new LogData(message, duration, color)); - } - public static void Log(string message, float duration = 2) - { - Manager.Add(new LogData(message, duration)); - } - public static void LogWarning(string message, float duration = 2) - { - Manager.Add(new LogData(message, duration, LogType.Warning)); - } - public static void LogError(string message, float duration = 2) - { - Manager.Add(new LogData(message, duration, LogType.Error)); - } - public static void LogAssertion(string message, float duration = 2) - { - Manager.Add(new LogData(message, duration, LogType.Assert)); - } - public static void Button(string name, object author, string funtionName) - { - Manager.Add(new ButtonData(name, author, funtionName)); - } - } - -} \ No newline at end of file diff --git a/Runtime/ReadySet/Services/PrintService.cs.meta b/Runtime/ReadySet/Services/PrintService.cs.meta deleted file mode 100644 index 0e9d432e..00000000 --- a/Runtime/ReadySet/Services/PrintService.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: e0b5c215c57b74e4fa9b546a9d6009e4 \ No newline at end of file diff --git a/Runtime/ReadySet/Services/Spawan.cs b/Runtime/ReadySet/Services/Spawan.cs new file mode 100644 index 00000000..6a956cf7 --- /dev/null +++ b/Runtime/ReadySet/Services/Spawan.cs @@ -0,0 +1,737 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.Audio; +using UnityEngine.UIElements; +using System.Collections.Generic; + +namespace RealMethod +{ + /// + /// Spawn is a sealed static class used to instantiate gameplay objects such as + /// prefabs, UI elements, audio sources, and other spawnable types. + /// + /// This class automatically locates the required manager instances from the + /// World scope. When a new spawn request is made, Spawn will: + /// 1) Look for a cached manager of the requested type. + /// 2) If missing, it will attempt to find the manager inside World. + /// 3) The found manager is cached internally for reuse to avoid repeated lookups. + /// + /// Developers may register their own managers manually if needed. + /// This is useful when: + /// • A custom manager needs to be used before Spawn's automatic discovery. + /// • Multiple child managers inherit from an abstract base manager. + /// (Example: UIManager → ScreenManager / HUDManager) + /// Spawn will always pick the FIRST accessible base type (UIManager), + /// unless the developer registers a specific child manager earlier. + /// + /// Important notes: + /// • Spawn is a sealed class and cannot be inherited or modified. + /// • Spawn’s methods work only with the corresponding manager types + /// (UIManager, AudioManager, ScreenManager, TaskManager, HapticManager, EnumeratorManager & ..). + /// • When scenes change, World scope clears all managers. Spawn will also + /// lose cached references and re-discover managers on the next request. + /// Developers must ensure their managers are available in World before + /// calling Spawn. + /// + /// To manually register a manager early: + /// Game.World.SpawnService.AddManager(customManager); + /// This guarantees Spawn will use the developer‑provided manager instead of + /// auto-discovering one. + /// + /// Overall, Spawn provides a fast, centralized, and manager‑aware spawning + /// system that intelligently reuses previously found managers and adapts to + /// scene changes. + /// + public sealed class Spawn : Context, IBridge, IInspectorInfo + { + private Dictionary GameManagers; + private Dictionary WorldManagers; + + // Implement IBridge Interface + void IBridge.OnWorldChanged(World world) + { + WorldManagers.Clear(); + Debug.Log("ChangeWorld Spawn"); + } + + protected override void OnBegin() + { + // Check if you game not initialized + if (!Game.IsGameInitialized) + { + Debug.LogWarning($"Game doesn't initialized !"); + return; + } + Game.Bridge.Bind(this); + GameManagers = new(); + WorldManagers = new(); + Debug.Log("Begin Spawn"); + } + protected override void OnEnd() + { + Game.Bridge.Unbind(this); + GameManagers = null; + WorldManagers = null; + Debug.Log("End Spawn"); + } + + private static T Get(ScopeTarget context = ScopeTarget.Both) where T : Component, IGameManager + { + System.Type type = typeof(T); + + switch (context) + { + case ScopeTarget.World: + if (Instance.WorldManagers.ContainsKey(type)) + { + return (T)Instance.WorldManagers[type].Component; + } + else + { + if (Game.World.TryFindGameManager(out T manager)) + { + Instance.WorldManagers.Add(type, manager); + return manager; + } + } + break; + case ScopeTarget.Game: + if (Instance.GameManagers.ContainsKey(type)) + { + return (T)Instance.GameManagers[type].Component; + } + else + { + if (Game.Instance.TryFindGameManager(out T manager)) + { + Instance.GameManagers.Add(type, manager); + return manager; + } + } + break; + case ScopeTarget.Both: + if (Instance.WorldManagers.ContainsKey(type)) + { + return (T)Instance.WorldManagers[type].Component; + } + else if (Instance.GameManagers.ContainsKey(type)) + { + return (T)Instance.GameManagers[type].Component; + } + else if (Game.World.TryFindGameManager(out T manager1)) + { + Instance.WorldManagers.Add(type, manager1); + return manager1; + } + else if (Game.Instance.TryFindGameManager(out T manager2)) + { + Instance.GameManagers.Add(type, manager2); + return manager2; + } + break; + } + + Debug.LogError($"{Instance}:Failed to spawn, Manager({typeof(T).Name}) is not available. [{context} Context]"); + return null; + } + + +#if UNITY_EDITOR + string IInspectorInfo.GetInfo() + { + return $"GameManagers ({GameManagers.Count}) , WorldManagers ({WorldManagers.Count})"; + } +#endif + + // UI + public static T Widget(string Name, Object spawner = null, ScopeTarget Scope = ScopeTarget.Both) where T : MonoBehaviour + { + return Get(Scope).CreateLayer(Name, spawner); + } + public static T Widget(VisualTreeAsset UIAsset, string Name, Object spawner = null, ScopeTarget Scope = ScopeTarget.Both) where T : MonoBehaviour + { + return Get(Scope).CreateLayer(Name, UIAsset, spawner); + } + public static GameObject Widget(UPrefab Prefab, string Name, Object spawner = null, ScopeTarget Scope = ScopeTarget.Both) + { + return Get(Scope).AddLayer(Name, Prefab, spawner); + } + public static T Widget(UPrefab Prefab, string Name, Object spawner = null, ScopeTarget Scope = ScopeTarget.Both) where T : MonoBehaviour + { + return Get(Scope).AddLayer(Name, Prefab, spawner); + } + public static UIDocument UIDoc(string Name, VisualTreeAsset UIAsset, ScopeTarget Scope = ScopeTarget.Both) + { + return Get(Scope).CreateLayer(Name, UIAsset); + } + + // Screen + public static void Message(string message) + { + if (Get().Informer != null) + { + Get().Informer.Popup(message); + } + else + { + Debug.LogWarning($"ScreenMaanger need to set Informer"); + } + } + public static void Message(string message, float duration) + { + if (Get().Informer != null) + { + Get().Informer.Popup(message, duration); + } + else + { + Debug.LogWarning($"ScreenMaanger need to set Informer"); + } + } + + // Sound + public static AudioSource Sound3D(AudioClip clip, Vector3 location, Transform parent = null, AudioMixerGroup group = null, float rolloffDistanceMin = 1f, bool loop = false, float pauseTime = 0, bool autoDestroy = true) + { + if (Get() != null) + { + return Get().PlaySound(clip, location, parent, group, rolloffDistanceMin, loop, pauseTime, autoDestroy); + } + else + { + GameObject AudioObject = new GameObject(); + AudioObject.name = "Audio_" + clip.name; + AudioSource source = AudioObject.AddComponent(); + source.clip = clip; + source.outputAudioMixerGroup = group; + source.spatialBlend = 0; + source.minDistance = rolloffDistanceMin; + source.transform.SetParent(parent != null ? parent : Game.World.transform); + AudioObject.transform.localPosition = location; + source.Play(); + if (autoDestroy) + { + AudioObject.AddComponent(clip.length); + } + else + { + Debug.LogWarning("for loop or puaseTime , you need to use AudioManager"); + } + return source; + } + } + public static AudioSource Sound3D(AudioClip clip, Vector3 location, Transform parent = null, bool autoDestroy = true) + { + return Sound3D(clip, location, parent, null, 1f, false, 0f, autoDestroy); + } + public static AudioSource Sound2D(AudioClip clip, AudioMixerGroup group = null, float rolloffDistanceMin = 1f, bool loop = false, float pauseTime = 0, bool autoDestroy = true) + { + if (Get() != null) + { + return Get().PlaySound2D(clip, group, 1, loop, pauseTime, autoDestroy); + } + else + { + GameObject AudioObject = new GameObject(); + AudioObject.name = "Audio_" + clip.name; + AudioObject.transform.SetParent(Game.World.transform); + AudioSource source = AudioObject.AddComponent(); + source.clip = clip; + source.outputAudioMixerGroup = group; + source.spatialBlend = 0; + source.minDistance = rolloffDistanceMin; + source.Play(); + if (autoDestroy) + { + AudioObject.AddComponent(clip.length); + } + else + { + Debug.LogWarning("for loop or puaseTime , you need to use AudioManager"); + } + return source; + } + } + public static AudioSource Sound2D(AudioClip clip, bool autoDestroy = true) + { + return Sound2D(clip, null, 1f, false, 0f, autoDestroy); + } + + // Clone + public static T Clone(T original, Object spawner = null) where T : Object + { + if (spawner != null) + { + var target = Object.Instantiate(original); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(original); + } + } + public static T Clone(T original, Transform parent, Object spawner = null) where T : Object + { + if (spawner != null) + { + var target = Object.Instantiate(original, parent); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(original, parent); + } + } + public static T Clone(T original, Vector3 position, Quaternion rotation, Object spawner = null) where T : Object + { + if (spawner != null) + { + var target = Object.Instantiate(original, position, rotation); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(original, position, rotation); + } + } + public static T Clone(T original, Transform parent, bool worldPositionStays, Object spawner = null) where T : Object + { + if (spawner != null) + { + var target = Object.Instantiate(original, parent, worldPositionStays); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(original, parent, worldPositionStays); + } + } + + // Prefab + public static GameObject Prefab(PrefabCore prefab, Object spawner = null) + { + if (spawner != null) + { + GameObject target = Object.Instantiate(prefab, Game.World.transform); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab, Game.World.transform); + } + } + public static GameObject Prefab(PrefabCore prefab, Transform parent, Object spawner = null) + { + if (spawner != null) + { + GameObject target = Object.Instantiate(prefab, parent); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab, parent); + } + } + public static GameObject Prefab(PrefabCore prefab, Transform parent, bool instantiateInWorldSpace, Object spawner = null) + { + if (spawner != null) + { + GameObject target = Object.Instantiate(prefab, parent, instantiateInWorldSpace); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab, parent, instantiateInWorldSpace); + } + } + public static GameObject Prefab(PrefabCore prefab, Vector3 position, Vector3 rotation, Object spawner = null) + { + if (spawner != null) + { + GameObject target = Object.Instantiate(prefab, position, Quaternion.Euler(rotation)); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab, position, Quaternion.Euler(rotation)); + } + } + public static GameObject Prefab(PrefabCore prefab, Vector3 position, Quaternion rotation, Object spawner = null) + { + if (spawner != null) + { + GameObject target = Object.Instantiate(prefab, position, rotation); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab, position, rotation); + } + } + public static GameObject Prefab(PrefabCore prefab, Vector3 position, Object spawner = null) + { + if (spawner != null) + { + GameObject target = Object.Instantiate(prefab, position, Quaternion.identity); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab, position, Quaternion.identity); + } + } + public static GameObject Prefab(PrefabCore prefab, Vector3 position, Vector3 rotation, Transform parent, Object spawner = null) + { + if (spawner != null) + { + GameObject target = Object.Instantiate(prefab, position, Quaternion.Euler(rotation), parent); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab, position, Quaternion.Euler(rotation), parent); + } + } + public static GameObject Prefab(PrefabCore prefab, UnityEngine.SceneManagement.Scene scene, Object spawner = null) + { + if (spawner != null) + { + GameObject target = Object.Instantiate(prefab, scene) as GameObject; + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab, scene) as GameObject; + } + + } + public static T Prefab(PrefabCore prefab, Object spawner = null) where T : Component + { + if (spawner != null) + { + T target = Object.Instantiate(prefab.GetMainComponent()); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab.GetMainComponent()); + } + } + public static T Prefab(PrefabCore prefab, Transform parent, Object spawner = null) where T : Component + { + if (spawner != null) + { + T target = Object.Instantiate(prefab.GetMainComponent(), parent); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab.GetMainComponent(), parent); + } + } + public static T Prefab(PrefabCore prefab, Vector3 position, Quaternion rotation, Object spawner = null) where T : Component + { + if (spawner != null) + { + T target = Object.Instantiate(prefab.GetMainComponent(), position, rotation); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab.GetMainComponent(), position, rotation); + } + } + public static T Prefab(PrefabCore prefab, Transform parent, bool worldPositionStays, Object spawner = null) where T : Component + { + if (spawner != null) + { + T target = Object.Instantiate(prefab.GetMainComponent(), parent, worldPositionStays); + target.InvokeSpawnEvent(spawner); + return target; + } + else + { + return Object.Instantiate(prefab.GetMainComponent(), parent, worldPositionStays); + } + } + + // Pool + public static T Pool(PoolAsset asset) where T : Component + { + if (asset is IPoolSpawner pooler) + { + return pooler.Spawn(); + } + else + { + Debug.LogWarning("PoolAsset does not implement IPoolSpawner."); + return null; + } + } + public static T Pool(PoolAsset asset, Vector3 location) where T : Component + { + if (asset is IPoolSpawner pooler) + { + return pooler.Spawn(location); + } + else + { + Debug.LogWarning("PoolAsset does not implement IPoolSpawner."); + return null; + } + } + public static T Pool(PoolAsset asset, Vector3 location, Quaternion rotation) where T : Component + { + if (asset is IPoolSpawner pooler) + { + return pooler.Spawn(location, rotation); + } + else + { + Debug.LogWarning("PoolAsset does not implement IPoolSpawner."); + return null; + } + } + public static T Pool(PoolAsset asset, Vector3 location, Quaternion rotation, Vector3 scale) where T : Component + { + if (asset is IPoolSpawner pooler) + { + return pooler.Spawn(location, rotation, scale); + } + else + { + Debug.LogWarning("PoolAsset does not implement IPoolSpawner."); + return null; + } + } + + // Effect + public static EffectPlayer Effect(EPrefab prefab, Object spawner = null) + { + return Prefab(prefab, spawner); + } + public static EffectPlayer Effect(EPrefab prefab, Vector3 location, Vector3 rotation, Object spawner = null) + { + return Prefab(prefab, location, Quaternion.Euler(rotation), spawner); + } + public static EffectPlayer Effect(EPrefab prefab, Transform parent, Object spawner = null) + { + return Prefab(prefab, parent, spawner); + } + + // Haptic + public static IHapticProvider Haptic(HapticConfig config, ScopeTarget Scope = ScopeTarget.Both) + { + return Get(Scope).Produce(config); + } + + // Particle + public static ParticleSystem Particle(PSPrefab prefab, Vector3 location, Vector3 rotation, Object spawner = null) + { + return Prefab(prefab, location, Quaternion.Euler(rotation), spawner); + } + public static ParticleSystem Particle(PSPrefab prefab, Transform parent, Object spawner = null) + { + return Prefab(prefab, parent, spawner); + } + + // Code + public static T Component(GameObject target, Object spawner = null) where T : MonoBehaviour + { + if (target) + { + var result = target.AddComponent(); + if (spawner != null) + { + result.InvokeSpawnEvent(spawner); + } + return target.AddComponent(); + } + else + { + Debug.LogWarning($" {Instance}: target is not valid."); + return null; + } + + } + public static T Class(System.Type classType) + { + if (classType == null) + { + Debug.LogWarning($" {Instance}: ClassType is not valid!"); + return default; + } + return (T)System.Activator.CreateInstance(classType); + } + + // Realmethod + public static T Command(CPrefab prefab, MonoBehaviour owner) where T : Command + { + if (owner == null) + { + Debug.LogWarning($" {Instance}: Owner or Author is not available."); + return null; + } + GameObject SpawnedObject = Object.Instantiate(prefab, owner.transform); + T TargetCommand = SpawnedObject.GetComponent(); + if (!TargetCommand.GetComponent().Initiate(owner)) + { + Debug.LogWarning($"Spawn Command Breack: Initiation failed for command '{typeof(T).Name}' on '{prefab.NameID}'."); + } + return TargetCommand; + } + public static T Asset(Object spawner = null) where T : PrimitiveAsset + { + var target = ScriptableObject.CreateInstance(); + target.InvokeSpawnEvent(spawner); + target.name = $"{typeof(T).Name}_Instance"; + + return target; + } + public static PrimitiveAsset Asset(System.Type type, Object spawner = null) + { + if (type == null) + throw new System.ArgumentNullException(nameof(type)); + + if (!typeof(PrimitiveAsset).IsAssignableFrom(type)) + throw new System.ArgumentException( + $"Type {type.Name} must inherit from PrimitiveAsset."); + + PrimitiveAsset target = (PrimitiveAsset)ScriptableObject.CreateInstance(type); + target.InvokeSpawnEvent(spawner); + target.name = $"{type.Name}_Instance"; + + return target; + } + public static bool Service(ScopeTarget Scope = ScopeTarget.Game) where T : GameService, new() + { + T newModule = GetScope(Scope).AddModule(); + if (newModule != null) + { + newModule.InvokeReqisterEvent(); + return true; + } + return false; + } + public static T Service(System.Type ServiceType, ScopeTarget Scope = ScopeTarget.Game) where T : IService + { + if (ServiceType == null) + { + Debug.LogWarning($" {Instance}: classType is not valid."); + return default; + } + + if (!ServiceType.HasImplementInterface()) + { + Debug.LogWarning($" {ServiceType.Name}: has not implement any IService."); + return default; + } + + GameModule newModule = GetScope(Scope).AddModule(ServiceType); + if (newModule != null) + { + newModule.InvokeReqisterEvent(); + if (newModule is T provider) + { + return provider; + } + } + + return default; + } + public static J Service(ScopeTarget Scope = ScopeTarget.Game) where T : GameService, new() where J : IService + { + T newModule = GetScope(Scope).AddModule(); + if (newModule != null) + { + newModule.InvokeReqisterEvent(); + if (newModule is J provider) + { + return provider; + } + } + return default; + } + + + // Task + public static T Task(F Task, bool AutoStart = false) where T : IHandle where F : class + { + TaskManager manager = Get>(); + if (manager == null) + return default; + return manager.Create(Task, AutoStart); + } + + // Enumerator + public static Coroutine Coroutine(IEnumerator routine) + { + return Get().Run(routine); + } + public static ICoroutineTask CoroutineTask(IEnumerator routine) + { + return Get().StartTask(routine); + } + + // Other + public static GameObject Empty(string name) + { + return new GameObject(name); + } + public static MeshRenderer Mesh(Mesh geometry) + { + GameObject emptyobject = new GameObject(geometry.name); + emptyobject.AddComponent().mesh = geometry; + return emptyobject.AddComponent(); + } + public static MeshRenderer Mesh(Mesh geometry, Vector3 location) + { + MeshRenderer result = Mesh(geometry); + result.transform.position = location; + return result; + } + public static AudioSource Audio(AudioClip clip) + { + GameObject emptyobject = new GameObject(clip.name); + AudioSource source = emptyobject.AddComponent(); + source.clip = clip; + if (Get() != null) + { + source.outputAudioMixerGroup = Get().DefaultGroup; + emptyobject.transform.SetParent(Get().transform); + } + return source; + } + + + + private static Scope GetScope(ScopeTarget Scope) + { + switch (Scope) + { + case ScopeTarget.Game: + return Game.Instance; + case ScopeTarget.World: + return Game.World; + default: + Debug.LogWarning("Your ScopeTarget should be World or Game"); + return null; + } + } + } +} + diff --git a/Runtime/ReadySet/Services/SpawanService.cs.meta b/Runtime/ReadySet/Services/Spawan.cs.meta similarity index 100% rename from Runtime/ReadySet/Services/SpawanService.cs.meta rename to Runtime/ReadySet/Services/Spawan.cs.meta diff --git a/Runtime/ReadySet/Services/SpawanService.cs b/Runtime/ReadySet/Services/SpawanService.cs deleted file mode 100644 index 71391244..00000000 --- a/Runtime/ReadySet/Services/SpawanService.cs +++ /dev/null @@ -1,923 +0,0 @@ -using System.Collections; -using UnityEngine; -using UnityEngine.Audio; -using UnityEngine.UIElements; - -namespace RealMethod -{ - public sealed class Spawn : Service - { - private static Spawn CacheInstance = null; - public static Spawn instance - { - get - { - if (CacheInstance != null) - { - return CacheInstance; - } - else - { - if (Game.TryFindService(out Spawn CacheInstance)) - { - return CacheInstance; - } - CacheInstance = Game.AddService(null); - return CacheInstance; - } - } - } - - public Despawn GameDespawn; - public AudioManager GameAudio; - public UIManager GameUI; - public ScreenManager GameScreen; - public TaskManager GameTask; - public HapticManager GameHaptic; - public EnumeratorManager GameEnumerator; - - // Base Service - protected override void OnStart(object Author) - { - GameDespawn = new Despawn(); - } - protected override void OnNewWorld() - { - } - protected override void OnEnd(object Author) - { - GameDespawn = null; - GameAudio = null; - GameUI = null; - GameScreen = null; - GameTask = null; - GameHaptic = null; - GameEnumerator = null; - CacheInstance = null; - } - - // Public Functions - public void BringManager(IGameManager manager) - { - MonoBehaviour TargetManager = manager.GetManagerClass(); - switch (TargetManager) // **Order is very important** - { - case ScreenManager screenmanager: // Bring ScreenManager - if (GameScreen == null) - { - GameScreen = screenmanager; - } - else - { - Debug.LogError($"Spawn Service already have {typeof(ScreenManager)} Cant Enter this {screenmanager}"); - } - break; - case TaskManager taskmanager: // Bring TaskManager - if (GameTask == null) - { - GameTask = taskmanager; - } - else - { - Debug.LogError($"Spawn Service already have {typeof(TaskManager)} Cant Enter this {taskmanager}"); - } - break; - case EnumeratorManager enumeratormanager: - if (GameEnumerator == null) - { - GameEnumerator = enumeratormanager; - } - else - { - Debug.LogError($"Spawn Service already have {typeof(EnumeratorManager)} Cant Enter this {enumeratormanager}"); - } - break; - case HapticManager hapticmanager: - if (GameHaptic == null) - { - GameHaptic = hapticmanager; - } - else - { - Debug.LogError($"Spawn Service already have {typeof(HapticManager)} Cant Enter this {hapticmanager}"); - } - break; - case AudioManager audiomanager: // Brind AudioManager - if (GameAudio == null) - { - GameAudio = audiomanager; - } - else - { - Debug.LogError($"Spawn Service already have {typeof(AudioManager)} Cant Enter this {audiomanager}"); - } - break; - case UIManager uIManager: // Brind UIManager - if (GameUI == null) - { - GameUI = uIManager; - } - else - { - Debug.LogError($"Spawn Service already have {typeof(UIManager)} Cant Enter this {uIManager}"); - } - break; - default: - Debug.LogWarning($"{TargetManager.gameObject}:Manager not define in SpawnService"); - break; - } - } - - - // UI - public static T Widget(string Name, Object spawner = null) where T : MonoBehaviour - { - if (instance.GameUI != null) - { - return instance.GameUI.CreateLayer(Name, spawner); - } - else - { - Debug.LogWarning($" {instance}: UIManager is not available."); - return null; - } - } - public static T Widget(VisualTreeAsset UIAsset, string Name, Object spawner = null) where T : MonoBehaviour - { - if (instance.GameUI != null) - { - return instance.GameUI.CreateLayer(Name, UIAsset, spawner); - } - else - { - Debug.LogWarning($" {instance}: UIManager is not available."); - return null; - } - } - public static GameObject Widget(UPrefab Prefab, string Name, Object spawner = null) - { - if (instance.GameUI != null) - { - return instance.GameUI.AddLayer(Name, Prefab, spawner); - } - else - { - Debug.LogWarning($" {instance}: UIManager is not available."); - return null; - } - } - public static T Widget(UPrefab Prefab, string Name, Object spawner = null) where T : MonoBehaviour - { - if (instance.GameUI != null) - { - return instance.GameUI.AddLayer(Name, Prefab, spawner); - } - else - { - Debug.LogWarning($" {instance}: UIManager is not available."); - return null; - } - } - public static UIDocument UIDoc(string Name, VisualTreeAsset UIAsset) - { - if (instance.GameUI != null) - { - return instance.GameUI.CreateLayer(Name, UIAsset); - } - else - { - Debug.LogWarning($" {instance}: UIManager is not available."); - return null; - } - } - - // Screen - public static void Message(string message) - { - if (instance.GameScreen != null) - { - if (instance.GameScreen.Informer != null) - { - instance.GameScreen.Informer.Popup(message); - } - else - { - Debug.LogWarning($"ScreenMaanger need to set Informer"); - } - } - else - { - Debug.LogWarning($" {instance}: ScreenManager is not available."); - } - } - public static void Message(string message, float duration) - { - if (instance.GameScreen != null) - { - if (instance.GameScreen.Informer != null) - { - instance.GameScreen.Informer.Popup(message, duration); - } - else - { - Debug.LogWarning($"ScreenMaanger need to set Informer"); - } - } - else - { - Debug.LogWarning($" {instance}: ScreenManager is not available."); - } - } - - // Sound - public static AudioSource Sound3D(AudioClip clip, Vector3 location, Transform parent = null, AudioMixerGroup group = null, float rolloffDistanceMin = 1f, bool loop = false, float pauseTime = 0, bool autoDestroy = true) - { - if (instance.GameAudio != null) - { - return instance.GameAudio.PlaySound(clip, location, parent, group, rolloffDistanceMin, loop, pauseTime, autoDestroy); - } - else - { - GameObject AudioObject = new GameObject(); - AudioObject.name = "Audio_" + clip.name; - AudioSource source = AudioObject.AddComponent(); - source.clip = clip; - source.outputAudioMixerGroup = group; - source.spatialBlend = 0; - source.minDistance = rolloffDistanceMin; - source.transform.SetParent(parent != null ? parent : Game.World.transform); - AudioObject.transform.localPosition = location; - source.Play(); - if (autoDestroy) - { - AudioObject.AddComponent(clip.length); - } - else - { - Debug.LogWarning("for loop or puaseTime , you need to use AudioManager"); - } - return source; - } - } - public static AudioSource Sound3D(AudioClip clip, Vector3 location, Transform parent = null, bool autoDestroy = true) - { - return Sound3D(clip, location, parent, null, 1f, false, 0f, autoDestroy); - } - public static AudioSource Sound2D(AudioClip clip, AudioMixerGroup group = null, float rolloffDistanceMin = 1f, bool loop = false, float pauseTime = 0, bool autoDestroy = true) - { - if (instance.GameAudio != null) - { - return instance.GameAudio.PlaySound2D(clip, group, 1, loop, pauseTime, autoDestroy); - } - else - { - GameObject AudioObject = new GameObject(); - AudioObject.name = "Audio_" + clip.name; - AudioObject.transform.SetParent(Game.World.transform); - AudioSource source = AudioObject.AddComponent(); - source.clip = clip; - source.outputAudioMixerGroup = group; - source.spatialBlend = 0; - source.minDistance = rolloffDistanceMin; - source.Play(); - if (autoDestroy) - { - AudioObject.AddComponent(clip.length); - } - else - { - Debug.LogWarning("for loop or puaseTime , you need to use AudioManager"); - } - return source; - } - } - public static AudioSource Sound2D(AudioClip clip, bool autoDestroy = true) - { - return Sound2D(clip, null, 1f, false, 0f, autoDestroy); - } - - // Clone - public static T Clone(T original, Object spawner = null) where T : Object - { - if (spawner != null) - { - var target = Object.Instantiate(original); - if (target is MonoBehaviour mono) - { - mono.SendSpawnEvent(spawner); - } - else if (target is GameObject obj) - { - obj.SendSpawnEvent(spawner); - } - else - { - Debug.LogWarning($"Spawn Event can only be sent to MonoBehaviour or GameObject. Target type: {target.GetType()}"); - } - return target; - } - else - { - return Object.Instantiate(original); - } - } - public static T Clone(T original, Transform parent, Object spawner = null) where T : Object - { - if (spawner != null) - { - var target = Object.Instantiate(original, parent); - if (target is MonoBehaviour mono) - { - mono.SendSpawnEvent(spawner); - } - else if (target is GameObject obj) - { - obj.SendSpawnEvent(spawner); - } - else - { - Debug.LogWarning($"Spawn Event can only be sent to MonoBehaviour or GameObject. Target type: {target.GetType()}"); - } - return target; - } - else - { - return Object.Instantiate(original, parent); - } - } - public static T Clone(T original, Vector3 position, Quaternion rotation, Object spawner = null) where T : Object - { - if (spawner != null) - { - var target = Object.Instantiate(original, position, rotation); - if (target is MonoBehaviour mono) - { - mono.SendSpawnEvent(spawner); - } - else if (target is GameObject obj) - { - obj.SendSpawnEvent(spawner); - } - else - { - Debug.LogWarning($"Spawn Event can only be sent to MonoBehaviour or GameObject. Target type: {target.GetType()}"); - } - return target; - } - else - { - return Object.Instantiate(original, position, rotation); - } - } - public static T Clone(T original, Transform parent, bool worldPositionStays, Object spawner = null) where T : Object - { - if (spawner != null) - { - var target = Object.Instantiate(original, parent, worldPositionStays); - if (target is MonoBehaviour mono) - { - mono.SendSpawnEvent(spawner); - } - else if (target is GameObject obj) - { - obj.SendSpawnEvent(spawner); - } - else - { - Debug.LogWarning($"Spawn Event can only be sent to MonoBehaviour or GameObject. Target type: {target.GetType()}"); - } - return target; - } - else - { - return Object.Instantiate(original, parent, worldPositionStays); - } - } - - // Prefab - public static GameObject Prefab(PrefabCore prefab, Object spawner = null) - { - if (spawner != null) - { - GameObject target = Object.Instantiate(prefab.asset, Game.World.transform); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.asset, Game.World.transform); - } - } - public static GameObject Prefab(PrefabCore prefab, Transform parent, Object spawner = null) - { - if (spawner != null) - { - GameObject target = Object.Instantiate(prefab.asset, parent); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.asset, parent); - } - } - public static GameObject Prefab(PrefabCore prefab, Transform parent, bool instantiateInWorldSpace, Object spawner = null) - { - if (spawner != null) - { - GameObject target = Object.Instantiate(prefab.asset, parent, instantiateInWorldSpace); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.asset, parent, instantiateInWorldSpace); - } - } - public static GameObject Prefab(PrefabCore prefab, Vector3 position, Vector3 rotation, Object spawner = null) - { - if (spawner != null) - { - GameObject target = Object.Instantiate(prefab.asset, position, Quaternion.Euler(rotation)); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.asset, position, Quaternion.Euler(rotation)); - } - } - public static GameObject Prefab(PrefabCore prefab, Vector3 position, Quaternion rotation, Object spawner = null) - { - if (spawner != null) - { - GameObject target = Object.Instantiate(prefab.asset, position, rotation); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.asset, position, rotation); - } - } - public static GameObject Prefab(PrefabCore prefab, Vector3 position, Object spawner = null) - { - if (spawner != null) - { - GameObject target = Object.Instantiate(prefab.asset, position, Quaternion.identity); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.asset, position, Quaternion.identity); - } - } - public static GameObject Prefab(PrefabCore prefab, Vector3 position, Vector3 rotation, Transform parent, Object spawner = null) - { - if (spawner != null) - { - GameObject target = Object.Instantiate(prefab.asset, position, Quaternion.Euler(rotation), parent); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.asset, position, Quaternion.Euler(rotation), parent); - } - } - public static GameObject Prefab(PrefabCore prefab, UnityEngine.SceneManagement.Scene scene, Object spawner = null) - { - if (spawner != null) - { - GameObject target = Object.Instantiate(prefab.asset, scene) as GameObject; - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.asset, scene) as GameObject; - } - - } - public static T Prefab(PrefabCore prefab, Object spawner = null) where T : Component - { - if (spawner != null) - { - T target = Object.Instantiate(prefab.GetSoftClassTarget()); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.GetSoftClassTarget()); - } - } - public static T Prefab(PrefabCore prefab, Transform parent, Object spawner = null) where T : Component - { - if (spawner != null) - { - T target = Object.Instantiate(prefab.GetSoftClassTarget(), parent); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.GetSoftClassTarget(), parent); - } - } - public static T Prefab(PrefabCore prefab, Vector3 position, Quaternion rotation, Object spawner = null) where T : Component - { - if (spawner != null) - { - T target = Object.Instantiate(prefab.GetSoftClassTarget(), position, rotation); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.GetSoftClassTarget(), position, rotation); - } - } - public static T Prefab(PrefabCore prefab, Transform parent, bool worldPositionStays, Object spawner = null) where T : Component - { - if (spawner != null) - { - T target = Object.Instantiate(prefab.GetSoftClassTarget(), parent, worldPositionStays); - target.SendSpawnEvent(spawner); - return target; - } - else - { - return Object.Instantiate(prefab.GetSoftClassTarget(), parent, worldPositionStays); - } - } - - // Pool - public static T Pool(PoolAsset asset) where T : Component - { - if (asset is IPoolSpawner pooler) - { - return pooler.Spawn(); - } - else - { - Debug.LogWarning("PoolAsset does not implement IPoolSpawner."); - return null; - } - } - public static T Pool(PoolAsset asset, Vector3 location) where T : Component - { - if (asset is IPoolSpawner pooler) - { - return pooler.Spawn(location); - } - else - { - Debug.LogWarning("PoolAsset does not implement IPoolSpawner."); - return null; - } - } - public static T Pool(PoolAsset asset, Vector3 location, Quaternion rotation) where T : Component - { - if (asset is IPoolSpawner pooler) - { - return pooler.Spawn(location, rotation); - } - else - { - Debug.LogWarning("PoolAsset does not implement IPoolSpawner."); - return null; - } - } - public static T Pool(PoolAsset asset, Vector3 location, Quaternion rotation, Vector3 scale) where T : Component - { - if (asset is IPoolSpawner pooler) - { - return pooler.Spawn(location, rotation, scale); - } - else - { - Debug.LogWarning("PoolAsset does not implement IPoolSpawner."); - return null; - } - } - - // Effect - public static EffectPlayer Effect(EPrefab prefab, Object spawner = null) - { - return Prefab(prefab, spawner); - } - public static EffectPlayer Effect(EPrefab prefab, Vector3 location, Vector3 rotation, Object spawner = null) - { - return Prefab(prefab, location, Quaternion.Euler(rotation), spawner); - } - public static EffectPlayer Effect(EPrefab prefab, Transform parent, Object spawner = null) - { - return Prefab(prefab, parent, spawner); - } - - // Haptic - public static IHapticProvider Haptic(HapticConfig config) - { - if (instance.GameHaptic != null) - { - return instance.GameHaptic.Produce(config); - } - else - { - Debug.LogWarning($" {instance}: HapticManager is not available."); - return null; - } - } - - // Particle - public static ParticleSystem Particle(PSPrefab prefab, Vector3 location, Vector3 rotation, Object spawner = null) - { - return Prefab(prefab, location, Quaternion.Euler(rotation), spawner); - } - public static ParticleSystem Particle(PSPrefab prefab, Transform parent, Object spawner = null) - { - return Prefab(prefab, parent, spawner); - } - - // Code - public static T Component(GameObject target, Object spawner = null) where T : MonoBehaviour - { - if (target) - { - var result = target.AddComponent(); - if (spawner != null) - { - result.SendSpawnEvent(spawner); - } - return target.AddComponent(); - } - else - { - Debug.LogWarning($" {instance}: target is not valid."); - return null; - } - - } - public static T Class() where T : Object, new() - { - return new T(); - } - - // Realmethod - public static T Command(CPrefab prefab, MonoBehaviour owner, Object author) where T : Command - { - if (owner == null || author == null) - { - Debug.LogWarning($" {instance}: Owner or Author is not available."); - return null; - } - GameObject SpawnedObject = Object.Instantiate(prefab.asset, owner.transform); - T TargetCommand = SpawnedObject.GetComponent(); - if (!TargetCommand.GetComponent().Initiate(author, owner)) - { - Debug.LogWarning($"Spawn Command Breack: Initiation failed for command '{typeof(T).Name}' on '{prefab.NameID}'."); - } - return TargetCommand; - } - public static T Asset(Object spawner = null) where T : PrimitiveAsset - { - if (spawner != null) - { - var target = ScriptableObject.CreateInstance(); - IAsset provider = target; - provider.OnSpawned(spawner); - return target; - } - else - { - return ScriptableObject.CreateInstance(); - } - } - - // Task - public static bool Task(object TaskObj, Object author) - { - if (instance.GameTask != null) - { - if (TaskObj is ITask task) - { - if (!instance.GameTask.IsValid(task)) - { - instance.GameTask.Add(task, author); - return true; - } - else - { - Debug.LogWarning($"Task already is running"); - return false; - } - } - else - { - Debug.LogWarning($"Your Object should have {typeof(ITask)} Interface"); - return false; - } - } - else - { - Debug.LogWarning($" {instance}: TaskManager is not available."); - return false; - } - } - - // Enumerator - public static Coroutine Coroutine(IEnumerator routine) - { - if (instance.GameEnumerator != null) - { - return instance.GameEnumerator.Run(routine); - } - else - { - Debug.LogWarning($" {instance}: EnumeratorManager is not available."); - return null; - } - } - public static ICoroutineTask CoroutineTask(IEnumerator routine) - { - if (instance.GameEnumerator != null) - { - return instance.GameEnumerator.StartTask(routine); - } - else - { - Debug.LogWarning($" {instance}: EnumeratorManager is not available."); - return null; - } - } - - // Other - public static GameObject Empty(string name) - { - return new GameObject(name); - } - public static MeshRenderer Mesh(Mesh geometry) - { - GameObject emptyobject = new GameObject(geometry.name); - emptyobject.AddComponent().mesh = geometry; - return emptyobject.AddComponent(); - } - public static MeshRenderer Mesh(Mesh geometry, Vector3 location) - { - MeshRenderer result = Mesh(geometry); - result.transform.position = location; - return result; - } - public static AudioSource Audio(AudioClip clip) - { - GameObject emptyobject = new GameObject(clip.name); - AudioSource source = emptyobject.AddComponent(); - source.clip = clip; - if (instance.GameAudio != null) - { - source.outputAudioMixerGroup = instance.GameAudio.defaultGroup; - emptyobject.transform.SetParent(instance.GameAudio.transform); - } - return source; - } - - } - - public sealed class Despawn - { - // UI - public static bool Widget(string Name, Object spawner = null, bool debug = true) - { - if (Spawn.instance.GameUI == null) - { - if (debug) - Debug.LogWarning("Despawn UIManager is not available."); - return false; - } - - return Spawn.instance.GameUI.RemoveLayer(Name, spawner); - } - public static bool Widget(MonoBehaviour Comp, Object spawner = null, bool debug = true) - { - if (Spawn.instance.GameUI == null) - { - if (debug) - Debug.LogWarning("Despawn UIManager is not available."); - return false; - } - - return Spawn.instance.GameUI.RemoveLayer(Comp, spawner); - } - - // Prefab - public static bool GameObject(GameObject target, Object spawner = null, bool debug = true) - { - if (target != null) - { - if (spawner != null) - { - target.SendDespawnEvent(spawner); - } - Object.Destroy(target); - return true; - } - else - { - if (debug) - Debug.LogWarning("Despawn target is not available."); - return false; - } - } - - // Pool - public static bool Pool(PoolAsset asset, bool debug = true) where T : Component - { - if (asset is IPoolDespawner pooler) - { - pooler.Despawn(); - return true; - } - else - { - if (debug) - Debug.LogWarning("PoolAsset does not implement IPoolDespawner."); - return false; - } - } - public static bool Pool(PoolAsset asset, T target, bool debug = true) where T : Component - { - if (asset is IPoolDespawner pooler) - { - pooler.Despawn(target); - return true; - } - else - { - if (debug) - Debug.LogWarning("PoolAsset does not implement IPoolDespawner."); - return false; - } - } - - // Task - public static bool Task(object TaskObj, Object author, bool debug = true) - { - if (Spawn.instance.GameTask == null) - { - if (debug) - Debug.LogWarning("TaskManager is not available."); - return false; - } - - if (TaskObj is ITask task) - { - if (Spawn.instance.GameTask.IsValid(task)) - { - Spawn.instance.GameTask.Remove(task, author); - return true; - } - else - { - if (debug) - Debug.LogWarning($"Task Not Found!"); - return false; - } - } - else - { - if (debug) - Debug.LogWarning($"Your Object should have {typeof(ITask)} Interfave"); - return false; - } - } - - // Enumerator - public static bool Coroutine(Coroutine coroutine, bool debug = true) - { - if (Spawn.instance.GameEnumerator == null) - { - if (debug) - Debug.LogWarning("TaskManager is not available."); - return false; - } - - Spawn.instance.GameEnumerator.Stop(coroutine); - return true; - } - - // Haptic - public static bool Haptic(IHapticProvider provider, bool debug = true) - { - if (Spawn.instance.GameHaptic == null) - { - if (debug) - Debug.LogWarning("HapticManager is not available."); - return false; - } - return Spawn.instance.GameHaptic.Demolish(provider); - } - } -} - diff --git a/Runtime/ReadySet/Services/TimeService.cs b/Runtime/ReadySet/Services/TimeService.cs index c98316bb..0d92e9a9 100644 --- a/Runtime/ReadySet/Services/TimeService.cs +++ b/Runtime/ReadySet/Services/TimeService.cs @@ -2,27 +2,38 @@ namespace RealMethod { - public sealed class TimeService : Service + public interface ITimer : IService + { + + } + + public sealed class TimeService : GameService, ITimer { private float serviceTime; private float worldTime; - private Hictionary RecordTime; + private NameTable RecordTime; - // Service Methods - protected override void OnStart(object Author) + // Module Methods + protected override void OnBegin() { serviceTime = Time.time; worldTime = Time.time; - RecordTime = new Hictionary(10); + RecordTime = new NameTable(10); } - protected override void OnNewWorld() + protected override void OnWorldChanged() { worldTime = Time.time; } - protected override void OnEnd(object Author) + protected override void OnEnd() { RecordTime.Clear(); } +#if UNITY_EDITOR + protected override string GetInspectorInfo() + { + return $"Record ({RecordTime.Count})"; + } +#endif // Public Functions public bool CheckRecord(string tag, float targettime) @@ -68,6 +79,8 @@ public bool IsValidTime(string tag) { return RecordTime.ContainsKey(tag); } + + } } diff --git a/Runtime/Toolkit/Ability/AbilityAsset.cs b/Runtime/Toolkit/Ability/AbilityAsset.cs index 8537322b..da105012 100644 --- a/Runtime/Toolkit/Ability/AbilityAsset.cs +++ b/Runtime/Toolkit/Ability/AbilityAsset.cs @@ -1,14 +1,13 @@ using System.Collections.Generic; using UnityEngine; + namespace RealMethod { - public abstract class AbilityAsset : TemplateAsset, IAbility, ICooldown + public abstract class AbilityAsset : CloneAsset, IAbility, ICooldown { private float lastUsedTime = -Mathf.Infinity; - // Implement IIdentifier Interface - string IIdentifier.NameID => name; // Implement IAbility Interface public bool CanUse(GameObject user) { @@ -59,13 +58,6 @@ public void ResetCooldown() protected abstract float GetCooldown(); protected abstract IAbilityEffect[] GetEffects(); protected abstract bool Prerequisite(GameObject user); - -#if UNITY_EDITOR - public override void OnEditorPlay() - { - lastUsedTime = -Mathf.Infinity; - } -#endif } public abstract class AbilityEffectAsset : AbilityAsset { @@ -120,13 +112,5 @@ private System.Type GetClassType(string classname) } return null; } - -#if UNITY_EDITOR - public override void OnEditorPlay() - { - base.OnEditorPlay(); - myEffects = null; - } -#endif } } \ No newline at end of file diff --git a/Runtime/Toolkit/Ability/AbilityController.cs b/Runtime/Toolkit/Ability/AbilityController.cs index 9a16a2d1..2a565cc0 100644 --- a/Runtime/Toolkit/Ability/AbilityController.cs +++ b/Runtime/Toolkit/Ability/AbilityController.cs @@ -39,7 +39,7 @@ void IAbilityAction.UseInput(InputAction.CallbackContext context) public abstract class AbilityController : MonoBehaviour { [System.Serializable] - private class InputAbility : SerializableDictionary { } + private class InputAbility : Map { } [Header("Setting")] [SerializeField] diff --git a/Runtime/Toolkit/Inventory/Inventory.cs b/Runtime/Toolkit/Inventory/Inventory.cs index b2dd96f9..fa1b3b8b 100644 --- a/Runtime/Toolkit/Inventory/Inventory.cs +++ b/Runtime/Toolkit/Inventory/Inventory.cs @@ -1,15 +1,16 @@ using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace RealMethod { - public class InventoryItemProperty : IResource + public class InventoryItemProperty : IResource, INameIdentifier { [SerializeField] private IInventoryItem Item; public IInventoryItem provider => Item; - public string Name => provider.NameID; + public string SelfName => provider.SelfName; [SerializeField] private int ItemQuantity; public int Quantity => ItemQuantity; @@ -102,7 +103,7 @@ private enum BehaviorType [SerializeField] private BehaviorType Behavior; [SerializeField] - private ItemAsset[] DefaultItem; + private PrimitiveAsset[] DefaultItem; // Actions public System.Action OnItemAdded; @@ -110,8 +111,8 @@ private enum BehaviorType public System.Action OnItemRemoved; // Private Variable - private Hictionary Items; - public int Count => Items.IsValid() ? Items.Count : 0; + private NameTable Items; + public int Count => Items.IsValid ? Items.Count : 0; protected IInventoryStorage inventoryStorage { get; private set; } @@ -136,17 +137,17 @@ private void Awake() if (LoadStorage()) { InventoryItemProperty[] cacheItems = inventoryStorage.GetItems(); - Items = new Hictionary(cacheItems.Length); + Items = new NameTable(cacheItems.Length); foreach (var data in cacheItems) { - Items.Add(data.Name, data); + Items.Add(data.SelfName, data); } } else { if (DefaultItem != null) { - Items = new Hictionary(DefaultItem.Length); + Items = new NameTable(DefaultItem.Length); foreach (var itemAsset in DefaultItem) { if (itemAsset is IInventoryItem item) @@ -162,7 +163,7 @@ private void Awake() } else { - Items = new Hictionary(5); + Items = new NameTable(5); } } } @@ -196,31 +197,31 @@ public bool TryFindResourceItem(string itemTitle, out IResource resource) } public IResource GetResourceProvider(IInventoryItem item) { - return Items[item.NameID]; + return Items[item.SelfName]; } public int GetQuantity(IInventoryItem item) { - if (Items.ContainsKey(item.NameID)) + if (Items.ContainsKey(item.SelfName)) { - return Items[item.NameID].Quantity; + return Items[item.SelfName].Quantity; } else { return 0; } } - public bool IsValidItem(IIdentifier item) + public bool IsValidItem(INameIdentifier Name) { - return Items.ContainsKey(item.NameID); + return Items.ContainsKey(Name.SelfName); } public bool AddNewItem(IInventoryItem item, int quantity, int capacity) { - if (!Items.ContainsKey(item.NameID)) + if (!Items.ContainsKey(item.SelfName)) { if (item.CanPickUp(this)) { InventoryItemProperty NewItem = new InventoryItemProperty(item, quantity, capacity); - Items.Add(item.NameID, NewItem); + Items.Add(item.SelfName, NewItem); inventoryStorage.CreateItem(NewItem); MessageBehavior(ItemState.Create, item, quantity); return true; @@ -232,7 +233,7 @@ public bool AddNewItem(IInventoryItem item, int quantity, int capacity) } else { - Debug.LogWarning($"Item with this Name {item.NameID} already there"); + Debug.LogWarning($"Item with this Name {item.SelfName} already there"); return false; } } @@ -240,11 +241,11 @@ public bool AddItem(IInventoryItem item, int quantity = 1) { if (_capacity == 0 || Items.Count < _capacity) { - if (Items.ContainsKey(item.NameID)) + if (Items.ContainsKey(item.SelfName)) { if (item.CanChange(true)) { - Items[item.NameID].Add(quantity); + Items[item.SelfName].Add(quantity); inventoryStorage.UpdateQuantity(item, quantity); MessageBehavior(ItemState.Update, item, quantity); } @@ -254,7 +255,7 @@ public bool AddItem(IInventoryItem item, int quantity = 1) if (item.CanPickUp(this)) { InventoryItemProperty NewItem = new InventoryItemProperty(item, quantity); - Items.Add(item.NameID, NewItem); + Items.Add(item.SelfName, NewItem); inventoryStorage.CreateItem(NewItem); MessageBehavior(ItemState.Create, item, quantity); } @@ -270,7 +271,7 @@ public bool AddItem(IInventoryItem item, int quantity = 1) public bool SetItemCapacity(IInventoryItem item, int newCpacity) { InventoryItemProperty target; - if (Items.TryGetValue(item.NameID, out target)) + if (Items.TryGetValue(item.SelfName, out target)) { inventoryStorage.UpdateCapacity(item, newCpacity); target.NewCpacity(newCpacity); @@ -278,14 +279,14 @@ public bool SetItemCapacity(IInventoryItem item, int newCpacity) } else { - Debug.LogError($"Can't Find Item With this Name {item.NameID}"); + Debug.LogError($"Can't Find Item With this Name {item.SelfName}"); return false; } } public bool RemoveItem(IInventoryItem item, int quantity = 1) { InventoryItemProperty target; - if (Items.TryGetValue(item.NameID, out target)) + if (Items.TryGetValue(item.SelfName, out target)) { if (item.CanChange(true)) { @@ -299,7 +300,7 @@ public bool RemoveItem(IInventoryItem item, int quantity = 1) { if (item.CanDropp(this)) { - if (Items.Remove(item.NameID)) + if (Items.Remove(item.SelfName)) { inventoryStorage.DestroyItem(item); MessageBehavior(ItemState.Delete, null, 0); @@ -332,9 +333,9 @@ public bool RemoveItem(IInventoryItem item, int quantity = 1) } public bool DeleteItem(IInventoryItem item) { - if (Items.ContainsKey(item.NameID)) + if (Items.ContainsKey(item.SelfName)) { - bool Result = Items.Remove(item.NameID); + bool Result = Items.Remove(item.SelfName); if (Result) { inventoryStorage.DestroyItem(item); @@ -351,7 +352,7 @@ public bool DeleteItem(IInventoryItem item) public T[] CopyItemsByClass() where T : IInventoryItem { List Result = new List(); - foreach (var pack in Items.GetValues()) + foreach (var pack in Items.Values) { if (pack.provider is T finditem) { @@ -363,15 +364,15 @@ public T[] CopyItemsByClass() where T : IInventoryItem public void Clear() { Items.Clear(); - inventoryStorage.StorageClear(); + ////inventoryStorage.StorageClear(); } // Protected Functions protected InventoryItemProperty[] GetCopyItemsProperty() { - var values = Items.GetValues(); + var values = Items.Values; var copy = new InventoryItemProperty[Items.Count]; - values.CopyTo(copy, 0); + values.ToArray().CopyTo(copy, 0); return copy; } @@ -461,17 +462,17 @@ public abstract class InventoryStorage : Inventory { [Header("Save")] [SerializeField] - private StorageFile storage; - public SaveFile file => storage.file; + private Storage storage; + public IFile file => storage.File; // override Methods protected sealed override IInventoryStorage GetStorage() { - return storage.provider; + return storage.File; } protected sealed override bool LoadStorage() { - return storage.Load(this); + return storage.IsExist; } } diff --git a/Runtime/Toolkit/Inventory/InventoryInterface.cs b/Runtime/Toolkit/Inventory/InventoryInterface.cs index 2f12e633..747df8dd 100644 --- a/Runtime/Toolkit/Inventory/InventoryInterface.cs +++ b/Runtime/Toolkit/Inventory/InventoryInterface.cs @@ -1,6 +1,6 @@ namespace RealMethod { - public interface IInventoryStorage : IStorage + public interface IInventoryStorage : IFile { InventoryItemProperty[] GetItems(); void CreateItem(InventoryItemProperty item); @@ -10,7 +10,7 @@ public interface IInventoryStorage : IStorage void UpdateCapacity(IInventoryItem item, int value); } - public interface IInventoryItem : IItem , IResourceItem + public interface IInventoryItem : IItem, IResourceItem, INameIdentifier { void PickedUp(Inventory owner, int quantity); void Cahanged(int quantity); diff --git a/Runtime/Toolkit/Inventory/InventorySaveFile.cs b/Runtime/Toolkit/Inventory/InventorySaveFile.cs index 8daf63f7..9dc15429 100644 --- a/Runtime/Toolkit/Inventory/InventorySaveFile.cs +++ b/Runtime/Toolkit/Inventory/InventorySaveFile.cs @@ -5,7 +5,7 @@ namespace RealMethod { [CreateAssetMenu(fileName = "InventorySaveFile", menuName = "RealMethod/Inventory/SaveFile", order = 1)] - public class InventorySaveFile : SaveFile, IInventoryStorage + public class InventorySaveFile : SaveFileAsset, IInventoryStorage { [Header("Inventory")] [SerializeField, ReadOnly, TextArea] @@ -22,62 +22,49 @@ public class InventorySaveFile : SaveFile, IInventoryStorage // SaveFile Methods - protected override void OnStable(DataManager manager) - { - - } protected override void OnSaved() { if (UsePlayerPrefs) { - RM_PlayerPrefs.SetArray("ItemsName", ItemsName.ToArray()); - RM_PlayerPrefs.SetArray("ItemsQuantity", ItemsQuantity.ToArray()); - RM_PlayerPrefs.SetArray("ItemsCapacity", ItemsCapacity.ToArray()); + RM_Save.SetArray("ItemsName", ItemsName.ToArray()); + RM_Save.SetArray("ItemsQuantity", ItemsQuantity.ToArray()); + RM_Save.SetArray("ItemsCapacity", ItemsCapacity.ToArray()); } } protected override void OnLoaded() { if (UsePlayerPrefs) { - ItemsName = RM_PlayerPrefs.GetArray("ItemsName").ToList(); - ItemsQuantity = RM_PlayerPrefs.GetArray("ItemsQuantity").ToList(); - ItemsCapacity = RM_PlayerPrefs.GetArray("ItemsCapacity").ToList(); - } - } - protected override void OnDeleted() - { - if (UsePlayerPrefs) - { - ItemsName = null; - ItemsQuantity = null; - ItemsCapacity = null; + ItemsName = RM_Save.GetArray("ItemsName").ToList(); + ItemsQuantity = RM_Save.GetArray("ItemsQuantity").ToList(); + ItemsCapacity = RM_Save.GetArray("ItemsCapacity").ToList(); } } // Implement IInventorySave Interface - void IStorage.StorageCreated(Object author) - { - } - void IStorage.StorageLoaded(Object author) - { - } + // void IStorage.StorageCreated(Object author) + // { + // } + // void IStorage.StorageLoaded(Object author) + // { + // } void IInventoryStorage.CreateItem(InventoryItemProperty item) { - ItemsName.Add(item.Name); + ItemsName.Add(item.SelfName); ItemsQuantity.Add(item.Quantity); ItemsCapacity.Add(item.Capacity); } void IInventoryStorage.DestroyItem(IInventoryItem item) { - int Target = GetIndexItem(item.NameID); + int Target = GetIndexItem(item.SelfName); ItemsName.RemoveAt(Target); ItemsQuantity.RemoveAt(Target); ItemsCapacity.RemoveAt(Target); } void IInventoryStorage.UpdateQuantity(IInventoryItem item, int amount) { - int Target = GetIndexItem(item.NameID); + int Target = GetIndexItem(item.SelfName); if (amount != 0) { ItemsQuantity[Target] += amount; @@ -90,7 +77,7 @@ void IInventoryStorage.UpdateQuantity(IInventoryItem item, int amount) } void IInventoryStorage.UpdateCapacity(IInventoryItem item, int value) { - int Target = GetIndexItem(item.NameID); + int Target = GetIndexItem(item.SelfName); ItemsCapacity[Target] = value; } InventoryItemProperty[] IInventoryStorage.GetItems() @@ -104,7 +91,7 @@ InventoryItemProperty[] IInventoryStorage.GetItems() { for (int i = 0; i < ItemsName.Count; i++) { - if (ItemsName[i] == item.NameID) + if (ItemsName[i] == item.SelfName) { Result.Add(new InventoryItemProperty(item, ItemsQuantity[i], ItemsCapacity[i])); continue; @@ -119,12 +106,12 @@ InventoryItemProperty[] IInventoryStorage.GetItems() } return Result.ToArray(); } - void IStorage.StorageClear() - { - ItemsName.Clear(); - ItemsQuantity.Clear(); - ItemsCapacity.Clear(); - } + // void IStorage.StorageClear() + // { + // ItemsName.Clear(); + // ItemsQuantity.Clear(); + // ItemsCapacity.Clear(); + // } // Private Functions private int GetIndexItem(string name) diff --git a/Runtime/Toolkit/PCG/Assets/PCGCashAsset.cs b/Runtime/Toolkit/PCG/Assets/PCGCashAsset.cs index fa9672c7..36d472c3 100644 --- a/Runtime/Toolkit/PCG/Assets/PCGCashAsset.cs +++ b/Runtime/Toolkit/PCG/Assets/PCGCashAsset.cs @@ -11,7 +11,6 @@ public interface IPCGCashAsset : IIdentifier public class PCGCashAsset : ConfigAsset, IPCGCashAsset { - public string NameID => name; [SerializeField] private PCGData[] CashData; diff --git a/Runtime/Toolkit/PCG/Assets/PCGGenerationAsset.cs b/Runtime/Toolkit/PCG/Assets/PCGGenerationAsset.cs index f4868fbe..16594da6 100644 --- a/Runtime/Toolkit/PCG/Assets/PCGGenerationAsset.cs +++ b/Runtime/Toolkit/PCG/Assets/PCGGenerationAsset.cs @@ -3,6 +3,10 @@ using System.Linq; using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + namespace RealMethod { [Serializable] @@ -168,7 +172,7 @@ private PCGData Stage_Background(PCGData Data) var requestInterface = MyRequest as ICommand; if (requestInterface != null) { - if (!requestInterface.Initiate(this, this)) + if (!requestInterface.Initiate(this)) { Debug.LogWarning($"{this.name}> ICommandInitiator.Initiate failed for {MyRequest.GetType().Name}"); } @@ -205,7 +209,7 @@ private PCGData Stage_Middleground(PCGData Data) var requestInterface = MyRequest as ICommand; if (requestInterface != null) { - if (!requestInterface.Initiate(this, this)) + if (!requestInterface.Initiate(this)) { Debug.LogWarning($"{this.name}> ICommandInitiator.Initiate failed for {MyRequest.GetType().Name}"); } @@ -242,7 +246,7 @@ private PCGData Stage_Foreground(PCGData Data) var requestInterface = MyRequest as ICommand; if (requestInterface != null) { - if (!requestInterface.Initiate(this, this)) + if (!requestInterface.Initiate(this)) { Debug.LogWarning($"{this.name}> ICommandInitiator.Initiate failed for {MyRequest.GetType().Name}"); } @@ -279,7 +283,7 @@ private PCGData Stage_PostProcess(PCGData Data) var requestInterface = MyRequest as ICommand; if (requestInterface != null) { - if (!requestInterface.Initiate(this, this)) + if (!requestInterface.Initiate(this)) { Debug.LogWarning($"{this.name}> ICommandInitiator.Initiate failed for {MyRequest.GetType().Name}"); } @@ -324,11 +328,19 @@ private void PrintGuide() Guide += MyLine + Environment.NewLine; } } -#if UNITY_EDITOR - public override void OnEditorPlay() + + private void Reset() { PrintGuide(); } + +#if UNITY_EDITOR + public override bool AutoReset(PlayModeStateChange state) + { + if (state == PlayModeStateChange.ExitingPlayMode) + return true; + return base.AutoReset(state); + } #endif } diff --git a/Runtime/Toolkit/PCG/Assets/PCGResourceConfig.cs b/Runtime/Toolkit/PCG/Assets/PCGResourceConfig.cs index e8a65fe0..623bab9d 100644 --- a/Runtime/Toolkit/PCG/Assets/PCGResourceConfig.cs +++ b/Runtime/Toolkit/PCG/Assets/PCGResourceConfig.cs @@ -36,7 +36,6 @@ public struct PCGSource [CreateAssetMenu(fileName = "PCG_Resource", menuName = "RealMethod/PCG/Resource", order = 1)] public class PCGResourceConfig : ConfigAsset, IPCGResource { - public string NameID => name; [SerializeField] private PCGSource[] Sources; diff --git a/Runtime/Toolkit/PCG/PCG.cs b/Runtime/Toolkit/PCG/PCG.cs index 6b771ac8..76e78dba 100644 --- a/Runtime/Toolkit/PCG/PCG.cs +++ b/Runtime/Toolkit/PCG/PCG.cs @@ -17,9 +17,9 @@ public abstract class PCG : MonoBehaviour private PCGType Type; [SerializeField] private PCGResourceConfig Resource; - [SerializeField, ShowInInspectorByEnum("Type", 1)] + [SerializeField, ConditionalShowByEnum("Type", 1)] private PCGGenerationAsset Generation; - [SerializeField, ShowInInspectorByEnum("Type", 0)] + [SerializeField, ConditionalShowByEnum("Type", 0)] private PCGCashAsset CashFile; [Header("Load")] [SerializeField] diff --git a/Runtime/Toolkit/PCG/PCGRequest.cs b/Runtime/Toolkit/PCG/PCGRequest.cs index 048ceb27..384fab40 100644 --- a/Runtime/Toolkit/PCG/PCGRequest.cs +++ b/Runtime/Toolkit/PCG/PCGRequest.cs @@ -14,7 +14,7 @@ public abstract class PCGRequest : ICommand private PCGGenerationAsset Owner; // Implement ICommand Interface - bool ICommand.Initiate(Object author, Object owner) + bool ICommand.Initiate(Object owner) { if (owner is PCGGenerationAsset result) { diff --git a/Runtime/Toolkit/Pickup/C_PickupItem.cs b/Runtime/Toolkit/Pickup/C_PickupItem.cs index 39ccb48a..5fac90c8 100644 --- a/Runtime/Toolkit/Pickup/C_PickupItem.cs +++ b/Runtime/Toolkit/Pickup/C_PickupItem.cs @@ -19,7 +19,7 @@ public sealed class C_PickupItem : Command private IInventoryItem itemprovider; // ExecutCommand Methods - protected override bool OnInitiate(Object author, Object owner) + protected override bool OnInitiate(Object owner) { if (items == null) { @@ -36,12 +36,12 @@ protected override bool OnInitiate(Object author, Object owner) return false; } } - protected override bool CanExecute(object Owner) + protected override bool CanExecute(object Executer) { if (!enabled) return false; - if (Owner is Component mono) + if (Executer is Component mono) { IPicker Picker = mono.GetComponent(); if (Picker != null) diff --git a/Runtime/Toolkit/RPG/Resource/ResourceData.cs b/Runtime/Toolkit/RPG/Resource/ResourceData.cs index bceffda4..0fcfe13b 100644 --- a/Runtime/Toolkit/RPG/Resource/ResourceData.cs +++ b/Runtime/Toolkit/RPG/Resource/ResourceData.cs @@ -44,7 +44,7 @@ public ResourceData(string ReName, float val, float max) float IResource.Value => value; float IResource.MaxValue => GetMaxValue(defaultMaxValue); // Implement IIdentifier Interface - public string NameID => resourceName; + public Name16 NameID => resourceName; void IResource.Refill() { value = provider.MaxValue; @@ -83,7 +83,7 @@ void IConsumableResource.Consume(float amount) public abstract class ResourceData : ResourceData, IResourceData where T : System.Enum { [System.Serializable] - private class StatRatio : SerializableDictionary { } + private class StatRatio : Map { } // Variable [SerializeField, ReadOnly] private float additiveMaxValue = 0; diff --git a/Runtime/Toolkit/RPG/StatSystem/BuffConfig.cs b/Runtime/Toolkit/RPG/StatSystem/BuffConfig.cs index 4db7bc1a..e38fca6d 100644 --- a/Runtime/Toolkit/RPG/StatSystem/BuffConfig.cs +++ b/Runtime/Toolkit/RPG/StatSystem/BuffConfig.cs @@ -8,8 +8,6 @@ public abstract class BuffConfig : ConfigAsset, IIdentifier [Header("Setting")] [SerializeField] private string configName; - // Implement IIdentifier Interface - public string NameID => configName; // Abstract Method public abstract IStatModifier[] GetModifiers(T StateName) where T : System.Enum; @@ -59,7 +57,7 @@ public sealed override IStatModifier[] GetModifiers(J StateName) int targetindex = System.Convert.ToInt32(StateName); foreach (var modif in presets) { - if (RM_Core.enume.AreEnumValuesEqual(modif.Stat, StateName)) + if (RM_Enum.AreEnumValuesEqual(modif.Stat, StateName)) { Result.Add(modif); } diff --git a/Runtime/Toolkit/RPG/StatSystem/CharacterStatComponent.cs b/Runtime/Toolkit/RPG/StatSystem/CharacterStatComponent.cs index b3acf7a7..92d8985d 100644 --- a/Runtime/Toolkit/RPG/StatSystem/CharacterStatComponent.cs +++ b/Runtime/Toolkit/RPG/StatSystem/CharacterStatComponent.cs @@ -14,7 +14,7 @@ public abstract class CharacterStat : MonoBehaviour, IPrimitiveStatContainer private BuffConfig[] DefaultBuff; - protected DataManager SaveSystem; + protected SaveManager SaveSystem; // Unity Methods @@ -31,7 +31,7 @@ private void Awake() } private void Start() { - SaveSystem = Game.FindManager(); + SaveSystem = Game.GetManager(); } private void OnEnable() { @@ -93,7 +93,7 @@ public void Save() if (SaveSystem) { Profile.StoreStats(); - SaveSystem.SaveFile(Profile.file); + SaveSystem.Save(Profile.file); } else { diff --git a/Runtime/Toolkit/RPG/StatSystem/StatData.cs b/Runtime/Toolkit/RPG/StatSystem/StatData.cs index df8c7680..55312ea0 100644 --- a/Runtime/Toolkit/RPG/StatSystem/StatData.cs +++ b/Runtime/Toolkit/RPG/StatSystem/StatData.cs @@ -53,7 +53,7 @@ public BaseStatData(float startValue, float min, float max) // Implement IStat Interface - public string NameID => GetStatName(); + public Name16 NameID => GetStatName(); public float BaseValue => baseValue.GetMergeValue(); public float Value => GetFinalValue(); public float MinValue => minValue; diff --git a/Runtime/Toolkit/RPG/StatSystem/StatProfile.cs b/Runtime/Toolkit/RPG/StatSystem/StatProfile.cs index 0f8b5c62..b8c9b1ef 100644 --- a/Runtime/Toolkit/RPG/StatSystem/StatProfile.cs +++ b/Runtime/Toolkit/RPG/StatSystem/StatProfile.cs @@ -18,7 +18,7 @@ public interface IPrimitiveStatContainer : IPrimitiveStatContainer where T : void DeclineBuff(IStatModifier modifier, T identity); IStat GetStat(T identity); } - public interface IStatStorage : IStorage + public interface IStatStorage : IFile { void StoreStats(IStat[] stat); bool TryLoadStats(StatData data); @@ -45,8 +45,7 @@ public IStat this[int index] } } - // Implement IIdentifier Interface - public string NameID => profileName; + // Implement IPrimitiveStatContainer Interface void IPrimitiveStatContainer.InitializeResource(IResourceData resource) { resource.Initialize(this); @@ -76,22 +75,22 @@ public abstract class StatProfileStorage : StatProfile { [Header("Save")] [SerializeField] - private StorageFile storage; - public SaveFile file => storage.file; + private Storage storage; + public IStatStorage file => storage.File; protected sealed override IStatStorage GetStorage() { - return storage.provider; + return storage.File; } protected sealed override bool LoadStorage() { - return storage.Load(this); + return storage.IsExist; } } public abstract class StatProfile : StatProfileStorage, IPrimitiveStatContainer where En : System.Enum where Sd : StatData { [System.Serializable] - private class GameStat : SerializableDictionary { } + private class GameStat : Map { } [Header("Definition")] [SerializeField] private GameStat ChacterStats; @@ -277,13 +276,6 @@ private void CheckStorage() } } - -#if UNITY_EDITOR - public override void OnEditorPlay() - { - Clear(); - } -#endif } } \ No newline at end of file diff --git a/Runtime/Toolkit/RPG/StatSystem/StatSaveFile.cs b/Runtime/Toolkit/RPG/StatSystem/StatSaveFile.cs index 867f38d0..9f5939f2 100644 --- a/Runtime/Toolkit/RPG/StatSystem/StatSaveFile.cs +++ b/Runtime/Toolkit/RPG/StatSystem/StatSaveFile.cs @@ -5,7 +5,7 @@ namespace RealMethod { [CreateAssetMenu(fileName = "StatSaveFile", menuName = "RealMethod/RPG/StatSaveFile", order = 1)] - public class StatSaveFile : SaveFile, IStatStorage + public class StatSaveFile : SaveFileAsset, IStatStorage { [Header("Stat")] [SerializeField, ReadOnly, TextArea] @@ -18,72 +18,58 @@ public class StatSaveFile : SaveFile, IStatStorage public List Mins = new List(5); public List Maxs = new List(5); - - protected override void OnStable(DataManager manager) - { - } + // SaveFile Methods protected override void OnSaved() { if (UsePlayerPrefs) { - RM_PlayerPrefs.SetArray("StatName", Names.ToArray()); - RM_PlayerPrefs.SetArray("StatBaseValue", BaseValue.ToArray()); - RM_PlayerPrefs.SetArray("StatMin", Mins.ToArray()); - RM_PlayerPrefs.SetArray("StatMax", Maxs.ToArray()); + RM_Save.SetArray("StatName", Names.ToArray()); + RM_Save.SetArray("StatBaseValue", BaseValue.ToArray()); + RM_Save.SetArray("StatMin", Mins.ToArray()); + RM_Save.SetArray("StatMax", Maxs.ToArray()); } } protected override void OnLoaded() { if (UsePlayerPrefs) { - Names = RM_PlayerPrefs.GetArray("StatName").ToList(); - BaseValue = RM_PlayerPrefs.GetArray("StatBaseValue").ToList(); - Mins = RM_PlayerPrefs.GetArray("StatMin").ToList(); - Maxs = RM_PlayerPrefs.GetArray("StatMax").ToList(); + Names = RM_Save.GetArray("StatName").ToList(); + BaseValue = RM_Save.GetArray("StatBaseValue").ToList(); + Mins = RM_Save.GetArray("StatMin").ToList(); + Maxs = RM_Save.GetArray("StatMax").ToList(); } } - protected override void OnDeleted() - { - if (UsePlayerPrefs) - { - Names = null; - BaseValue = null; - Mins = null; - Maxs = null; - } - } - // Implement IStorage Interface - void IStorage.StorageCreated(Object author) - { - } - void IStorage.StorageLoaded(Object author) - { - } - void IStorage.StorageClear() - { - } + // void IStorage.StorageCreated(Object author) + // { + // } + // void IStorage.StorageLoaded(Object author) + // { + // } + // void IStorage.StorageClear() + // { + // } // Implement IStatStorage Interface void IStatStorage.StoreStats(IStat[] stats) { - foreach (var stat in stats) - { - if (Names.Contains(stat.NameID)) - { - int targetindex = Names.IndexOf(stat.NameID); - BaseValue[targetindex] = stat.BaseValue; - Mins[targetindex] = stat.MinValue; - Maxs[targetindex] = stat.MaxValue; - } - else - { - Names.Add(stat.NameID); - BaseValue.Add(stat.BaseValue); - Mins.Add(stat.MinValue); - Maxs.Add(stat.MaxValue); - } - } + // foreach (var stat in stats) + // { + // if (Names.Contains(stat.NameID)) + // { + // int targetindex = Names.IndexOf(stat.NameID); + // BaseValue[targetindex] = stat.BaseValue; + // Mins[targetindex] = stat.MinValue; + // Maxs[targetindex] = stat.MaxValue; + // } + // else + // { + // Names.Add(stat.NameID); + // BaseValue.Add(stat.BaseValue); + // Mins.Add(stat.MinValue); + // Maxs.Add(stat.MaxValue); + // } + // } } bool IStatStorage.TryLoadStats(StatData data) { @@ -97,14 +83,16 @@ bool IStatStorage.TryLoadStats(StatData data) return false; } -#if UNITY_EDITOR - public override void OnEditorPlay() + + // Unity Event + protected override void Reset() { + base.Reset(); + Names.Clear(); BaseValue.Clear(); Mins.Clear(); Maxs.Clear(); } -#endif } } \ No newline at end of file diff --git a/Runtime/Toolkit/Tutorial/TutorialConfig.cs b/Runtime/Toolkit/Tutorial/TutorialConfig.cs index 93d7fed1..b42da6ea 100644 --- a/Runtime/Toolkit/Tutorial/TutorialConfig.cs +++ b/Runtime/Toolkit/Tutorial/TutorialConfig.cs @@ -33,9 +33,6 @@ public abstract class TutorialConfigCore : ConfigAsset, IItem, ITutorialSpawner private float offset; public float Offset => offset; - - // Implement IIdentifier Interface - public string NameID => label; // Implement IItem Interface public Texture2D Icon => icon; Sprite IItem.GetSpriteIcon() @@ -73,7 +70,7 @@ ITutorialMessage ITutorialSpawner.InstantiateMessage(Transform parent) protected abstract UI_TutorialUnit InstantiateMessageObject(Transform parent); #if UNITY_EDITOR - void IItem.ChangeItemName(string newLabel) + void IItem.SetItemName(string newLabel) { label = newLabel; } @@ -91,7 +88,7 @@ public class TutorialConfig : TutorialConfigCore // Implement TutorialConfigCore protected override UI_TutorialUnit InstantiateMessageObject(Transform parent) { - return Instantiate(tutorialPrefab.asset, parent).GetComponent(); + return Instantiate(tutorialPrefab, parent).GetComponent(); } #if UNITY_EDITOR diff --git a/Runtime/Toolkit/Tutorial/TutorialInterfaces.cs b/Runtime/Toolkit/Tutorial/TutorialInterfaces.cs index aed740d7..7d29e6e6 100644 --- a/Runtime/Toolkit/Tutorial/TutorialInterfaces.cs +++ b/Runtime/Toolkit/Tutorial/TutorialInterfaces.cs @@ -13,7 +13,7 @@ public interface ITutorialMessage T GetClass() where T : UI_TutorialUnit; void Initiate(Object author, IWidget owner, TutorialConfig config); } - public interface ITutorialStorage : IStorage + public interface ITutorialStorage : IFile { void AddNewTutorial(TutorialConfig conf); bool RemoveTutorial(TutorialConfig conf); diff --git a/Runtime/Toolkit/Tutorial/TutorialSaveFile.cs b/Runtime/Toolkit/Tutorial/TutorialSaveFile.cs index 793d322b..9690ffe1 100644 --- a/Runtime/Toolkit/Tutorial/TutorialSaveFile.cs +++ b/Runtime/Toolkit/Tutorial/TutorialSaveFile.cs @@ -2,10 +2,14 @@ using System.Linq; using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + namespace RealMethod { [CreateAssetMenu(fileName = "TutorialSaveFile", menuName = "RealMethod/Tutorial/SaveFile", order = 1)] - public class TutorialSaveFile : SaveFile, ITutorialStorage + public class TutorialSaveFile : SaveFileAsset, ITutorialStorage { [Header("Tutorial")] [SerializeField, ReadOnly, TextArea] @@ -16,34 +20,26 @@ public class TutorialSaveFile : SaveFile, ITutorialStorage public HashSet TutorialMessage = new HashSet(); // SaveFile Method - protected override void OnStable(DataManager manager) - { - } protected override void OnSaved() { if (UsePlayerPrefs) - RM_PlayerPrefs.SetArray("Tutorial", TutorialMessage.ToArray()); + RM_Save.SetArray("Tutorial", TutorialMessage.ToArray()); } protected override void OnLoaded() { if (UsePlayerPrefs) - TutorialMessage = RM_PlayerPrefs.GetArray("Tutorial").ToHashSet(); - } - protected override void OnDeleted() - { - if (UsePlayerPrefs) - TutorialMessage.Clear(); + TutorialMessage = RM_Save.GetArray("Tutorial").ToHashSet(); } // IMplement ITutorialStorage Interface - void IStorage.StorageCreated(Object author) - { + // void IStorage.StorageCreated(Object author) + // { - } - void IStorage.StorageLoaded(Object author) - { + // } + // void IStorage.StorageLoaded(Object author) + // { - } + // } void ITutorialStorage.AddNewTutorial(TutorialConfig conf) { TutorialMessage.Add(conf.NameID); @@ -56,15 +52,24 @@ bool ITutorialStorage.IsValidTutorial(TutorialConfig conf) { return TutorialMessage.Contains(conf.NameID); } - void IStorage.StorageClear() + // void IStorage.StorageClear() + // { + // TutorialMessage.Clear(); + // } + + + protected override void Reset() { + base.Reset(); TutorialMessage.Clear(); } #if UNITY_EDITOR - public override void OnEditorPlay() + public override bool AutoReset(PlayModeStateChange state) { - TutorialMessage.Clear(); + if (state == PlayModeStateChange.ExitingPlayMode) + return true; + return base.AutoReset(state); } #endif diff --git a/Runtime/Toolkit/Tutorial/W_Tutorial.cs b/Runtime/Toolkit/Tutorial/W_Tutorial.cs index 4cde322f..db96d10f 100644 --- a/Runtime/Toolkit/Tutorial/W_Tutorial.cs +++ b/Runtime/Toolkit/Tutorial/W_Tutorial.cs @@ -83,7 +83,7 @@ public bool ResetMessage(TutorialConfig config) } public void Clear() { - tutorialStorage.StorageClear(); + ////tutorialStorage.StorageClear(); } // Private Functions @@ -107,16 +107,16 @@ public abstract class W_TutorialStorage : W_Tutorial { [Header("Save")] [SerializeField] - private StorageFile storage; - public SaveFile file => storage.file; + private Storage storage; + public IFile file => storage.File; protected sealed override ITutorialStorage GetStorage() { - return storage.provider; + return storage.File; } protected sealed override bool LoadStorage() { - return storage.Load(this); + return storage.IsExist; } } } \ No newline at end of file diff --git a/Runtime/Toolkit/Upgrade/Sample/ChainUpgradeMapConfig.cs b/Runtime/Toolkit/Upgrade/Sample/ChainUpgradeMapConfig.cs index f15f956b..0a360916 100644 --- a/Runtime/Toolkit/Upgrade/Sample/ChainUpgradeMapConfig.cs +++ b/Runtime/Toolkit/Upgrade/Sample/ChainUpgradeMapConfig.cs @@ -70,7 +70,7 @@ public class ChainUpgradeMapConfig : UpgradeMapConfig, IChainUpgrade { [Header("Setting")] [SerializeField] - private SaveFile CoinFile; + private FileAsset CoinFile; [SerializeField] public int[] pricing; [SerializeField, ReadOnly] diff --git a/Runtime/Toolkit/Upgrade/Upgrade.cs b/Runtime/Toolkit/Upgrade/Upgrade.cs index d3e6d780..ef4a5e48 100644 --- a/Runtime/Toolkit/Upgrade/Upgrade.cs +++ b/Runtime/Toolkit/Upgrade/Upgrade.cs @@ -259,7 +259,7 @@ public void Clear() } } } - upgradeStorage.StorageClear(); + //////upgradeStorage.StorageClear(); // Create AvailableItems AvailableItems = new List(Maps.Length); foreach (var conf in Maps) @@ -320,17 +320,17 @@ public abstract class UpgradeStorage : Upgrade { [Header("Save")] [SerializeField] - private StorageFile storage; - public SaveFile file => storage.file; + private Storage storage; + public IFile file => storage.File; // override Methods protected sealed override IUpgradeStorage GetStorage() { - return storage.provider; + return storage.File; } protected sealed override bool LoadStorage() { - return storage.Load(this); + return storage.IsExist; } } diff --git a/Runtime/Toolkit/Upgrade/UpgradeInterface.cs b/Runtime/Toolkit/Upgrade/UpgradeInterface.cs index 621d30e5..3580f8ec 100644 --- a/Runtime/Toolkit/Upgrade/UpgradeInterface.cs +++ b/Runtime/Toolkit/Upgrade/UpgradeInterface.cs @@ -28,7 +28,7 @@ public interface IUpgradeConfig IUpgradeItem GetStartItem(); } - public interface IUpgradeStorage : IStorage + public interface IUpgradeStorage : IFile { void UnlockItem(IUpgradeItem item); void LockItem(IUpgradeItem item); diff --git a/Runtime/Toolkit/Upgrade/UpgradeSaveFile.cs b/Runtime/Toolkit/Upgrade/UpgradeSaveFile.cs index 37b41ec4..a70e8b9f 100644 --- a/Runtime/Toolkit/Upgrade/UpgradeSaveFile.cs +++ b/Runtime/Toolkit/Upgrade/UpgradeSaveFile.cs @@ -2,10 +2,14 @@ using System.Linq; using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + namespace RealMethod { [CreateAssetMenu(fileName = "UpgradeSaveFile", menuName = "RealMethod/Upgrade/SaveFile", order = 1)] - public class UpgradeSaveFile : SaveFile, IUpgradeStorage + public class UpgradeSaveFile : SaveFileAsset, IUpgradeStorage { [Header("Setting")] public bool UsePlayerPrefs = true; @@ -14,52 +18,40 @@ public class UpgradeSaveFile : SaveFile, IUpgradeStorage public List AvailableItems; // Base SaveFile Method - protected override void OnStable(DataManager manager) - { - } protected override void OnSaved() { if (UsePlayerPrefs) { - RM_PlayerPrefs.SetArray("UnlockItems", UnlockItems.ToArray()); - RM_PlayerPrefs.SetArray("AvailableItems", AvailableItems.ToArray()); + RM_Save.SetArray("UnlockItems", UnlockItems.ToArray()); + RM_Save.SetArray("AvailableItems", AvailableItems.ToArray()); } } protected override void OnLoaded() { if (UsePlayerPrefs) { - UnlockItems = RM_PlayerPrefs.GetArray("UnlockItems").ToList(); - AvailableItems = RM_PlayerPrefs.GetArray("AvailableItems").ToList(); + UnlockItems = RM_Save.GetArray("UnlockItems").ToList(); + AvailableItems = RM_Save.GetArray("AvailableItems").ToList(); } } - protected override void OnDeleted() - { - if (UsePlayerPrefs) - { - UnlockItems = null; - AvailableItems = null; - } - - } // Implement IUpgradeStorage Interface - void IStorage.StorageCreated(Object author) - { - if (author is Upgrade upgrator) - { - UnlockItems = new List(upgrator.ItemCount); - AvailableItems = new List(); - } - else - { - Debug.LogWarning($"{this} Storage Should create by Upgrade Class"); - } - } - void IStorage.StorageLoaded(Object author) - { - } + // void IStorage.StorageCreated(Object author) + // { + // if (author is Upgrade upgrator) + // { + // UnlockItems = new List(upgrator.ItemCount); + // AvailableItems = new List(); + // } + // else + // { + // Debug.LogWarning($"{this} Storage Should create by Upgrade Class"); + // } + // } + // void IStorage.StorageLoaded(Object author) + // { + // } void IUpgradeStorage.UnlockItem(IUpgradeItem item) { UnlockItems.Add(item.Label); @@ -84,20 +76,28 @@ string[] IUpgradeStorage.GetUnlockItems() { return UnlockItems.ToArray(); } - void IStorage.StorageClear() + // void IStorage.StorageClear() + // { + // if (UnlockItems != null) + // UnlockItems.Clear(); + // if (UnlockItems != null) + // AvailableItems.Clear(); + // } + + + protected override void Reset() { - if (UnlockItems != null) - UnlockItems.Clear(); - if (UnlockItems != null) - AvailableItems.Clear(); + base.Reset(); + //((IFile)this).StorageClear(); } #if UNITY_EDITOR - public override void OnEditorPlay() + public override bool AutoReset(PlayModeStateChange state) { - //base.OnEditorPlay(); - ((IStorage)this).StorageClear(); + if (state == PlayModeStateChange.ExitingPlayMode) + return true; + return base.AutoReset(state); } #endif diff --git a/Tests/Editor.meta b/Tests/Editor.meta new file mode 100644 index 00000000..6882fdf9 --- /dev/null +++ b/Tests/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 09bd7b0e521680449aa84200b0bd469c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/Editor/DelegateDisplayEditor.cs b/Tests/Editor/DelegateDisplayEditor.cs new file mode 100644 index 00000000..23232605 --- /dev/null +++ b/Tests/Editor/DelegateDisplayEditor.cs @@ -0,0 +1,64 @@ +using System; +using UnityEditor; +using UnityEngine; +using System.Reflection; + +namespace RealMethod +{ + // [CustomEditor(typeof(MonoBehaviour), true)] + // public class DelegateDisplayEditor : UnityEditor.Editor + // { + // public override void OnInspectorGUI() + // { + // base.OnInspectorGUI(); + + // MonoBehaviour targetMono = (MonoBehaviour)target; + // Type type = targetMono.GetType(); + + // BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + // var fields = type.GetFields(flags); + + // EditorGUILayout.Space(); + // EditorGUILayout.LabelField("Assigned Delegates", EditorStyles.boldLabel); + + // bool anyShown = false; + + // foreach (var field in fields) + // { + // // Check if it's a delegate or derived from MulticastDelegate (includes Action, Func, etc.) + // if (typeof(MulticastDelegate).IsAssignableFrom(field.FieldType.BaseType)) + // { + // var del = field.GetValue(targetMono) as Delegate; + + // if (del != null) + // { + // Delegate[] invocationList = del.GetInvocationList(); + + // foreach (var d in invocationList) + // { + // string methodName = d.Method?.Name ?? ""; + // string targetName = d.Target?.GetType().Name ?? ""; + + // EditorGUILayout.LabelField($"{field.Name}", $"{methodName} ({targetName})"); + // } + // } + // else + // { + // EditorGUILayout.LabelField($"{field.Name}", ""); + // } + + // anyShown = true; + // } + // } + + // if (!anyShown) + // { + // EditorGUILayout.LabelField("No delegates found."); + // } + + // Debug.Log("sdsdsd"); + // } + + + // } +} \ No newline at end of file diff --git a/Tests/Inspector/DelegateDisplayEditor.cs.meta b/Tests/Editor/DelegateDisplayEditor.cs.meta similarity index 100% rename from Tests/Inspector/DelegateDisplayEditor.cs.meta rename to Tests/Editor/DelegateDisplayEditor.cs.meta diff --git a/Tests/Events.cs b/Tests/Events.cs new file mode 100644 index 00000000..59820551 --- /dev/null +++ b/Tests/Events.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; + +public enum GameEvent +{ + Spawn, + Despawn, + Die, + TakeDamage, + Heal, + Attach, + Detach, + Share, + Reset +} + + +public static class EventBus +{ + private static readonly Dictionary> _eventMap = + new Dictionary>(); + + public static void Subscribe(string eventName, Action callback) + { + if (!_eventMap.ContainsKey(eventName)) + _eventMap[eventName] = delegate { }; + + _eventMap[eventName] += callback; + } + + public static void Unsubscribe(string eventName, Action callback) + { + if (_eventMap.ContainsKey(eventName)) + _eventMap[eventName] -= callback; + } + + public static void Raise(string eventName, object payload = null) + { + if (_eventMap.TryGetValue(eventName, out var callbacks)) + callbacks?.Invoke(payload); + } + + public static void Raise(GameEvent ev, object payload = null) + => Raise(ev.ToName(), payload); +} + +// EventBus.Subscribe(GameEvent.Spawn.ToName(), OnSpawn); +// private void OnSpawn(object payload) +// { +// // Handle your event +// } +// EventBus.Raise(GameEvent.Spawn); +// EventBus.Raise(GameEvent.TakeDamage, new DamageInfo { amount = 20 }); + + +public static class GameEventExtensions +{ + public static string ToName(this GameEvent ev) + { + return ev.ToString(); + } +} + +public static class TypedEventBus +{ + private static event Action OnEvent; + + public static void Subscribe(Action callback) => OnEvent += callback; + public static void Unsubscribe(Action callback) => OnEvent -= callback; + + public static void Raise(T payload) => OnEvent?.Invoke(payload); +} + +// TypedEventBus.Subscribe(OnDamage); +// TypedEventBus.Raise(new DamageInfo(25)); + diff --git a/Tests/Events.cs.meta b/Tests/Events.cs.meta new file mode 100644 index 00000000..60c53350 --- /dev/null +++ b/Tests/Events.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 354ebf6331ef0354c9b72e315428bcfa \ No newline at end of file diff --git a/Tests/FileManager.cs b/Tests/FileManager.cs new file mode 100644 index 00000000..ee23a1a9 --- /dev/null +++ b/Tests/FileManager.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; + +namespace RealMethod +{ + public abstract class FileManager : MonoBehaviour, IGameManager + { + protected class FileData + { + public FieldInfo[] Fields { get; private set; } + public PropertyInfo[] Properties { get; private set; } + + public FileData(object Instance, BindingFlags flags) + { + System.Type type = Instance.GetType(); + Fields = type.GetFields(flags); + Properties = type.GetProperties(flags); + } + } + protected Dictionary FileList = new Dictionary(); + + public event System.Action OnFileAdded; + public event System.Action OnFileRemoved; + + // Implement IGameManager Interface + public virtual void InitiateManager(Scope owner) + { + + } + + // Functions + public bool AddFile(IFile file) + { + if (!FileList.ContainsKey(file)) + { + if (CanAddFile(file)) + { + FileList.Add(file, CreateFileData(file)); + OnFileAdded?.Invoke(file); + return true; + } + else + { + Debug.LogWarning($"Can't Add file with name: {file.FileName}"); + return false; + } + } + else + { + Debug.LogWarning($"There is a file with this name: {file.FileName}"); + return false; + } + } + public bool RemoveFile(IFile file) + { + if (FileList.ContainsKey(file)) + { + FileList.Remove(file); + OnFileRemoved?.Invoke(file); + return true; + } + else + { + Debug.LogWarning($"Can't find any file with this name: {file.FileName}"); + return false; + } + } + public bool IsValidFile(IFile file) + { + return FileList.ContainsKey(file); + } + protected T GetFileData(IFile file) where T : FileData + { + return (T)FileList[file]; + } + + // Methods + protected virtual BindingFlags GetFlagSetting() + { + return BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + } + protected virtual FileData CreateFileData(IFile file) + { + return new FileData(file.Self, GetFlagSetting()); + } + + // Abstraction Methods + protected abstract bool CanAddFile(IFile file); + } + + // public abstract class FileManager : FileManager where T : FileAsset + // { + // [Header("Files")] + // [SerializeField] + // private T[] Files; + + + // // IGameManager + // public override void InitiateManager(bool AlwaysLoaded) + // { + // base.InitiateManager(AlwaysLoaded); + // foreach (var file in Files) + // { + // AddFile(file); + // } + // Files = null; + // } + // } +} \ No newline at end of file diff --git a/Tests/FileManager.cs.meta b/Tests/FileManager.cs.meta new file mode 100644 index 00000000..61e8aa7b --- /dev/null +++ b/Tests/FileManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3a9a003a670dfa440ac2138c4913af6a \ No newline at end of file diff --git a/Tests/General/AIManager.cs b/Tests/General/AIManager.cs index fa577c72..075c948b 100644 --- a/Tests/General/AIManager.cs +++ b/Tests/General/AIManager.cs @@ -45,9 +45,9 @@ public MonoBehaviour GetManagerClass() { return this; } - public void InitiateManager(bool AlwaysLoaded) + public void InitiateManager(Scope owner) { - if (AlwaysLoaded) return; + if (owner.IsGameScope()) return; // MyWorld = GetComponent(); // if (MyWorld == null) Debug.LogError("AIDirector Couldn't Find World."); @@ -56,10 +56,6 @@ public void InitiateManager(bool AlwaysLoaded) // MyWorld.OnGameBegin += OnGameStarted; } - public void ResolveService(Service service, bool active) - { - throw new System.NotImplementedException(); - } // #endregion diff --git a/Tests/General/EnvironmentManager.cs b/Tests/General/EnvironmentManager.cs index 5e21f4c2..19808108 100644 --- a/Tests/General/EnvironmentManager.cs +++ b/Tests/General/EnvironmentManager.cs @@ -33,16 +33,11 @@ public MonoBehaviour GetManagerClass() } // Initializes the manager and subscribes to the difficulty change event - public void InitiateManager(bool AlwaysLoaded) + public void InitiateManager(Scope owner) { //CCGame.CastWorld().OndifficultyChange += OnPlayerLevelChanged; } - // Placeholder for initiating services, currently does nothing - public void ResolveService(Service service, bool active) - { - } - #endregion // Event handler for player level change diff --git a/Tests/General/LevelManager.cs b/Tests/General/LevelManager.cs index be47b59f..95ecbfee 100644 --- a/Tests/General/LevelManager.cs +++ b/Tests/General/LevelManager.cs @@ -34,7 +34,7 @@ public MonoBehaviour GetManagerClass() { return this; } - public void InitiateManager(bool AlwaysLoaded) + public void InitiateManager(Scope owner) { // if (!LG) // { @@ -53,11 +53,6 @@ public void InitiateManager(bool AlwaysLoaded) StartCoroutine(OnPlayerLocationChange()); } - public void ResolveService(Service service, bool active) - { - throw new System.NotImplementedException(); - } - private void OnEnable() { diff --git a/Tests/General/MissionManager.cs b/Tests/General/MissionManager.cs index 7871e393..873a7a3e 100644 --- a/Tests/General/MissionManager.cs +++ b/Tests/General/MissionManager.cs @@ -1,4 +1,3 @@ -using System.Collections; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; @@ -24,7 +23,7 @@ public abstract class MissionManager : MonoBehaviour, IGameManager public GameObject UI; public Animator playerStatusAnimator; public GameObject MissionPassUI; - public SceneReference HomeScene; + public SceneAsset HomeScene; [Header("Events")] public UnityEvent OnMissionCompleted; @@ -34,8 +33,6 @@ public abstract class MissionManager : MonoBehaviour, IGameManager //private PlayerEnergy playerenargy; // private Rigidbody body; private int currentObstacleCount = 0; - // private bool IsMissionComplited = false; - private DataManager dataManager; private Text GoalRecord; private Text GoalTitle; private Button NextLevel; @@ -48,14 +45,14 @@ public MonoBehaviour GetManagerClass() { return this; } - public void InitiateManager(bool AlwaysLoaded) + public void InitiateManager(Scope owner) { //MyWorld = Game.CastWorld(); //GameObject PlayerObject = MyWorld.GetPlayerObject(); //playercontroller = PlayerObject.GetComponent(); //playerenargy = PlayerObject.GetComponent(); //body = PlayerObject.GetComponent(); - dataManager = Game.Instance.GetComponent(); + //dataManager = Game.Instance.GetComponent(); GoalRecord = UI.GetComponentsInChildren()[1]; GoalTitle = UI.GetComponentsInChildren()[0]; GoalRecord.text = $"{currentObstacleCount}/{ObstacleCount}"; @@ -65,9 +62,6 @@ public void InitiateManager(bool AlwaysLoaded) //if (GameData.GetMissionsLength() == MissionID) //NextLevel.gameObject.SetActive(false); } - public void ResolveService(Service service, bool active) - { - } diff --git a/Tests/General/SpawnManager.cs b/Tests/General/SpawnManager.cs index 4da961bf..2154a23e 100644 --- a/Tests/General/SpawnManager.cs +++ b/Tests/General/SpawnManager.cs @@ -46,20 +46,11 @@ public void StopManager() throw new System.NotImplementedException(); } - public MonoBehaviour GetManagerClass() - { - return this; - } - public void InitiateManager(bool AlwaysLoaded) - { - throw new System.NotImplementedException(); - } - public void ResolveService(Service service, bool active) + + public void InitiateManager(Scope owner) { throw new System.NotImplementedException(); } - - } } diff --git a/Tests/General/TutorialManager.cs b/Tests/General/TutorialManager.cs index 1e1b6030..a2ddc184 100644 --- a/Tests/General/TutorialManager.cs +++ b/Tests/General/TutorialManager.cs @@ -51,7 +51,7 @@ public MonoBehaviour GetManagerClass() { return this; } - public void InitiateManager(bool AlwaysLoaded) + public void InitiateManager(Scope owner) { // if (Savefile == null) // { @@ -72,10 +72,6 @@ public void InitiateManager(bool AlwaysLoaded) // Destroy(this); // } } - public void ResolveService(Service service, bool active) - { - } - // Private Methods private void BeginTutorial() @@ -224,7 +220,7 @@ private void OnPlayerMassChanged(float mass) // aIManager.SetEnemySpawnEnabled(true); // ResetPlayer(); // Savefile.FirstPlay = true; - // Game.Instance.GetComponent().SaveFile(); + // Game.Instance.GetComponent().SaveFile(); // Destroy(this); // } diff --git a/Tests/Inspector/DelegateDisplayEditor.cs b/Tests/Inspector/DelegateDisplayEditor.cs deleted file mode 100644 index 91e53591..00000000 --- a/Tests/Inspector/DelegateDisplayEditor.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using UnityEditor; -using UnityEngine; -using System.Reflection; - -namespace RealMethod -{ - [CustomEditor(typeof(MonoBehaviour), true)] - public class DelegateDisplayEditor : UnityEditor.Editor - { - public override void OnInspectorGUI() - { - base.OnInspectorGUI(); - - MonoBehaviour targetMono = (MonoBehaviour)target; - Type type = targetMono.GetType(); - - BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - var fields = type.GetFields(flags); - - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Assigned Delegates", EditorStyles.boldLabel); - - bool anyShown = false; - - foreach (var field in fields) - { - // Check if it's a delegate or derived from MulticastDelegate (includes Action, Func, etc.) - if (typeof(MulticastDelegate).IsAssignableFrom(field.FieldType.BaseType)) - { - var del = field.GetValue(targetMono) as Delegate; - - if (del != null) - { - Delegate[] invocationList = del.GetInvocationList(); - - foreach (var d in invocationList) - { - string methodName = d.Method?.Name ?? ""; - string targetName = d.Target?.GetType().Name ?? ""; - - EditorGUILayout.LabelField($"{field.Name}", $"{methodName} ({targetName})"); - } - } - else - { - EditorGUILayout.LabelField($"{field.Name}", ""); - } - - anyShown = true; - } - } - - if (!anyShown) - { - EditorGUILayout.LabelField("No delegates found."); - } - - Debug.Log("sdsdsd"); - } - - - } -} \ No newline at end of file diff --git a/Tests/MissionManager.cs b/Tests/MissionManager.cs new file mode 100644 index 00000000..557c5583 --- /dev/null +++ b/Tests/MissionManager.cs @@ -0,0 +1,49 @@ +using System; +using UnityEngine; + +namespace RealMethod +{ + /// + /// Represents the possible outcomes of a Game process. + /// + public enum GameProcess + { + /// + /// The process finished successfully. + /// + Success, + /// + /// The process failed. + /// + Failure, + /// + /// The process was cancelled before completion. + /// + Cancelled + } + + public class MissionManager2 : MonoBehaviour, IGameManager + { + /// + /// Invoked when the process finishes. + /// Process in your game take define with yourelf. + /// (for example: show win screen, game over UI, load next level, etc). + /// + public static event Action OnCompleted; + + public void InitiateManager(Scope owner) + { + throw new System.NotImplementedException(); + } + + /// + /// Attempts to invoke + /// + public void Complete(GameProcess result) + { + OnCompleted.Invoke(result); + } + + + } +} \ No newline at end of file diff --git a/Tests/MissionManager.cs.meta b/Tests/MissionManager.cs.meta new file mode 100644 index 00000000..201eff8d --- /dev/null +++ b/Tests/MissionManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6af078be0e3f22740a33816d1826bc98 \ No newline at end of file diff --git a/Tests/TrashService.cs b/Tests/TrashService.cs new file mode 100644 index 00000000..f43ec2dd --- /dev/null +++ b/Tests/TrashService.cs @@ -0,0 +1,205 @@ + + + + + + + +/// +/// List of runtime-registered instances owned by the game. +/// +// private readonly Dictionary Services = new(); + +/// +/// Returns true if the Game system has one or more registered services; +/// otherwise, returns false. +/// +// public static bool HasService => Instance.Services.Count > 0; + + + + + + + +/// +/// Registers a service instance of type in the service container. +/// +/// +/// The type of the service to register. Must implement . +/// +/// +/// The service instance to register. +/// +/// +/// Optional object providing context or ownership information for the registration. +/// Passed to . +/// +/// +/// true if the service was successfully registered; +/// false if a service of the same type is already registered. +/// +/// +/// This method prevents duplicate registrations. If a service of the same type +/// is already registered, an error is logged and the method returns false. +/// Upon successful registration, is invoked. +/// +// public static bool Register(T service, object author = null) where T : IService +// { +// Type TypeService = typeof(T); + +// if (Instance.Services.ContainsKey(TypeService)) +// { +// Debug.LogError($"IService {TypeService} already registered."); +// return false; +// } + +// service.OnRegister(author); +// Instance.Services[TypeService] = service; +// return true; + +// } +/// +/// Checks whether a service of type is currently registered +/// in the Service Locator. +/// +/// +/// The type of service to check. The type must implement . +/// +/// +/// true if a service of type is registered; otherwise false. +/// +// public static bool IsRegistered() where T : IService +// { +// return Instance.Services.ContainsKey(typeof(T)); +// } +/// +/// Remove service instance +/// +/// The object type that implement 'IService' +// public static bool Unregister(object author = null) where T : IService +// { +// Type TypeService = typeof(T); + +// if (Instance.Services.ContainsKey(TypeService)) +// { +// Instance.Services[TypeService].OnUnregister(author); +// return Instance.Services.Remove(TypeService); ; +// } +// else +// { +// Debug.LogWarning($"IService {TypeService} Not found."); +// return false; +// } +// } +/// +/// Retrieves the service instance of type if available. +/// +/// IService type to retrieve. +/// The service instance of type , or null if not found. +// public static T GetService() where T : IService +// { +// Type TypeService = typeof(T); + +// if (Instance.Services.TryGetValue(TypeService, out var provider)) +// return (T)provider.Self; + +// throw new Exception($"Service {TypeService} not registered."); +// } +/// +/// Attempts to find a service of type . +/// +/// IService type to find. +/// Out parameter that receives the service if found. +/// true if the service was found; otherwise false. +// public static bool TryGetService(out T service) where T : IService +// { +// if (Instance.Services.TryGetValue(typeof(T), out var provider)) +// { +// service = (T)provider.Self; +// return true; +// } + +// service = default; +// return false; +// } +/// +/// Clear all services in Game +/// +// public static void ClearService() +// { +// foreach (var service in Instance.Services.Values) +// { +// service.OnUnregister(null); +// } +// Instance.Services.Clear(); +// } + + + +// private void Notify_OnWorldInitiate(World NewWorld) +// { +// foreach (var service in Services) +// { +// service.Value.OnWorldChanging(World, NewWorld); +// } +// World = NewWorld; +// OnWorldChanged(World); +// } + + + + + + + + + + + + +/// +/// Base abstract class implementing . +/// Provides a framework for derived services to handle lifecycle events. +/// +// public abstract class Service : IService +// { +// // Implement IService Interface +// /// +// /// Called when the service starts. Must be implemented by derived classes. +// /// +// /// The object responsible for creating the service. +// public abstract void OnRegister(object author); +// /// +// /// Called when a new world or environment is initialized. +// /// Must be implemented by derived classes. +// /// +// public abstract void OnWorldChanging(World Previous, World New); +// /// +// /// Called when the service ends or is deleted. +// /// Must be implemented by derived classes. +// /// +// /// The object responsible for deleting the service. +// public abstract void OnUnregister(object author); +// #if UNITY_EDITOR +// string IService.GetInspectorInfo() +// { +// return GetDisplayInfo(); +// } +// protected virtual string GetDisplayInfo() +// { +// return GetType().ToString() + ": "; +// } +// #endif + +// } + + + +/// + /// Returns the object instance that implements this service. + /// + // object Self => this; + + + diff --git a/Tests/TrashService.cs.meta b/Tests/TrashService.cs.meta new file mode 100644 index 00000000..8bf822d0 --- /dev/null +++ b/Tests/TrashService.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f38c2ceee0a62d040a2db048084faf4c \ No newline at end of file