├── Runtime ├── GUnity.GUA.asmdef ├── State │ ├── StateValue.cs.meta │ ├── GState.cs.meta │ ├── StateValue.cs │ └── GState.cs ├── Event │ ├── EventStruct.cs.meta │ ├── GEventPool.cs.meta │ ├── GEventPool.cs │ └── EventStruct.cs ├── System │ ├── MonoSystem.cs.meta │ ├── GSystem.cs.meta │ ├── GSystem.cs │ └── MonoSystem.cs ├── Extension │ ├── UnityEventExtension.cs.meta │ ├── ButtonClickedEventExtension.cs.meta │ ├── Singleton.cs.meta │ ├── UnityEventExtension.cs │ ├── ButtonClickedEventExtension.cs │ └── Singleton.cs ├── Data.meta ├── Event.meta ├── Invoke.meta ├── State.meta ├── System.meta ├── Extension.meta ├── GUnity.GUA.asmdef.meta ├── Data │ ├── GDataPool.cs.meta │ └── GDataPool.cs └── Invoke │ ├── GInvoke.cs.meta │ └── GInvoke.cs ├── Content ├── package_manager.gif └── package_manager.gif.meta ├── LICENSE.md.meta ├── README.md.meta ├── package.json.meta ├── Editor ├── Starter.cs.txt.meta ├── StarterEditor.cs.txt.meta ├── GUnity.GUA.Editor.asmdef.meta ├── CreatorWindow.cs.meta ├── GUnity.GUA.Editor.asmdef ├── StarterEditor.cs.txt ├── Starter.cs.txt └── CreatorWindow.cs ├── Content.meta ├── Editor.meta ├── Runtime.meta ├── package.json ├── LICENSE.md ├── .gitignore └── README.md /Runtime/GUnity.GUA.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GUnity.GUA" 3 | } 4 | -------------------------------------------------------------------------------- /Content/package_manager.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gunity/GUA/HEAD/Content/package_manager.gif -------------------------------------------------------------------------------- /Runtime/State/StateValue.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1049ec08becb4690ac96b655d7d7c9b0 3 | timeCreated: 1628337505 -------------------------------------------------------------------------------- /Runtime/Event/EventStruct.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6eddc67a4c25445ca6e97479be894028 3 | timeCreated: 1628167935 -------------------------------------------------------------------------------- /Runtime/System/MonoSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cab4129307114f6185965e54ec3bb88b 3 | timeCreated: 1628161545 -------------------------------------------------------------------------------- /Runtime/Extension/UnityEventExtension.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c2e4f7cd09544acb937710feb6df29bc 3 | timeCreated: 1628942356 -------------------------------------------------------------------------------- /Runtime/Extension/ButtonClickedEventExtension.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bc01b55b73994debb0ce1b473c164b1d 3 | timeCreated: 1628941820 -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b485cdde2f49c4d6b857de4fe1030616 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 069763136182c494fba143f824494771 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8a6b5a8aea2784547a8517c4eb67d826 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/Starter.cs.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a09cd8cf312349ec8e7f10d65306feb 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Content.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b47acc680a9491d4ab1d3a8c6b1d005f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e219bd0089b9846acb7198617c10d7d0 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/StarterEditor.cs.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 40ee83ee3e88b4f098938d7cde92a019 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d9414222f28c34158bc39b74c3792999 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Data.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c1336dd070f8d4e3784d6948f7624a10 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Event.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 14b1211fa3b724fb8bcb502c1001d77c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Invoke.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5f6af766916b14909bd463c636383754 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/State.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ee3c8677c8042e3409d6bd4f5ef00bfa 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/System.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8840e636ea1344ee699c2732e24551b1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Extension.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2f13030f848c1444fa3c4a9b48ac4c92 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/GUnity.GUA.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e0ea345c19a8f49c6bc63d75aeae8b98 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/GUnity.GUA.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 54f511dc16af64b6ca952aede8a936f3 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/CreatorWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2513dcc88cef340028440b5c7f5bcb45 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/State/GState.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6c824de07b262c44c8bd24fb430c5382 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Data/GDataPool.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dc7287751cd1e4158b2c9287a9179e65 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Event/GEventPool.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 255477263a95e47f0bfab78bfb8657fa 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Invoke/GInvoke.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: be860451fe59549d09b42b76cbdb6980 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/System/GSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e3c8d1cdf51884667b261ad094b4b8b7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Extension/Singleton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 05b987a52f333417c9bb8235ccaa2a20 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.gunity.gua", 3 | "version": "2.1.3", 4 | "displayName": "GUnityArchitecture", 5 | "description": "A simple architecture that is designed to use some of the programming patterns.", 6 | "author": { 7 | "name": "GUnity", 8 | "telegram": "http://t.me/gunity_dev", 9 | "github": "https://github.com/gunity" 10 | } 11 | } -------------------------------------------------------------------------------- /Runtime/Extension/UnityEventExtension.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.Events; 2 | 3 | namespace GUA.Extension 4 | { 5 | public static class UnityEventExtension 6 | { 7 | public static void SetListener(this UnityEvent unityEvent, UnityAction action) 8 | { 9 | unityEvent.RemoveAllListeners(); 10 | unityEvent.AddListener(action); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Runtime/Extension/ButtonClickedEventExtension.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.Events; 2 | using UnityEngine.UI; 3 | 4 | namespace GUA.Extension 5 | { 6 | public static class ButtonClickedEventExtension 7 | { 8 | public static void SetListener(this Button.ButtonClickedEvent unityEvent, UnityAction action) 9 | { 10 | unityEvent.RemoveAllListeners(); 11 | unityEvent.AddListener(action); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Editor/GUnity.GUA.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GUnity.GUA.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:31438d7adbbd846d280ef7b8573c0412", 6 | "GUID:e0ea345c19a8f49c6bc63d75aeae8b98" 7 | ], 8 | "includePlatforms": [ 9 | "Editor" 10 | ], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": false, 13 | "overrideReferences": false, 14 | "precompiledReferences": [], 15 | "autoReferenced": true, 16 | "defineConstraints": [], 17 | "versionDefines": [], 18 | "noEngineReferences": false 19 | } -------------------------------------------------------------------------------- /Runtime/Extension/Singleton.cs: -------------------------------------------------------------------------------- 1 | namespace GUA.Extension 2 | { 3 | public abstract class Singleton where T : class, new() 4 | { 5 | private static T _instance; 6 | 7 | public static T Instance 8 | { 9 | get 10 | { 11 | if (_instance != null) return _instance; 12 | _instance = new T(); 13 | return _instance; 14 | } 15 | } 16 | 17 | protected virtual void Awake() 18 | { 19 | _instance = this as T; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Runtime/Invoke/GInvoke.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using UnityEngine.Events; 4 | 5 | namespace GUA.Invoke 6 | { 7 | public class GInvoke 8 | { 9 | private CancellationTokenSource _cancellationTokenSource; 10 | 11 | public async void Delay(UnityAction unityAction, int milliseconds) 12 | { 13 | _cancellationTokenSource = new CancellationTokenSource(); 14 | try 15 | { 16 | await Task.Delay(milliseconds, _cancellationTokenSource.Token); 17 | } 18 | catch 19 | { 20 | return; 21 | } 22 | unityAction.Invoke(); 23 | } 24 | 25 | public void Stop() 26 | { 27 | _cancellationTokenSource.Cancel(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Editor/StarterEditor.cs.txt: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | using #STARTER_NAMESPACE#; 4 | 5 | namespace #NAMESPACE# 6 | { 7 | [CustomEditor(typeof(#STARTER_NAME#))] 8 | public class #SCRIPT_NAME# : UnityEditor.Editor 9 | { 10 | private #STARTER_NAME# _target; 11 | 12 | public override void OnInspectorGUI() 13 | { 14 | base.OnInspectorGUI(); 15 | 16 | _target = target as #STARTER_NAME#; 17 | if(_target == null) return; 18 | 19 | GUILayout.Space(20); 20 | 21 | if (GUILayout.Button("Reset all saved data", GUILayout.Height(30))) 22 | { 23 | PlayerPrefs.DeleteAll(); 24 | Debug.Log("All saved data has been discarded."); 25 | } 26 | 27 | // Some functional 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Runtime/System/GSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using GUA.Data; 3 | using GUA.Event; 4 | 5 | namespace GUA.System 6 | { 7 | public sealed class GSystem 8 | { 9 | private readonly List _systems = new List(); 10 | 11 | public void Add(MonoSystem system) 12 | { 13 | _systems.Add(system); 14 | } 15 | 16 | public void Run() 17 | { 18 | _systems.ForEach(system => 19 | { 20 | if (system.Enabled) system.Run(); 21 | }); 22 | } 23 | 24 | public void FixedRun() 25 | { 26 | _systems.ForEach(system => 27 | { 28 | if (system.Enabled) system.FixedRun(); 29 | }); 30 | } 31 | 32 | public static void ClearSystem() 33 | { 34 | GDataPool.Clear(); 35 | GEventPool.Clear(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Runtime/Data/GDataPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace GUA.Data 5 | { 6 | public static class GDataPool 7 | { 8 | private static readonly Dictionary Data = new Dictionary(); 9 | 10 | public static void Set(object data) 11 | { 12 | #if UNITY_EDITOR 13 | if (Data.ContainsKey(data.GetType())) 14 | { 15 | throw new Exception($"GDataPool: {data.GetType()} type has already been added"); 16 | } 17 | #endif 18 | Data.Add(data.GetType(), data); 19 | } 20 | 21 | public static T Get() 22 | { 23 | #if UNITY_EDITOR 24 | if (!Data.ContainsKey(typeof(T))) 25 | { 26 | throw new Exception($"GDataPool: {typeof(T)} type has not been added"); 27 | } 28 | #endif 29 | return (T) Data[typeof(T)]; 30 | } 31 | 32 | public static void Clear() 33 | { 34 | Data.Clear(); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /Editor/Starter.cs.txt: -------------------------------------------------------------------------------- 1 | using GUA.System; 2 | using UnityEngine; 3 | 4 | namespace #NAMESPACE# 5 | { 6 | public class #SCRIPT_NAME# : MonoBehaviour 7 | { 8 | private readonly GSystem _system = new GSystem(); 9 | 10 | // [Header("Emitters")] 11 | // [SerializeField] private SomeEmitter someEmitter; 12 | 13 | // [Header("Data")] 14 | // [SerializeField] private SomeData someData; 15 | 16 | private void Start() 17 | { 18 | Application.targetFrameRate = 60; 19 | InitializeAssistants(); 20 | 21 | // GDataPool.Set(someEmitter); 22 | 23 | // GDataPool.Set(someData); 24 | 25 | // _system.Add(new SomeSystem()); 26 | } 27 | 28 | private void InitializeAssistants() 29 | { 30 | // initialize assistance 31 | } 32 | 33 | private void Update() => _system.Run(); 34 | 35 | private void FixedUpdate() => _system.FixedRun(); 36 | 37 | private void OnApplicationQuit() => GSystem.ClearSystem(); 38 | 39 | private void OnDestroy() => GSystem.ClearSystem(); 40 | } 41 | } -------------------------------------------------------------------------------- /Runtime/System/MonoSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using UnityEngine; 3 | 4 | namespace GUA.System 5 | { 6 | public abstract class MonoSystem 7 | { 8 | public bool Enabled 9 | { 10 | get => _enabled; 11 | protected set 12 | { 13 | _enabled = value; 14 | Startup(); 15 | } 16 | } 17 | 18 | private bool _enabled; 19 | private bool _initialized; 20 | 21 | protected MonoSystem(bool enabled) 22 | { 23 | Enabled = enabled; 24 | } 25 | 26 | private async void Startup() 27 | { 28 | await Task.Yield(); 29 | 30 | if (!Enabled) return; 31 | if (_initialized) return; 32 | 33 | _initialized = true; 34 | Start(); 35 | } 36 | 37 | protected virtual void Start() 38 | { 39 | // nothing 40 | } 41 | 42 | public virtual void Run() 43 | { 44 | // nothing 45 | } 46 | 47 | public virtual void FixedRun() 48 | { 49 | // nothing 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Never ignore Asset meta data 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # TextMesh Pro files 20 | [Aa]ssets/TextMesh*Pro/ 21 | 22 | # Autogenerated Jetbrains Rider plugin 23 | [Aa]ssets/Plugins/Editor/JetBrains* 24 | 25 | # Visual Studio cache directory 26 | .vs/ 27 | 28 | # Gradle cache directory 29 | .gradle/ 30 | 31 | # Autogenerated VS/MD/Consulo solution and project files 32 | ExportedObj/ 33 | .consulo/ 34 | *.csproj 35 | *.unityproj 36 | *.sln 37 | *.suo 38 | *.tmp 39 | *.user 40 | *.userprefs 41 | *.pidb 42 | *.booproj 43 | *.svd 44 | *.pdb 45 | *.mdb 46 | *.opendb 47 | *.VC.db 48 | 49 | # Unity3D generated meta files 50 | *.pidb.meta 51 | *.pdb.meta 52 | *.mdb.meta 53 | 54 | # Unity3D generated file on crash reports 55 | sysinfo.txt 56 | 57 | # Builds 58 | *.apk 59 | *.unitypackage 60 | 61 | # Crashlytics generated file 62 | crashlytics-build.properties 63 | 64 | 65 | .DS_Store 66 | -------------------------------------------------------------------------------- /Runtime/State/StateValue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace GUA.State 5 | { 6 | public class StateValue 7 | { 8 | public Enum StateType 9 | { 10 | get => _stateType; 11 | set 12 | { 13 | _stateType = value; 14 | RefreshExecutableObject(); 15 | } 16 | } 17 | 18 | public object ExecutableObject; 19 | 20 | private Enum _stateType; 21 | private readonly object _mainExecutableObject; 22 | private readonly Dictionary _states; 23 | 24 | public StateValue(Enum stateType, object mainExecutableObject) 25 | { 26 | _states = new Dictionary(); 27 | ExecutableObject = mainExecutableObject; 28 | _mainExecutableObject = mainExecutableObject; 29 | StateType = stateType; 30 | } 31 | 32 | public void RegisterState(Enum state, object executableObject) 33 | { 34 | _states.Add(state, executableObject); 35 | RefreshExecutableObject(); 36 | } 37 | 38 | private void RefreshExecutableObject() 39 | { 40 | ExecutableObject = _states.ContainsKey(_stateType) 41 | ? _states[_stateType] 42 | : _mainExecutableObject; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Runtime/Event/GEventPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace GUA.Event 6 | { 7 | public static class GEventPool 8 | { 9 | private static readonly List GEvents = new List(); 10 | 11 | public static void SendMessage(T gEvent) where T : struct 12 | { 13 | var any = GEvents.Any(e => 14 | { 15 | if (e.EventType != gEvent.GetType()) return false; 16 | if (!e.HasObject) e.SetObject(gEvent); 17 | e.Invoke(); 18 | return true; 19 | }); 20 | 21 | if (any) return; 22 | GEvents.Add(new EventStruct(gEvent)); 23 | } 24 | 25 | public static void AddListener(Action uEventMethod) 26 | { 27 | var any = GEvents.Any(e => 28 | { 29 | if (e.EventType != typeof(T)) return false; 30 | e.AddAction(t => uEventMethod((T) t)); 31 | return true; 32 | }); 33 | 34 | if (any) return; 35 | var eventStruct = new EventStruct(typeof(T), t => uEventMethod((T) t)); 36 | GEvents.Add(eventStruct); 37 | } 38 | 39 | public static void Clear() 40 | { 41 | GEvents.Clear(); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Runtime/Event/EventStruct.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine.Events; 4 | 5 | namespace GUA.Event 6 | { 7 | public struct EventStruct 8 | { 9 | public Type EventType { get; } 10 | public bool HasObject { get; private set; } 11 | 12 | private object _eventObject; 13 | private readonly List> _events; 14 | 15 | public EventStruct(object eventObject) 16 | { 17 | _eventObject = eventObject; 18 | _events = new List>(); 19 | EventType = eventObject.GetType(); 20 | HasObject = true; 21 | } 22 | 23 | public EventStruct(Type eventType, UnityAction action) 24 | { 25 | _eventObject = null; 26 | _events = new List> 27 | { 28 | action 29 | }; 30 | EventType = eventType; 31 | HasObject = false; 32 | } 33 | 34 | public void SetObject(object eventObject) 35 | { 36 | _eventObject = eventObject; 37 | HasObject = true; 38 | } 39 | 40 | public void AddAction(UnityAction action) 41 | { 42 | _events.Add(action); 43 | } 44 | 45 | public void Invoke() 46 | { 47 | var thisStruct = this; 48 | thisStruct._events.ForEach(e => e.Invoke(thisStruct._eventObject)); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Runtime/State/GState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace GUA.State 5 | { 6 | public static class GState 7 | { 8 | private static readonly Dictionary States = new Dictionary(); 9 | private static readonly Dictionary Executables = new Dictionary(); 10 | 11 | public static void SetState(T stateType, object mainExecutableObject = null) where T : Enum 12 | { 13 | var type = typeof(T); 14 | 15 | if (States.ContainsKey(type)) 16 | { 17 | var state = States[type]; 18 | state.StateType = stateType; 19 | 20 | if (state.ExecutableObject == null) return; 21 | SetExecutable(state.ExecutableObject); 22 | } 23 | else 24 | { 25 | States.Add(type, new StateValue(stateType, mainExecutableObject)); 26 | 27 | if (mainExecutableObject == null) return; 28 | SetExecutable(mainExecutableObject); 29 | } 30 | } 31 | 32 | public static T GetState() where T : Enum 33 | { 34 | return (T)States[typeof(T)].StateType; 35 | } 36 | 37 | public static T GetExecutable() where T : class 38 | { 39 | if (!Executables.ContainsKey(typeof(T))) 40 | throw new Exception("Error"); 41 | return Executables[typeof(T)] as T; 42 | } 43 | 44 | private static void SetExecutable(object executable) 45 | { 46 | var type = executable.GetType(); 47 | var baseType = type.BaseType; 48 | 49 | if (baseType == null) return; 50 | if (baseType == typeof(object)) 51 | Executables[type] = executable; 52 | else 53 | Executables[baseType] = executable; 54 | } 55 | 56 | public static void RegisterState(Enum state, object executable) 57 | { 58 | var currentState = States[state.GetType()]; 59 | currentState.RegisterState(state, executable); 60 | 61 | if(!Equals(state, currentState.StateType)) return; 62 | 63 | SetExecutable(executable); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Content/package_manager.gif.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 72ec1cba07256e34c80deae4a97e6254 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: -1 36 | aniso: -1 37 | mipBias: -100 38 | wrapU: 1 39 | wrapV: 1 40 | wrapW: 1 41 | nPOTScale: 0 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 1 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 1 54 | spriteTessellationDetail: -1 55 | textureType: 8 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | spriteSheet: 79 | serializedVersion: 2 80 | sprites: [] 81 | outline: [] 82 | physicsShape: [] 83 | bones: [] 84 | spriteID: 5e97eb03825dee720800000000000000 85 | internalID: 0 86 | vertices: [] 87 | indices: 88 | edges: [] 89 | weights: [] 90 | secondaryTextures: [] 91 | spritePackingTag: 92 | pSDRemoveMatte: 0 93 | pSDShowRemoveMatteOption: 0 94 | userData: 95 | assetBundleName: 96 | assetBundleVariant: 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GUA 2 | 3 | * [About](#about) 4 | * [Installation](#installation) 5 | * [GSystem](#gsystem) 6 | * [GState](#gstate) 7 | * [Simple state](#simple-state) 8 | * [Behavioral states](#behavioral-states) 9 | * [GDataPool](#gdatapool) 10 | * [GEventPool](#geventpool) 11 | * [GInvoke](#ginvoke) 12 | * [Extensions](#extensions) 13 | * [Singleton](#singleton) 14 | * [SetListener](#setlistener) 15 | 16 | ## About 17 | A simple package, following the rules of which you can write 18 | a more supportable and extensible application. GUA uses the principles 19 | of single entry into the application, independence of its systems, variability. 20 | 21 | ## Installation 22 | This repository can be installed as unity module directly from Git URL 23 | ```text 24 | https://github.com/gunity/GUA.git 25 | ``` 26 | 27 | ![Installation](https://github.com/gunity/GUA/blob/main/Content/package_manager.gif) 28 | 29 | ## GSystem 30 | A single-entry principle is used. 31 | The whole code is divided into parts - systems. 32 | The system must be inherited from the `MonoSystem`. 33 | ```c# 34 | public class SomeSystem : MonoSystem 35 | { 36 | public SomeSystem(bool enabled) : base(enabled) { } 37 | } 38 | ``` 39 | In the starter file you must add the system. 40 | ```c# 41 | _system.Add(new SomeSystem(true)); 42 | ``` 43 | where `true` - the system is initially enabled. 44 | ```c# 45 | public class SomeSystem : MonoSystem 46 | { 47 | public SomeSystem(bool enabled) : base(enabled) 48 | { 49 | // will be executed once when the system is initialized 50 | } 51 | 52 | protected override void Start() 53 | { 54 | // will be executed once on the next frame after the first enabling of the system 55 | } 56 | 57 | public override void Run() 58 | { 59 | // analogue Update 60 | } 61 | 62 | public override void FixedRun() 63 | { 64 | // analogue FixedUpdate 65 | } 66 | } 67 | ``` 68 | If your system is disabled, you can turn it on using the `Enabled` field 69 | ```c# 70 | public class SomeSystem : MonoSystem 71 | { 72 | public SomeSystem(bool enabled) : base(enabled) 73 | { 74 | GEventPool.AddListener(simpleEvent => Enabled = true); 75 | } 76 | 77 | public override void Run() 78 | { 79 | Debug.Log("The system is now enabled"); 80 | } 81 | } 82 | ``` 83 | 84 | ## GState 85 | 86 | ### Simple state 87 | 88 | You can save the enum state with GState 89 | ```c# 90 | public enum SomeState 91 | { 92 | First, 93 | Second, 94 | Third 95 | } 96 | ``` 97 | ```c# 98 | GState.SetState(SomeState.Second); 99 | ``` 100 | 101 | To get the enum state 102 | ```c# 103 | var state = GState.GetState(); 104 | ``` 105 | 106 | ### Behavioral states 107 | 108 | Also when creating a state, you can bind behavior to it. 109 | Create behaviors that inherit from the same class 110 | ```c# 111 | public class MainBehaviour 112 | { 113 | public virtual void SomeMethod() 114 | { 115 | Debug.Log("State is not specifically defined"); 116 | } 117 | } 118 | ``` 119 | ```c# 120 | public class FirstBehaviour : MainBehaviour 121 | { 122 | public override void SomeMethod() 123 | { 124 | Debug.Log("First Behaviour"); 125 | } 126 | } 127 | ``` 128 | ```c# 129 | public class SecondBehaviour : MainBehaviour 130 | { 131 | public override void SomeMethod() 132 | { 133 | Debug.Log("Second Behaviour"); 134 | } 135 | } 136 | ``` 137 | Declare the state and specify the default behavior 138 | ```c# 139 | public PlayerSystem(bool enabled) : base(enabled) 140 | { 141 | // SomeState.Second - initial state 142 | // new MainBehaviour() - default behavior 143 | GState.SetState(SomeState.Second, new MainBehaviour()); 144 | 145 | // Bind state to behavior 146 | GState.RegisterState(SomeState.First, new FirstBehaviour()); 147 | GState.RegisterState(SomeState.Second, new SecondBehaviour()); 148 | } 149 | 150 | public override void Run() 151 | { 152 | GState.GetExecutable().SomeMethod(); 153 | } 154 | ``` 155 | If you have not bound a state, the default behavior will be executed. 156 | 157 | ## GDataPool 158 | 159 | You can pass information to each system through the constructor, 160 | but then things will quickly become cluttered. 161 | That's why the data container is created. 162 | A container that stores data by unique types. 163 | 164 | Create a unique type field in the starter-file 165 | ```c# 166 | [SerializeField] private SomeData someData; 167 | ``` 168 | Injection 169 | ```c# 170 | GDataPool.Set(someData); 171 | ``` 172 | Getting data 173 | ```c# 174 | private readonly SomeData someData = GDataPool.Get(); 175 | ``` 176 | 177 | ## GEventPool 178 | 179 | Systems can communicate with each other with event structures. 180 | 181 | Create event-structure 182 | ```c# 183 | public struct SomeEvent 184 | { 185 | public int SomeInteger; 186 | public string SomeString; 187 | } 188 | ``` 189 | Add message listener 190 | ```c# 191 | GEventPool.AddListener(some => 192 | { 193 | Debug.Log($"Integer: {some.SomeInteger}; String: {some.SomeString}"); 194 | }); 195 | ``` 196 | Send message 197 | ```c# 198 | GEventPool.SendMessage(new SomeEvent 199 | { 200 | SomeInteger = 123, 201 | SomeString = "string" 202 | }); 203 | ``` 204 | See console 205 | ```text 206 | Integer: 123 String: string 207 | ``` 208 | 209 | ## GInvoke 210 | 211 | A way to delay code execution. 212 | The example below displays "Hello, World!" in the console after 5 seconds, 213 | but if you press the space bar, the execution is interrupted. 214 | 215 | ```c# 216 | private readonly GInvoke _gInvoke; 217 | 218 | public SomeSystem(bool enabled) : base(enabled) 219 | { 220 | _gInvoke = new GInvoke(); 221 | _gInvoke.Delay(() => 222 | { 223 | Debug.Log("Hello, World!"); 224 | }, 5000); 225 | } 226 | 227 | public override void Run() 228 | { 229 | if (Input.GetKeyDown(KeyCode.Space)) 230 | { 231 | _gInvoke.Stop(); 232 | } 233 | } 234 | ``` 235 | 236 | ## Extensions 237 | 238 | ### Singleton 239 | 240 | ```c# 241 | public class SomeClass : Singleton 242 | { 243 | // now it's Singleton class 244 | } 245 | ``` 246 | 247 | ### SetListener 248 | Instead 249 | ```c# 250 | unityEvent.RemoveAllListeners(); 251 | unityEvent.AddListener(SomeMethod); 252 | ``` 253 | You could write it like this 254 | ```c# 255 | unityEvent.SetListener(SomeMethod); 256 | ``` -------------------------------------------------------------------------------- /Editor/CreatorWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | namespace GUA.Editor 7 | { 8 | public class CreatorWindow : EditorWindow 9 | { 10 | private const string StarterTemplate = "Starter.cs.txt"; 11 | private const string StarterEditorTemplate = "StarterEditor.cs.txt"; 12 | 13 | private static bool _showWillBeGenerated; 14 | private static bool _createEditorScript; 15 | private static bool _createFolders; 16 | private static bool _createScriptsFolder; 17 | private static string _rootNamespace = string.Empty; 18 | private static string _selectedPath = string.Empty; 19 | private static string _starterName = "Starter"; 20 | 21 | private static CreatorWindow _window; 22 | 23 | [MenuItem("Assets/Create/GUA/Creator", false, 0)] 24 | private static void ShowWindow() 25 | { 26 | _window = GetWindow(true, "GUA Creator"); 27 | _window.minSize = new Vector2(350, 320); 28 | _rootNamespace = EditorSettings.projectGenerationRootNamespace.Trim(); 29 | _window.Show(); 30 | } 31 | 32 | private void OnGUI() 33 | { 34 | if(_selectedPath == string.Empty) _selectedPath = AssetDatabase.GetAssetPath(Selection.activeObject); 35 | 36 | _rootNamespace = EditorGUILayout.TextField("Root Namespace", _rootNamespace); 37 | _starterName = EditorGUILayout.TextField("Starter Name", _starterName); 38 | _createScriptsFolder = EditorGUILayout.Toggle("Create Script Folder", _createScriptsFolder); 39 | _createEditorScript = EditorGUILayout.Toggle("Create Editor Script", _createEditorScript); 40 | _createFolders = EditorGUILayout.Toggle("Create Folders", _createFolders); 41 | 42 | if (GUILayout.Button("Change Path")) 43 | { 44 | var path = EditorUtility.SaveFolderPanel("Select Folder", _selectedPath, string.Empty); 45 | if (CheckPath(path)) _selectedPath = TrimPath(path); 46 | else if (path != string.Empty) EditorUtility.DisplayDialog("Error", "Invalid path", "OK"); 47 | } 48 | 49 | GUILayout.Space(10); 50 | 51 | _showWillBeGenerated = EditorGUILayout.Foldout(_showWillBeGenerated, "Will be generated"); 52 | 53 | if (_showWillBeGenerated) 54 | { 55 | GUILayout.Label($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}{(_createFolders ? "Starters/" : string.Empty)}{_starterName}.cs"); 56 | if (_createEditorScript) GUILayout.Label($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Editor/{_starterName}Editor.cs"); 57 | if (_createFolders) 58 | { 59 | GUILayout.Label($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Data"); 60 | GUILayout.Label($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Emitters"); 61 | GUILayout.Label($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Information"); 62 | GUILayout.Label($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Managers"); 63 | GUILayout.Label($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Systems"); 64 | GUILayout.Label($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Events"); 65 | GUILayout.Label($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Structs"); 66 | } 67 | } 68 | 69 | GUILayout.Space(10); 70 | 71 | if (!GUILayout.Button("Create", GUILayout.Height(30))) return; 72 | 73 | Generate(); 74 | AssetDatabase.Refresh(); 75 | Close(); 76 | } 77 | 78 | private static void Generate() 79 | { 80 | EditorSettings.projectGenerationRootNamespace = _rootNamespace.Trim(); 81 | 82 | if (_createFolders) 83 | { 84 | CreateEmptyFolder($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Editor"); 85 | CreateEmptyFolder($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Data"); 86 | CreateEmptyFolder($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Emitters"); 87 | CreateEmptyFolder($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Information"); 88 | CreateEmptyFolder($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Managers"); 89 | CreateEmptyFolder($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Systems"); 90 | CreateEmptyFolder($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Events"); 91 | CreateEmptyFolder($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Structs"); 92 | CreateEmptyFolder($"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Starters"); 93 | } 94 | 95 | var starterPath = $"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}{(_createFolders ? "Starters/" : string.Empty)}"; 96 | var starterNamespace = CreateScript(starterPath, StarterTemplate, _starterName); 97 | 98 | if (!_createEditorScript) return; 99 | var starterEditorPath = $"{_selectedPath}/{(_createScriptsFolder ? "Scripts/" : string.Empty)}Editor/"; 100 | _ = CreateScript(starterEditorPath, StarterEditorTemplate, $"{_starterName}Editor", starterNamespace); 101 | } 102 | 103 | private static bool CheckPath(string path) 104 | { 105 | return path.Contains("Assets"); 106 | } 107 | 108 | private static string TrimPath(string path) 109 | { 110 | var startIndex = path.IndexOf("Assets", StringComparison.Ordinal); 111 | path = path.Substring(startIndex); 112 | return path; 113 | } 114 | 115 | private static void CreateEmptyFolder(string path) 116 | { 117 | if (Directory.Exists(path)) return; 118 | 119 | Directory.CreateDirectory(path); 120 | File.Create($"{path}/.gitkeep"); 121 | } 122 | 123 | private static string CreateScript(string path, string templateName, string scriptName, string starterNamespace = null) 124 | { 125 | var templatePath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(_window))); 126 | var template = File.ReadAllText($"{templatePath}/{templateName}"); 127 | var scriptNamespace = GetNamespace(path); 128 | 129 | var script = template.Replace("#SCRIPT_NAME#", scriptName); 130 | script = script.Replace("#STARTER_NAME#", _starterName); 131 | script = script.Replace("#NAMESPACE#", scriptNamespace); 132 | script = script.Replace("#STARTER_NAMESPACE#", starterNamespace); 133 | 134 | File.WriteAllText($"{path}/{scriptName}.cs", script); 135 | 136 | return scriptNamespace; 137 | } 138 | 139 | private static string GetNamespace(string path) 140 | { 141 | var result = string.Empty; 142 | 143 | var rootNamespace = _rootNamespace.Trim(); 144 | if (!string.IsNullOrEmpty(rootNamespace)) result += rootNamespace; 145 | 146 | var pathsSplit = path.Split('/'); 147 | var writeNamespace = false; 148 | foreach (var pathPart in pathsSplit) 149 | { 150 | if (string.IsNullOrEmpty(pathPart)) continue; 151 | if (pathPart == "Assets" || pathPart == "Scripts") 152 | { 153 | writeNamespace = true; 154 | continue; 155 | } 156 | if (writeNamespace) result += $"{(string.IsNullOrEmpty(result) ? string.Empty : ".")}{pathPart}"; 157 | } 158 | 159 | return result; 160 | } 161 | } 162 | } --------------------------------------------------------------------------------