From 6a89900d73c8d932da1fe77447c64b2338835201 Mon Sep 17 00:00:00 2001 From: SnowShow Date: Tue, 22 Apr 2025 15:51:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EintooAR/Assets/Animancer Settings.asset | 61 + EintooAR/Assets/Animancer Settings.asset.meta | 8 + EintooAR/Assets/AssetArt.meta | 8 + EintooAR/Assets/AssetRaw.meta | 8 + EintooAR/Assets/DefaultVolumeProfile.asset | 15 + .../Assets/DefaultVolumeProfile.asset.meta | 8 + EintooAR/Assets/Editor.meta | 8 + EintooAR/Assets/GameScripts.meta | 8 + EintooAR/Assets/Plugins.meta | 8 + EintooAR/Assets/Resources.meta | 8 + EintooAR/Assets/Scenes.meta | 8 + EintooAR/Assets/StreamingAssets.meta | 8 + EintooAR/Assets/TEngine.meta | 8 + EintooAR/Assets/TEngine/AssetSetting.meta | 8 + .../AssetBundleCollectorConfig.xml | 40 + .../AssetBundleCollectorConfig.xml.meta | 7 + .../AssetBundleCollectorSetting.asset | 203 + .../AssetBundleCollectorSetting.asset.meta | 8 + .../TEngine/AssetSetting/Resources.meta | 8 + .../Resources/YooAssetSettings.asset | 16 + .../Resources/YooAssetSettings.asset.meta | 8 + EintooAR/Assets/TEngine/Editor.meta | 8 + .../Assets/TEngine/Editor/DefineSymbols.meta | 8 + .../LogScriptingDefineSymbols.cs | 172 + .../LogScriptingDefineSymbols.cs.meta | 11 + .../DefineSymbols/ProfilerDefineSymbols.cs | 44 + .../ProfilerDefineSymbols.cs.meta | 3 + .../DefineSymbols/ScriptingDefineSymbols.cs | 151 + .../ScriptingDefineSymbols.cs.meta | 11 + .../Assets/TEngine/Editor/EditorTools.meta | 3 + .../TEngine/Editor/EditorTools/LubanTools.cs | 20 + .../Editor/EditorTools/LubanTools.cs.meta | 3 + .../Assets/TEngine/Editor/EventInterface.meta | 8 + .../EventInterface/EventInterfaceGenerate.cs | 307 + .../EventInterfaceGenerate.cs.meta | 11 + .../Assets/TEngine/Editor/GameSettings.meta | 3 + .../Editor/GameSettings/SettingsMenu.cs | 7 + .../Editor/GameSettings/SettingsMenu.cs.meta | 11 + .../GameSettings/SynAssemblysContent.cs | 35 + .../GameSettings/SynAssemblysContent.cs.meta | 11 + .../GameSettings/TEngineSettingsProvider.cs | 115 + .../TEngineSettingsProvider.cs.meta | 3 + EintooAR/Assets/TEngine/Editor/HybridCLR.meta | 3 + .../Editor/HybridCLR/BuildDLLCommand.cs | 99 + .../Editor/HybridCLR/BuildDLLCommand.cs.meta | 11 + EintooAR/Assets/TEngine/Editor/Inspector.meta | 8 + .../TEngine/Editor/Inspector/Asset.meta | 8 + .../Inspector/Asset/DefaultAssetInspector.cs | 52 + .../Asset/DefaultAssetInspector.cs.meta | 11 + .../Inspector/Asset/TextAssetInspector.cs | 53 + .../Asset/TextAssetInspector.cs.meta | 11 + .../Editor/Inspector/AudioModuleInspector.cs | 54 + .../Inspector/AudioModuleInspector.cs.meta | 11 + .../Assets/TEngine/Editor/Inspector/Core.meta | 8 + .../Inspector/Core/GameFrameworkInspector.cs | 57 + .../Core/GameFrameworkInspector.cs.meta | 11 + .../Editor/Inspector/FsmComponentInspector.cs | 40 + .../Inspector/FsmComponentInspector.cs.meta | 11 + .../Inspector/MemoryPoolModuleInspector.cs | 143 + .../MemoryPoolModuleInspector.cs.meta | 11 + .../Inspector/ObjectPoolModuleInspector.cs | 146 + .../ObjectPoolModuleInspector.cs.meta | 11 + .../Inspector/ProcedureModuleInspector.cs | 163 + .../ProcedureModuleInspector.cs.meta | 11 + .../Inspector/ResourceModuleInspector.cs | 290 + .../Inspector/ResourceModuleInspector.cs.meta | 11 + .../Editor/Inspector/RootModuleInspector.cs | 278 + .../Inspector/RootModuleInspector.cs.meta | 11 + .../Inspector/SettingModuleInspector.cs | 73 + .../Inspector/SettingModuleInspector.cs.meta | 11 + .../Editor/Inspector/UIModuleInspector.cs | 57 + .../Inspector/UIModuleInspector.cs.meta | 11 + .../Assets/TEngine/Editor/Localization.meta | 8 + .../Editor/Localization/EditorTools.cs | 764 + .../Editor/Localization/EditorTools.cs.meta | 8 + .../Editor/Localization/Inspectors.meta | 9 + .../LanguageSourceAssetInspector.cs | 20 + .../LanguageSourceAssetInspector.cs.meta | 10 + .../Inspectors/LanguageSourceInspector.cs | 22 + .../LanguageSourceInspector.cs.meta | 10 + .../Inspectors/LocalizationEditor.cs | 200 + .../Inspectors/LocalizationEditor.cs.meta | 10 + .../LocalizationParamsManagerInspector.cs | 107 + ...LocalizationParamsManagerInspector.cs.meta | 12 + .../Inspectors/LocalizeDropdownInspector.cs | 131 + .../LocalizeDropdownInspector.cs.meta | 12 + .../Inspectors/LocalizeInspector.cs | 896 ++ .../Inspectors/LocalizeInspector.cs.meta | 10 + .../Inspectors/ResourceManagerInspector.cs | 29 + .../ResourceManagerInspector.cs.meta | 10 + .../Inspectors/SetLanguageInspector.cs | 60 + .../Inspectors/SetLanguageInspector.cs.meta | 10 + .../Inspectors/TermsPopup_Drawer.cs | 164 + .../Inspectors/TermsPopup_Drawer.cs.meta | 10 + .../Editor/Localization/Localization.meta | 9 + .../Localization/LocalizationEditor.cs | 308 + .../Localization/LocalizationEditor.cs.meta | 10 + .../LocalizationEditor_Languages.cs | 477 + .../LocalizationEditor_Languages.cs.meta | 10 + .../LocalizationEditor_Spreadsheet_Google.cs | 727 + ...alizationEditor_Spreadsheet_Google.cs.meta | 10 + .../LocalizationEditor_Spreadsheet_Local.cs | 339 + ...calizationEditor_Spreadsheet_Local.cs.meta | 10 + .../Localization/LocalizationEditor_Terms.cs | 840 ++ .../LocalizationEditor_Terms.cs.meta | 10 + .../LocalizationEditor_Terms_Description.cs | 785 + ...calizationEditor_Terms_Description.cs.meta | 10 + .../Localization/LocalizationEditor_Tools.cs | 49 + .../LocalizationEditor_Tools.cs.meta | 10 + .../LocalizationEditor_Tools_Categorize.cs | 226 + ...ocalizationEditor_Tools_Categorize.cs.meta | 10 + .../LocalizationEditor_Tools_CharSet.cs | 190 + .../LocalizationEditor_Tools_CharSet.cs.meta | 10 + .../LocalizationEditor_Tools_MergeTerms.cs | 157 + ...ocalizationEditor_Tools_MergeTerms.cs.meta | 10 + .../LocalizationEditor_Tools_NoLocalized.cs | 163 + ...calizationEditor_Tools_NoLocalized.cs.meta | 10 + .../LocalizationEditor_Tools_ParseTerms.cs | 378 + ...ocalizationEditor_Tools_ParseTerms.cs.meta | 10 + .../LocalizationEditor_Tools_Scenes.cs | 179 + .../LocalizationEditor_Tools_Scenes.cs.meta | 10 + .../LocalizationEditor_Tools_Script.cs | 281 + .../LocalizationEditor_Tools_Script.cs.meta | 10 + .../LocalizationEditor_Warnings.cs | 173 + .../LocalizationEditor_Warnings.cs.meta | 10 + .../Localization/PostProcessBuild_ANDROID.cs | 151 + .../PostProcessBuild_ANDROID.cs.meta | 12 + .../Localization/PostProcessBuild_IOS.cs | 102 + .../Localization/PostProcessBuild_IOS.cs.meta | 12 + .../PostProcessBuild_UnloadLanguages.cs | 30 + .../PostProcessBuild_UnloadLanguages.cs.meta | 12 + .../Editor/Localization/Unity XCode.meta | 9 + .../UnityEditor.iOS_I2Loc.Xcode.dll | Bin 0 -> 123904 bytes .../UnityEditor.iOS_I2Loc.Xcode.dll.meta | 24 + .../Editor/Localization/Unity XCode/Xcode.txt | 9 + .../Localization/Unity XCode/Xcode.txt.meta | 8 + .../Editor/Localization/UpgradeManager.cs | 334 + .../Localization/UpgradeManager.cs.meta | 10 + .../Assets/TEngine/Editor/Postprocessor.meta | 8 + .../Postprocessor/SpritePostprocessor.cs | 548 + .../Postprocessor/SpritePostprocessor.cs.meta | 11 + .../Assets/TEngine/Editor/ReleaseTools.meta | 3 + .../Editor/ReleaseTools/ReleaseTools.cs | 258 + .../Editor/ReleaseTools/ReleaseTools.cs.meta | 3 + EintooAR/Assets/TEngine/Editor/Resource.meta | 3 + .../TEngine/Editor/Resource/Encryption.cs | 53 + .../Editor/Resource/Encryption.cs.meta | 11 + .../Editor/Resource/ExtensionFilterRule.cs | 14 + .../Resource/ExtensionFilterRule.cs.meta | 3 + .../TEngine/Editor/TEngine.Editor.asmdef | 49 + .../TEngine/Editor/TEngine.Editor.asmdef.meta | 7 + .../TEngine/Editor/ToolbarExtender.meta | 8 + .../Editor/ToolbarExtender/Custom.meta | 8 + .../ToolbarExtender/Custom/SceneSwitcher.meta | 8 + .../Custom/SceneSwitcher/Editor.meta | 8 + .../Editor/EditorResourceMode.cs | 70 + .../Editor/EditorResourceMode.cs.meta | 3 + .../SceneSwitcher/Editor/SceneSwitcher.cs | 100 + .../Editor/SceneSwitcher.cs.meta | 11 + .../Editor/ToolbarExtender/ToolbarCallback.cs | 111 + .../ToolbarExtender/ToolbarCallback.cs.meta | 11 + .../Editor/ToolbarExtender/ToolbarExtender.cs | 169 + .../ToolbarExtender/ToolbarExtender.cs.meta | 11 + EintooAR/Assets/TEngine/Editor/UI.meta | 3 + .../Editor/UI/ComponentAutoBindTool.meta | 3 + .../AutoBindGlobalSetting.cs | 45 + .../AutoBindGlobalSetting.cs.meta | 3 + .../AutoBindGlobalSettingInspector.cs | 12 + .../AutoBindGlobalSettingInspector.cs.meta | 3 + .../ComponentAutoBindToolInspector.cs | 534 + .../ComponentAutoBindToolInspector.cs.meta | 3 + .../TEngine/Editor/UI/ScriptGenerator.cs | 336 + .../TEngine/Editor/UI/ScriptGenerator.cs.meta | 11 + .../Assets/TEngine/Editor/UI/TEUIHelper.cs | 73 + .../TEngine/Editor/UI/TEUIHelper.cs.meta | 11 + .../TEngine/Editor/UI/TEUIHelperWindiw.cs | 138 + .../Editor/UI/TEUIHelperWindiw.cs.meta | 11 + EintooAR/Assets/TEngine/Editor/Utility.meta | 8 + .../TEngine/Editor/Utility/ClassHelper.cs | 69 + .../Editor/Utility/ClassHelper.cs.meta | 3 + .../Editor/Utility/CommandLineReader.cs | 120 + .../Editor/Utility/CommandLineReader.cs.meta | 3 + .../TEngine/Editor/Utility/GetAssetHelper.cs | 41 + .../Editor/Utility/GetAssetHelper.cs.meta | 11 + .../TEngine/Editor/Utility/HelperInfo.cs | 89 + .../TEngine/Editor/Utility/HelperInfo.cs.meta | 3 + .../TEngine/Editor/Utility/LogRedirection.cs | 123 + .../Editor/Utility/LogRedirection.cs.meta | 11 + .../Editor/Utility/OpenFolderHelper.cs | 83 + .../Editor/Utility/OpenFolderHelper.cs.meta | 11 + .../TEngine/Editor/Utility/ShellHelper.cs | 106 + .../Editor/Utility/ShellHelper.cs.meta | 3 + .../Assets/TEngine/Editor/Utility/Type.cs | 83 + .../TEngine/Editor/Utility/Type.cs.meta | 11 + EintooAR/Assets/TEngine/ResRaw.meta | 8 + .../ResRaw/AutoBindGlobalSetting.asset | 17 + .../ResRaw/AutoBindGlobalSetting.asset.meta | 8 + EintooAR/Assets/TEngine/ResRaw/Resources.meta | 8 + .../Resources/TEngineGlobalSettings.asset | 105 + .../TEngineGlobalSettings.asset.meta | 8 + EintooAR/Assets/TEngine/Runtime.meta | 8 + EintooAR/Assets/TEngine/Runtime/Core.meta | 8 + .../Assets/TEngine/Runtime/Core/Constant.meta | 3 + .../TEngine/Runtime/Core/Constant/Constant.cs | 32 + .../Runtime/Core/Constant/Constant.cs.meta | 3 + .../TEngine/Runtime/Core/DataStruct.meta | 3 + .../DataStruct/GameFrameworkDictionary.cs | 120 + .../GameFrameworkDictionary.cs.meta | 3 + .../DataStruct/GameFrameworkLinkedList.cs | 392 + .../GameFrameworkLinkedList.cs.meta | 3 + .../GameFrameworkLinkedListRange.cs | 180 + .../GameFrameworkLinkedListRange.cs.meta | 3 + .../GameFrameworkMultiDictionary.cs | 258 + .../GameFrameworkMultiDictionary.cs.meta | 3 + .../DataStruct/GameFrameworkSerializer.cs | 201 + .../GameFrameworkSerializer.cs.meta | 3 + .../Core/DataStruct/SerializableDictionary.cs | 259 + .../DataStruct/SerializableDictionary.cs.meta | 3 + .../Runtime/Core/DataStruct/TypeNamePair.cs | 116 + .../Core/DataStruct/TypeNamePair.cs.meta | 11 + .../TEngine/Runtime/Core/Exception.meta | 8 + .../Core/Exception/GameFrameworkException.cs | 49 + .../Exception/GameFrameworkException.cs.meta | 11 + .../TEngine/Runtime/Core/GameEvent.meta | 3 + .../Core/GameEvent/ActorEventDispatcher.cs | 640 + .../GameEvent/ActorEventDispatcher.cs.meta | 3 + .../Core/GameEvent/EventDelegateData.cs | 267 + .../Core/GameEvent/EventDelegateData.cs.meta | 3 + .../Runtime/Core/GameEvent/EventDispatcher.cs | 186 + .../Core/GameEvent/EventDispatcher.cs.meta | 3 + .../Core/GameEvent/EventInterfaceAttribute.cs | 31 + .../GameEvent/EventInterfaceAttribute.cs.meta | 3 + .../Runtime/Core/GameEvent/EventMgr.cs | 83 + .../Runtime/Core/GameEvent/EventMgr.cs.meta | 3 + .../Runtime/Core/GameEvent/GameEvent.cs | 597 + .../Runtime/Core/GameEvent/GameEvent.cs.meta | 3 + .../Runtime/Core/GameEvent/GameEventMgr.cs | 109 + .../Core/GameEvent/GameEventMgr.cs.meta | 3 + .../Runtime/Core/GameEvent/RuntimeId.cs | 56 + .../Runtime/Core/GameEvent/RuntimeId.cs.meta | 3 + .../TEngine/Runtime/Core/GameSettings.meta | 8 + .../Runtime/Core/GameSettings/Enum.meta | 3 + .../Core/GameSettings/Enum/AppStageEnum.cs | 31 + .../GameSettings/Enum/AppStageEnum.cs.meta | 3 + .../Core/GameSettings/Enum/ServerTypeEnum.cs | 25 + .../GameSettings/Enum/ServerTypeEnum.cs.meta | 3 + .../Runtime/Core/GameSettings/Framework.meta | 3 + .../Framework/FrameworkGlobalSettings.cs | 186 + .../Framework/FrameworkGlobalSettings.cs.meta | 3 + .../Runtime/Core/GameSettings/HybridCLR.meta | 3 + .../HybridCLRCustomGlobalSettings.cs | 49 + .../HybridCLRCustomGlobalSettings.cs.meta | 3 + .../Core/GameSettings/SettingsUtils.cs | 212 + .../Core/GameSettings/SettingsUtils.cs.meta | 3 + .../Core/GameSettings/TEngineSettings.cs | 19 + .../Core/GameSettings/TEngineSettings.cs.meta | 3 + .../Assets/TEngine/Runtime/Core/GameTime.meta | 3 + .../TEngine/Runtime/Core/GameTime/GameTime.cs | 55 + .../Runtime/Core/GameTime/GameTime.cs.meta | 3 + EintooAR/Assets/TEngine/Runtime/Core/Log.meta | 8 + .../Core/Log/GameFrameworkLog.ILogHelper.cs | 18 + .../Log/GameFrameworkLog.ILogHelper.cs.meta | 11 + .../Runtime/Core/Log/GameFrameworkLog.cs | 2639 ++++ .../Runtime/Core/Log/GameFrameworkLog.cs.meta | 11 + .../Runtime/Core/Log/GameFrameworkLogLevel.cs | 33 + .../Core/Log/GameFrameworkLogLevel.cs.meta | 11 + .../Assets/TEngine/Runtime/Core/Log/Log.cs | 2780 ++++ .../TEngine/Runtime/Core/Log/Log.cs.meta | 11 + .../TEngine/Runtime/Core/MemoryPool.meta | 3 + .../Runtime/Core/MemoryPool/IMemory.cs | 13 + .../Runtime/Core/MemoryPool/IMemory.cs.meta | 11 + .../MemoryPool/MemoryPool.MemoryCollection.cs | 156 + .../MemoryPool.MemoryCollection.cs.meta | 11 + .../Runtime/Core/MemoryPool/MemoryPool.cs | 207 + .../Core/MemoryPool/MemoryPool.cs.meta | 11 + .../Core/MemoryPool/MemoryPoolExtension.cs | 57 + .../MemoryPool/MemoryPoolExtension.cs.meta | 3 + .../Runtime/Core/MemoryPool/MemoryPoolInfo.cs | 118 + .../Core/MemoryPool/MemoryPoolInfo.cs.meta | 11 + .../Core/MemoryPool/MemoryPoolModule.cs | 77 + .../Core/MemoryPool/MemoryPoolModule.cs.meta | 11 + .../Assets/TEngine/Runtime/Core/Profiler.meta | 8 + .../Runtime/Core/Profiler/TProfiler.cs | 88 + .../Runtime/Core/Profiler/TProfiler.cs.meta | 11 + .../Assets/TEngine/Runtime/Core/Utility.meta | 8 + .../Runtime/Core/Utility/DefaultHelper.meta | 3 + .../DefaultHelper/DefaultJsonHelper.cs | 40 + .../DefaultHelper/DefaultJsonHelper.cs.meta | 3 + .../Utility/DefaultHelper/DefaultLogHelper.cs | 166 + .../DefaultHelper/DefaultLogHelper.cs.meta | 11 + .../DefaultHelper/DefaultTextHelper.cs | 584 + .../DefaultHelper/DefaultTextHelper.cs.meta | 3 + .../DefaultHelper/DefaultVersionHelper.cs | 20 + .../DefaultVersionHelper.cs.meta | 3 + .../Utility/DefaultHelper/UnityJsonHelper.cs | 43 + .../DefaultHelper/UnityJsonHelper.cs.meta | 3 + .../Runtime/Core/Utility/Utility.Assembly.cs | 102 + .../Core/Utility/Utility.Assembly.cs.meta | 3 + .../Runtime/Core/Utility/Utility.Converter.cs | 835 ++ .../Core/Utility/Utility.Converter.cs.meta | 3 + .../Core/Utility/Utility.Encryption.cs | 127 + .../Core/Utility/Utility.Encryption.cs.meta | 3 + .../Runtime/Core/Utility/Utility.File.cs | 234 + .../Runtime/Core/Utility/Utility.File.cs.meta | 3 + .../Runtime/Core/Utility/Utility.Http.cs | 114 + .../Runtime/Core/Utility/Utility.Http.cs.meta | 3 + .../Core/Utility/Utility.Json.IJsonHelper.cs | 39 + .../Utility/Utility.Json.IJsonHelper.cs.meta | 11 + .../Runtime/Core/Utility/Utility.Json.cs | 112 + .../Runtime/Core/Utility/Utility.Json.cs.meta | 11 + .../Runtime/Core/Utility/Utility.Marshal.cs | 228 + .../Core/Utility/Utility.Marshal.cs.meta | 3 + .../Runtime/Core/Utility/Utility.Path.cs | 93 + .../Runtime/Core/Utility/Utility.Path.cs.meta | 3 + .../Core/Utility/Utility.Reflection.cs | 358 + .../Core/Utility/Utility.Reflection.cs.meta | 3 + .../Core/Utility/Utility.Text.ITextHelper.cs | 398 + .../Utility/Utility.Text.ITextHelper.cs.meta | 11 + .../Runtime/Core/Utility/Utility.Text.cs | 614 + .../Runtime/Core/Utility/Utility.Text.cs.meta | 11 + .../Runtime/Core/Utility/Utility.Unity.cs | 408 + .../Core/Utility/Utility.Unity.cs.meta | 3 + .../TEngine/Runtime/Core/Utility/Utility.cs | 9 + .../Runtime/Core/Utility/Utility.cs.meta | 11 + .../Assets/TEngine/Runtime/Core/Version.meta | 3 + .../Core/Version/Version.IVersionHelper.cs | 27 + .../Version/Version.IVersionHelper.cs.meta | 3 + .../TEngine/Runtime/Core/Version/Version.cs | 58 + .../Runtime/Core/Version/Version.cs.meta | 3 + .../Assets/TEngine/Runtime/Extension.meta | 3 + .../Runtime/Extension/BinaryExtension.cs | 187 + .../Runtime/Extension/BinaryExtension.cs.meta | 3 + .../Runtime/Extension/StringBuilderCache.cs | 59 + .../Extension/StringBuilderCache.cs.meta | 11 + .../Runtime/Extension/UGUIExtension.meta | 8 + .../Extension/UGUIExtension/EmptyGraph.cs | 18 + .../UGUIExtension/EmptyGraph.cs.meta | 11 + .../Extension/UGUIExtension/MonoExtend.meta | 3 + .../UGUIExtension/MonoExtend/DragHandler.cs | 117 + .../MonoExtend/DragHandler.cs.meta | 3 + .../MonoExtend/EventTriggerListener.cs | 180 + .../MonoExtend/EventTriggerListener.cs.meta | 3 + .../MonoExtend/ImageBackGroundStretch.cs | 32 + .../MonoExtend/ImageBackGroundStretch.cs.meta | 11 + .../MonoExtend/PointerLongPress.cs | 154 + .../MonoExtend/PointerLongPress.cs.meta | 3 + .../UGUIExtension/MonoExtend/SafeTop.cs | 36 + .../UGUIExtension/MonoExtend/SafeTop.cs.meta | 11 + .../UGUIExtension/MonoExtend/UIButtonScale.cs | 150 + .../MonoExtend/UIButtonScale.cs.meta | 3 + .../UGUIExtension/UIButtonSuper.meta | 3 + .../UIButtonSuper/UIButtonSuper.cs | 292 + .../UIButtonSuper/UIButtonSuper.cs.meta | 3 + .../Extension/UGUIExtension/UIExtension.cs | 113 + .../UGUIExtension/UIExtension.cs.meta | 3 + .../Runtime/Extension/UnityExtension.cs | 195 + .../Runtime/Extension/UnityExtension.cs.meta | 3 + .../Assets/TEngine/Runtime/Libraries.meta | 8 + ...System.Runtime.CompilerServices.Unsafe.dll | Bin 0 -> 18024 bytes ...m.Runtime.CompilerServices.Unsafe.dll.meta | 33 + EintooAR/Assets/TEngine/Runtime/Modules.meta | 8 + .../TEngine/Runtime/Modules/AudioModule.meta | 8 + .../Runtime/Modules/AudioModule/AudioAgent.cs | 446 + .../Modules/AudioModule/AudioAgent.cs.meta | 11 + .../AudioModule/AudioAgentRuntimeState.cs | 33 + .../AudioAgentRuntimeState.cs.meta | 3 + .../Modules/AudioModule/AudioCategory.cs | 192 + .../Modules/AudioModule/AudioCategory.cs.meta | 11 + .../Modules/AudioModule/AudioGroupConfig.cs | 48 + .../AudioModule/AudioGroupConfig.cs.meta | 11 + .../Modules/AudioModule/AudioModule.cs | 216 + .../Modules/AudioModule/AudioModule.cs.meta | 11 + .../Modules/AudioModule/AudioModuleImp.cs | 560 + .../AudioModule/AudioModuleImp.cs.meta | 3 + .../Runtime/Modules/AudioModule/AudioType.cs | 34 + .../Modules/AudioModule/AudioType.cs.meta | 11 + .../Modules/AudioModule/IAudioModule.cs | 115 + .../Modules/AudioModule/IAudioModule.cs.meta | 3 + .../Modules/AudioModule/Resources.meta | 8 + .../AudioModule/Resources/AudioMixer.mixer | 708 + .../Resources/AudioMixer.mixer.meta | 8 + .../Runtime/Modules/DebugerModule.meta | 8 + .../Modules/DebugerModule/Component.meta | 3 + ...ggerModule.EnvironmentInformationWindow.cs | 89 + ...odule.EnvironmentInformationWindow.cs.meta | 3 + ...ebuggerModule.GraphicsInformationWindow.cs | 162 + ...erModule.GraphicsInformationWindow.cs.meta | 3 + ...dule.InputAccelerationInformationWindow.cs | 38 + ...InputAccelerationInformationWindow.cs.meta | 3 + ...gerModule.InputCompassInformationWindow.cs | 41 + ...dule.InputCompassInformationWindow.cs.meta | 3 + ...rModule.InputGyroscopeInformationWindow.cs | 42 + ...le.InputGyroscopeInformationWindow.cs.meta | 3 + ...erModule.InputLocationInformationWindow.cs | 43 + ...ule.InputLocationInformationWindow.cs.meta | 3 + ...gerModule.InputSummaryInformationWindow.cs | 32 + ...dule.InputSummaryInformationWindow.cs.meta | 3 + ...uggerModule.InputTouchInformationWindow.cs | 42 + ...Module.InputTouchInformationWindow.cs.meta | 3 + .../Component/DebuggerModule.LogNode.cs | 117 + .../Component/DebuggerModule.LogNode.cs.meta | 3 + ...uggerModule.MemoryPoolInformationWindow.cs | 106 + ...Module.MemoryPoolInformationWindow.cs.meta | 3 + ...DebuggerModule.NetworkInformationWindow.cs | 61 + ...gerModule.NetworkInformationWindow.cs.meta | 3 + ...uggerModule.ObjectPoolInformationWindow.cs | 86 + ...Module.ObjectPoolInformationWindow.cs.meta | 3 + .../DebuggerModule.OperationsWindow.cs | 59 + .../DebuggerModule.OperationsWindow.cs.meta | 3 + .../DebuggerModule.PathInformationWindow.cs | 28 + ...buggerModule.PathInformationWindow.cs.meta | 3 + ...ebuggerModule.ProfilerInformationWindow.cs | 59 + ...erModule.ProfilerInformationWindow.cs.meta | 3 + ...DebuggerModule.QualityInformationWindow.cs | 102 + ...gerModule.QualityInformationWindow.cs.meta | 3 + ...e.RuntimeMemoryInformationWindow.Sample.cs | 60 + ...timeMemoryInformationWindow.Sample.cs.meta | 3 + ...erModule.RuntimeMemoryInformationWindow.cs | 134 + ...ule.RuntimeMemoryInformationWindow.cs.meta | 3 + ...odule.RuntimeMemorySummaryWindow.Record.cs | 54 + ....RuntimeMemorySummaryWindow.Record.cs.meta | 3 + ...buggerModule.RuntimeMemorySummaryWindow.cs | 122 + ...rModule.RuntimeMemorySummaryWindow.cs.meta | 3 + .../DebuggerModule.SceneInformationWindow.cs | 37 + ...uggerModule.SceneInformationWindow.cs.meta | 3 + .../DebuggerModule.ScreenInformationWindow.cs | 87 + ...ggerModule.ScreenInformationWindow.cs.meta | 3 + ...ggerModule.ScrollableDebuggerWindowBase.cs | 92 + ...odule.ScrollableDebuggerWindowBase.cs.meta | 3 + .../DebuggerModule.SettingsWindow.cs | 218 + .../DebuggerModule.SettingsWindow.cs.meta | 3 + .../DebuggerModule.SystemInformationWindow.cs | 54 + ...ggerModule.SystemInformationWindow.cs.meta | 3 + .../DebuggerModule.TimeInformationWindow.cs | 68 + ...buggerModule.TimeInformationWindow.cs.meta | 3 + .../DebugerModule/DebuggerActiveWindowType.cs | 28 + .../DebuggerActiveWindowType.cs.meta | 3 + .../DebuggerComponent.ConsoleWindow.cs | 416 + .../DebuggerComponent.ConsoleWindow.cs.meta | 3 + .../DebuggerComponent.FpsCounter.cs | 67 + .../DebuggerComponent.FpsCounter.cs.meta | 3 + .../DebuggerManager.DebuggerWindowGroup.cs | 300 + ...ebuggerManager.DebuggerWindowGroup.cs.meta | 3 + .../Modules/DebugerModule/DebuggerManager.cs | 135 + .../DebugerModule/DebuggerManager.cs.meta | 3 + .../Modules/DebugerModule/DebuggerModule.cs | 440 + .../DebugerModule/DebuggerModule.cs.meta | 3 + .../DebugerModule/DebuggerSkin.guiskin | 1427 ++ .../DebugerModule/DebuggerSkin.guiskin.meta | 8 + .../Modules/DebugerModule/IDebuggerManager.cs | 54 + .../DebugerModule/IDebuggerManager.cs.meta | 3 + .../Modules/DebugerModule/IDebuggerWindow.cs | 41 + .../DebugerModule/IDebuggerWindow.cs.meta | 3 + .../DebugerModule/IDebuggerWindowGroup.cs | 52 + .../IDebuggerWindowGroup.cs.meta | 3 + .../Modules/DebugerModule/SkipUnityLogo.cs | 31 + .../DebugerModule/SkipUnityLogo.cs.meta | 3 + .../TEngine/Runtime/Modules/FsmModule.meta | 8 + .../TEngine/Runtime/Modules/FsmModule/Fsm.cs | 505 + .../Runtime/Modules/FsmModule/Fsm.cs.meta | 3 + .../Runtime/Modules/FsmModule/FsmBase.cs | 94 + .../Runtime/Modules/FsmModule/FsmBase.cs.meta | 3 + .../Runtime/Modules/FsmModule/FsmManager.cs | 393 + .../Modules/FsmModule/FsmManager.cs.meta | 3 + .../Runtime/Modules/FsmModule/FsmModule.cs | 249 + .../Modules/FsmModule/FsmModule.cs.meta | 3 + .../Runtime/Modules/FsmModule/FsmState.cs | 103 + .../Modules/FsmModule/FsmState.cs.meta | 3 + .../TEngine/Runtime/Modules/FsmModule/IFsm.cs | 158 + .../Runtime/Modules/FsmModule/IFsm.cs.meta | 3 + .../Runtime/Modules/FsmModule/IFsmManager.cs | 174 + .../Modules/FsmModule/IFsmManager.cs.meta | 3 + .../TEngine/Runtime/Modules/GameModule.cs | 205 + .../Runtime/Modules/GameModule.cs.meta | 3 + .../TEngine/Runtime/Modules/Helper.meta | 3 + .../TEngine/Runtime/Modules/Helper/Helper.cs | 68 + .../Runtime/Modules/Helper/Helper.cs.meta | 3 + .../TEngine/Runtime/Modules/Localization.meta | 8 + .../Runtime/Modules/Localization/Core.meta | 8 + .../Localization/Core/Configurables.meta | 10 + .../Core/Configurables/PersistentStorage.cs | 286 + .../Configurables/PersistentStorage.cs.meta | 13 + .../Configurables/SpecializationManager.cs | 204 + .../SpecializationManager.cs.meta | 10 + .../Localization/Core/EventCallback.cs | 24 + .../Localization/Core/EventCallback.cs.meta | 10 + .../Modules/Localization/Core/Extension.meta | 3 + .../Core/Extension/RealTimeTranslation.cs | 132 + .../Extension/RealTimeTranslation.cs.meta | 8 + .../Modules/Localization/Core/Google.meta | 9 + .../Core/Google/GoogleLanguages.cs | 648 + .../Core/Google/GoogleLanguages.cs.meta | 10 + .../Core/Google/GoogleTranslation.cs | 86 + .../Core/Google/GoogleTranslation.cs.meta | 10 + .../Core/Google/GoogleTranslation_Post.cs | 175 + .../Google/GoogleTranslation_Post.cs.meta | 10 + .../Core/Google/GoogleTranslation_Queries.cs | 375 + .../Google/GoogleTranslation_Queries.cs.meta | 10 + .../Localization/Core/Google/SimpleJSON.cs | 1109 ++ .../Core/Google/SimpleJSON.cs.meta | 10 + .../Core/Google/TranslationJob.cs | 34 + .../Core/Google/TranslationJob.cs.meta | 10 + .../Core/Google/TranslationJob_GET.cs | 79 + .../Core/Google/TranslationJob_GET.cs.meta | 10 + .../Core/Google/TranslationJob_Main.cs | 102 + .../Core/Google/TranslationJob_Main.cs.meta | 10 + .../Core/Google/TranslationJob_POST.cs | 60 + .../Core/Google/TranslationJob_POST.cs.meta | 10 + .../Core/Google/TranslationJob_WEB.cs | 169 + .../Core/Google/TranslationJob_WEB.cs.meta | 10 + .../Modules/Localization/Core/LanguageData.cs | 43 + .../Localization/Core/LanguageData.cs.meta | 10 + .../Localization/Core/LanguageSource.meta | 10 + .../Core/LanguageSource/LanguageSource.cs | 179 + .../LanguageSource/LanguageSource.cs.meta | 10 + .../LanguageSource/LanguageSourceAsset.cs | 16 + .../LanguageSourceAsset.cs.meta | 11 + .../Core/LanguageSource/LanguageSourceData.cs | 177 + .../LanguageSource/LanguageSourceData.cs.meta | 10 + .../LanguageSourceData_Assets.cs | 55 + .../LanguageSourceData_Assets.cs.meta | 10 + .../LanguageSourceData_Export_CSV.cs | 276 + .../LanguageSourceData_Export_CSV.cs.meta | 10 + .../LanguageSourceData_Export_Google.cs | 63 + .../LanguageSourceData_Export_Google.cs.meta | 10 + .../LanguageSourceData_Import_CSV.cs | 253 + .../LanguageSourceData_Import_CSV.cs.meta | 10 + .../LanguageSourceData_Import_Google.cs | 385 + .../LanguageSourceData_Import_Google.cs.meta | 10 + .../LanguageSourceData_Languages.cs | 335 + .../LanguageSourceData_Languages.cs.meta | 10 + .../LanguageSource/LanguageSourceData_Misc.cs | 67 + .../LanguageSourceData_Misc.cs.meta | 10 + .../LanguageSourceData_Terms.cs | 255 + .../LanguageSourceData_Terms.cs.meta | 10 + .../Localization/Core/LocalizationReader.cs | 243 + .../Core/LocalizationReader.cs.meta | 10 + .../Modules/Localization/Core/Localize.cs | 518 + .../Localization/Core/Localize.cs.meta | 10 + .../Localization/Core/LocalizeDropdown.cs | 111 + .../Core/LocalizeDropdown.cs.meta | 12 + .../Modules/Localization/Core/Manager.meta | 10 + .../Core/Manager/LocalizationManager.cs | 92 + .../Core/Manager/LocalizationManager.cs.meta | 10 + .../Manager/LocalizationManager_Language.cs | 348 + .../LocalizationManager_Language.cs.meta | 10 + .../Manager/LocalizationManager_Parameters.cs | 195 + .../LocalizationManager_Parameters.cs.meta | 10 + .../Core/Manager/LocalizationManager_RTL.cs | 70 + .../Manager/LocalizationManager_RTL.cs.meta | 10 + .../Manager/LocalizationManager_Sources.cs | 206 + .../LocalizationManager_Sources.cs.meta | 10 + .../LocalizationManager_SystemLanguage.cs | 44 + ...LocalizationManager_SystemLanguage.cs.meta | 10 + .../Manager/LocalizationManager_Targets.cs | 30 + .../LocalizationManager_Targets.cs.meta | 10 + .../LocalizationManager_Translation.cs | 225 + .../LocalizationManager_Translation.cs.meta | 10 + .../Modules/Localization/Core/Targets.meta | 9 + .../Core/Targets/ILocalizeTarget.cs | 36 + .../Core/Targets/ILocalizeTarget.cs.meta | 10 + .../Core/Targets/ILocalizeTargetDesc.cs | 41 + .../Core/Targets/ILocalizeTargetDesc.cs.meta | 10 + .../Targets/LocalizeTarget_2DToolKit_Label.cs | 66 + .../LocalizeTarget_2DToolKit_Label.cs.meta | 10 + .../LocalizeTarget_2DToolKit_Sprite.cs | 53 + .../LocalizeTarget_2DToolKit_Sprite.cs.meta | 10 + .../Core/Targets/LocalizeTarget_NGUI_Label.cs | 94 + .../Targets/LocalizeTarget_NGUI_Label.cs.meta | 10 + .../Targets/LocalizeTarget_NGUI_Sprite.cs | 65 + .../LocalizeTarget_NGUI_Sprite.cs.meta | 10 + .../Targets/LocalizeTarget_NGUI_Texture.cs | 41 + .../LocalizeTarget_NGUI_Texture.cs.meta | 10 + .../LocalizeTarget_SVGImporter_Image.cs | 42 + .../LocalizeTarget_SVGImporter_Image.cs.meta | 10 + .../LocalizeTarget_SVGImporter_Renderer.cs | 42 + ...ocalizeTarget_SVGImporter_Renderer.cs.meta | 10 + .../LocalizeTarget_TextMeshPro_Label.cs | 191 + .../LocalizeTarget_TextMeshPro_Label.cs.meta | 10 + .../LocalizeTarget_TextMeshPro_UGUI.cs | 98 + .../LocalizeTarget_TextMeshPro_UGUI.cs.meta | 10 + ...ocalizeTarget_UnityStandard_AudioSource.cs | 45 + ...zeTarget_UnityStandard_AudioSource.cs.meta | 10 + .../LocalizeTarget_UnityStandard_Child.cs | 51 + ...LocalizeTarget_UnityStandard_Child.cs.meta | 10 + ...calizeTarget_UnityStandard_MeshRenderer.cs | 80 + ...eTarget_UnityStandard_MeshRenderer.cs.meta | 13 + .../LocalizeTarget_UnityStandard_Prefab.cs | 96 + ...ocalizeTarget_UnityStandard_Prefab.cs.meta | 13 + ...lizeTarget_UnityStandard_SpriteRenderer.cs | 41 + ...arget_UnityStandard_SpriteRenderer.cs.meta | 10 + .../LocalizeTarget_UnityStandard_TextMesh.cs | 68 + ...alizeTarget_UnityStandard_TextMesh.cs.meta | 13 + ...ocalizeTarget_UnityStandard_VideoPlayer.cs | 33 + ...zeTarget_UnityStandard_VideoPlayer.cs.meta | 3 + .../Targets/LocalizeTarget_UnityUI_Image.cs | 53 + .../LocalizeTarget_UnityUI_Image.cs.meta | 10 + .../LocalizeTarget_UnityUI_RawImage.cs | 47 + .../LocalizeTarget_UnityUI_RawImage.cs.meta | 10 + .../Targets/LocalizeTarget_UnityUI_Text.cs | 111 + .../LocalizeTarget_UnityUI_Text.cs.meta | 10 + .../Modules/Localization/Core/TermData.cs | 150 + .../Localization/Core/TermData.cs.meta | 10 + .../Modules/Localization/Core/Utils.meta | 9 + .../Core/Utils/AutoChangeCultureInfo.cs | 13 + .../Core/Utils/AutoChangeCultureInfo.cs.meta | 12 + .../Core/Utils/CoroutineManager.cs | 53 + .../Core/Utils/CoroutineManager.cs.meta | 12 + .../Core/Utils/CustomLocalizeCallback.cs | 27 + .../Core/Utils/CustomLocalizeCallback.cs.meta | 13 + .../Localization/Core/Utils/HindiFixer.cs | 157 + .../Core/Utils/HindiFixer.cs.meta | 12 + .../Localization/Core/Utils/I2Utils.cs | 335 + .../Localization/Core/Utils/I2Utils.cs.meta | 13 + .../Core/Utils/LocalizationParamsManager.cs | 90 + .../Utils/LocalizationParamsManager.cs.meta | 10 + .../Core/Utils/LocalizedString.cs | 42 + .../Core/Utils/LocalizedString.cs.meta | 12 + .../Localization/Core/Utils/RTLFixer.cs | 971 ++ .../Localization/Core/Utils/RTLFixer.cs.meta | 12 + .../RegisterCallback_AllowSyncFromGoogle.cs | 27 + ...gisterCallback_AllowSyncFromGoogle.cs.meta | 3 + .../Core/Utils/RegisterGlobalParameters.cs | 28 + .../Utils/RegisterGlobalParameters.cs.meta | 8 + .../Core/Utils/ResourceManager.cs | 186 + .../Core/Utils/ResourceManager.cs.meta | 10 + .../Localization/Core/Utils/SetLanguage.cs | 27 + .../Core/Utils/SetLanguage.cs.meta | 10 + .../Core/Utils/SetLanguageDropdown.cs | 43 + .../Core/Utils/SetLanguageDropdown.cs.meta | 10 + .../Core/Utils/StringObfuscator.cs | 74 + .../Core/Utils/StringObfuscator.cs.meta | 10 + .../Localization/DefaultLocalizationHelper.cs | 133 + .../DefaultLocalizationHelper.cs.meta | 11 + .../Runtime/Modules/Localization/Language.cs | 263 + .../Modules/Localization/Language.cs.meta | 3 + .../Localization/LocalizationModule.cs | 313 + .../Localization/LocalizationModule.cs.meta | 11 + .../TEngine/Runtime/Modules/ModuleCore.meta | 3 + .../Runtime/Modules/ModuleCore/Module.cs | 18 + .../Runtime/Modules/ModuleCore/Module.cs.meta | 3 + .../Runtime/Modules/ModuleCore/ModuleImp.cs | 40 + .../Modules/ModuleCore/ModuleImp.cs.meta | 11 + .../Modules/ModuleCore/ModuleImpSystem.cs | 175 + .../ModuleCore/ModuleImpSystem.cs.meta | 3 + .../Modules/ModuleCore/ModuleSystem.cs | 141 + .../Modules/ModuleCore/ModuleSystem.cs.meta | 3 + .../Modules/ModuleCore/ShutdownType.cs | 23 + .../Modules/ModuleCore/ShutdownType.cs.meta | 3 + .../Runtime/Modules/ObjectPoolModule.meta | 8 + .../Modules/ObjectPoolModule/IObjectPool.cs | 211 + .../ObjectPoolModule/IObjectPool.cs.meta | 3 + .../ObjectPoolModule/IObjectPoolManager.cs | 744 + .../IObjectPoolManager.cs.meta | 3 + .../Modules/ObjectPoolModule/ObjectBase.cs | 164 + .../ObjectPoolModule/ObjectBase.cs.meta | 3 + .../Modules/ObjectPoolModule/ObjectInfo.cs | 73 + .../ObjectPoolModule/ObjectInfo.cs.meta | 3 + .../ObjectPoolModule/ObjectPoolBase.cs | 133 + .../ObjectPoolModule/ObjectPoolBase.cs.meta | 3 + .../ObjectPoolManager.Object.cs | 189 + .../ObjectPoolManager.Object.cs.meta | 3 + .../ObjectPoolManager.ObjectPool.cs | 602 + .../ObjectPoolManager.ObjectPool.cs.meta | 3 + .../ObjectPoolModule/ObjectPoolManager.cs | 1290 ++ .../ObjectPoolManager.cs.meta | 3 + .../ObjectPoolModule/ObjectPoolModule.cs | 1015 ++ .../ObjectPoolModule/ObjectPoolModule.cs.meta | 3 + .../ReleaseObjectFilterCallback.cs | 15 + .../ReleaseObjectFilterCallback.cs.meta | 3 + .../Runtime/Modules/ProcedureModule.meta | 8 + .../ProcedureModule/IProcedureManager.cs | 73 + .../ProcedureModule/IProcedureManager.cs.meta | 3 + .../Modules/ProcedureModule/ProcedureBase.cs | 58 + .../ProcedureModule/ProcedureBase.cs.meta | 3 + .../ProcedureModule/ProcedureManager.cs | 190 + .../ProcedureModule/ProcedureManager.cs.meta | 3 + .../ProcedureModule/ProcedureModule.cs | 173 + .../ProcedureModule/ProcedureModule.cs.meta | 3 + .../Runtime/Modules/ResourceModule.meta | 8 + .../ResourceModule/BuildinFileManifest.cs | 22 + .../BuildinFileManifest.cs.meta | 3 + .../Modules/ResourceModule/Callback.meta | 3 + .../Callback/LoadAssetCallbacks.cs | 92 + .../Callback/LoadAssetCallbacks.cs.meta | 11 + .../Callback/LoadAssetFailureCallback.cs | 11 + .../Callback/LoadAssetFailureCallback.cs.meta | 3 + .../Callback/LoadAssetSuccessCallback.cs | 11 + .../Callback/LoadAssetSuccessCallback.cs.meta | 3 + .../Callback/LoadAssetUpdateCallback.cs | 10 + .../Callback/LoadAssetUpdateCallback.cs.meta | 3 + .../Callback/LoadResourceStatus.cs | 38 + .../Callback/LoadResourceStatus.cs.meta | 3 + .../Callback/LoadSceneCallbacks.cs | 92 + .../Callback/LoadSceneCallbacks.cs.meta | 3 + .../Callback/LoadSceneFailureCallback.cs | 11 + .../Callback/LoadSceneFailureCallback.cs.meta | 3 + .../Callback/LoadSceneSuccessCallback.cs | 11 + .../Callback/LoadSceneSuccessCallback.cs.meta | 3 + .../Callback/LoadSceneUpdateCallback.cs | 10 + .../Callback/LoadSceneUpdateCallback.cs.meta | 3 + .../Callback/UnloadSceneCallbacks.cs | 58 + .../Callback/UnloadSceneCallbacks.cs.meta | 3 + .../Callback/UnloadSceneFailureCallback.cs | 9 + .../UnloadSceneFailureCallback.cs.meta | 3 + .../Callback/UnloadSceneSuccessCallback.cs | 9 + .../UnloadSceneSuccessCallback.cs.meta | 3 + .../Modules/ResourceModule/Extension.meta | 3 + .../Extension/AssetItemObject.cs | 21 + .../Extension/AssetItemObject.cs.meta | 3 + .../Extension/ISetAssetObject.cs | 22 + .../Extension/ISetAssetObject.cs.meta | 3 + .../ResourceModule/Extension/Implement.meta | 3 + .../Implement/SetSpriteExtensions.cs | 27 + .../Implement/SetSpriteExtensions.cs.meta | 3 + .../Extension/Implement/SetSpriteObject.cs | 106 + .../Implement/SetSpriteObject.cs.meta | 3 + .../Extension/LoadAssetObject.cs | 28 + .../Extension/LoadAssetObject.cs.meta | 3 + .../ResourceExtComponent.Resource.cs | 62 + .../ResourceExtComponent.Resource.cs.meta | 3 + .../Extension/ResourceExtComponent.cs | 144 + .../Extension/ResourceExtComponent.cs.meta | 3 + .../Modules/ResourceModule/HasAssetResult.cs | 43 + .../ResourceModule/HasAssetResult.cs.meta | 3 + .../ResourceModule/IResourceManager.cs | 271 + .../ResourceModule/IResourceManager.cs.meta | 3 + .../ResourceModule/ReadWritePathType.cs | 23 + .../ResourceModule/ReadWritePathType.cs.meta | 3 + .../Modules/ResourceModule/Reference.meta | 3 + .../Reference/AssetsReference.cs | 137 + .../Reference/AssetsReference.cs.meta | 3 + .../Reference/AssetsSetHelper.cs | 150 + .../Reference/AssetsSetHelper.cs.meta | 3 + .../Modules/ResourceModule/ResourceLogger.cs | 25 + .../ResourceModule/ResourceLogger.cs.meta | 3 + .../ResourceManager.AssetObject.cs | 66 + .../ResourceManager.AssetObject.cs.meta | 3 + .../ResourceModule/ResourceManager.Pool.cs | 68 + .../ResourceManager.Pool.cs.meta | 3 + .../ResourceManager.Services.cs | 297 + .../ResourceManager.Services.cs.meta | 3 + .../Modules/ResourceModule/ResourceManager.cs | 976 ++ .../ResourceModule/ResourceManager.cs.meta | 3 + .../Modules/ResourceModule/ResourceModule.cs | 713 + .../ResourceModule/ResourceModule.cs.meta | 11 + .../TEngine/Runtime/Modules/RootModule.cs | 316 + .../Runtime/Modules/RootModule.cs.meta | 3 + .../TEngine/Runtime/Modules/SceneModule.meta | 3 + .../Modules/SceneModule/ISceneModule.cs | 67 + .../Modules/SceneModule/ISceneModule.cs.meta | 3 + .../Modules/SceneModule/SceneModule.cs | 117 + .../Modules/SceneModule/SceneModule.cs.meta | 3 + .../Modules/SceneModule/SceneModuleImp.cs | 232 + .../SceneModule/SceneModuleImp.cs.meta | 3 + .../Runtime/Modules/SettingModule.meta | 8 + .../Modules/SettingModule/DefaultSetting.cs | 305 + .../SettingModule/DefaultSetting.cs.meta | 3 + .../SettingModule/DefaultSettingHelper.cs | 355 + .../DefaultSettingHelper.cs.meta | 3 + .../SettingModule/DefaultSettingSerializer.cs | 26 + .../DefaultSettingSerializer.cs.meta | 3 + .../Modules/SettingModule/ISettingHelper.cs | 199 + .../SettingModule/ISettingHelper.cs.meta | 3 + .../Modules/SettingModule/ISettingManager.cs | 205 + .../SettingModule/ISettingManager.cs.meta | 3 + .../SettingModule/PlayerPrefsSettingHelper.cs | 304 + .../PlayerPrefsSettingHelper.cs.meta | 3 + .../SettingModule/SettingHelperBase.cs | 200 + .../SettingModule/SettingHelperBase.cs.meta | 3 + .../Modules/SettingModule/SettingManager.cs | 558 + .../SettingModule/SettingManager.cs.meta | 3 + .../Modules/SettingModule/SettingModule.cs | 318 + .../SettingModule/SettingModule.cs.meta | 3 + .../TEngine/Runtime/Modules/TimerModule.meta | 3 + .../Modules/TimerModule/GameTimerTick.cs | 60 + .../Modules/TimerModule/GameTimerTick.cs.meta | 3 + .../Modules/TimerModule/TimerManager.cs | 465 + .../Modules/TimerModule/TimerManager.cs.meta | 3 + .../Modules/TimerModule/TimerModule.cs | 170 + .../Modules/TimerModule/TimerModule.cs.meta | 3 + .../TEngine/Runtime/Modules/UIModule.meta | 8 + .../UIModule/ComponentAutoBindTool.meta | 3 + .../ComponentAutoBindTool.cs | 81 + .../ComponentAutoBindTool.cs.meta | 11 + .../DefaultAutoBindRuleHelper.cs | 77 + .../DefaultAutoBindRuleHelper.cs.meta | 3 + .../IAutoBindRuleHelper.cs | 13 + .../IAutoBindRuleHelper.cs.meta | 3 + .../UIAutoBindRuleHelper.cs | 31 + .../UIAutoBindRuleHelper.cs.meta | 3 + .../Runtime/Modules/UIModule/ErrorLogger.meta | 3 + .../UIModule/ErrorLogger/ErrorLogger.cs | 27 + .../UIModule/ErrorLogger/ErrorLogger.cs.meta | 3 + .../Modules/UIModule/ErrorLogger/LogUI.cs | 50 + .../UIModule/ErrorLogger/LogUI.cs.meta | 3 + .../Runtime/Modules/UIModule/Resources.meta | 8 + .../Modules/UIModule/Resources/LogUI.prefab | 358 + .../UIModule/Resources/LogUI.prefab.meta | 7 + .../Runtime/Modules/UIModule/UIBase.cs | 545 + .../Runtime/Modules/UIModule/UIBase.cs.meta | 3 + .../Runtime/Modules/UIModule/UIModule.cs | 700 + .../Runtime/Modules/UIModule/UIModule.cs.meta | 3 + .../Runtime/Modules/UIModule/UIWidget.cs | 317 + .../Runtime/Modules/UIModule/UIWidget.cs.meta | 3 + .../Runtime/Modules/UIModule/UIWindow.cs | 457 + .../Runtime/Modules/UIModule/UIWindow.cs.meta | 3 + .../Modules/UIModule/WindowAttribute.cs | 75 + .../Modules/UIModule/WindowAttribute.cs.meta | 3 + .../TEngine/Runtime/TEngine.Runtime.asmdef | 20 + .../Runtime/TEngine.Runtime.asmdef.meta | 7 + EintooAR/Assets/TEngine/package.json | 23 + EintooAR/Assets/TEngine/package.json.meta | 7 + EintooAR/Assets/TextMesh Pro.meta | 8 + EintooAR/Assets/TextMesh Pro/Fonts.meta | 8 + .../Fonts/LiberationSans - OFL.txt | 46 + .../Fonts/LiberationSans - OFL.txt.meta | 8 + .../TextMesh Pro/Fonts/LiberationSans.ttf | Bin 0 -> 350200 bytes .../Fonts/LiberationSans.ttf.meta | 19 + EintooAR/Assets/TextMesh Pro/Resources.meta | 8 + .../Resources/Fonts & Materials.meta | 9 + .../LiberationSans SDF - Drop Shadow.mat | 106 + .../LiberationSans SDF - Drop Shadow.mat.meta | 8 + .../LiberationSans SDF - Fallback.asset | 454 + .../LiberationSans SDF - Fallback.asset.meta | 8 + .../LiberationSans SDF - Outline.mat | 104 + .../LiberationSans SDF - Outline.mat.meta | 8 + .../LiberationSans SDF.asset | 7821 ++++++++++ .../LiberationSans SDF.asset.meta | 8 + .../LineBreaking Following Characters.txt | 1 + ...LineBreaking Following Characters.txt.meta | 8 + .../LineBreaking Leading Characters.txt | 1 + .../LineBreaking Leading Characters.txt.meta | 8 + .../TextMesh Pro/Resources/Sprite Assets.meta | 9 + .../Resources/Sprite Assets/EmojiOne.asset | 659 + .../Sprite Assets/EmojiOne.asset.meta | 8 + .../TextMesh Pro/Resources/Style Sheets.meta | 9 + .../Style Sheets/Default Style Sheet.asset | 81 + .../Default Style Sheet.asset.meta | 8 + .../TextMesh Pro/Resources/TMP Settings.asset | 52 + .../Resources/TMP Settings.asset.meta | 8 + EintooAR/Assets/TextMesh Pro/Shaders.meta | 8 + .../TextMesh Pro/Shaders/SDFFunctions.hlsl | 178 + .../Shaders/SDFFunctions.hlsl.meta | 10 + .../Shaders/TMP_Bitmap-Custom-Atlas.shader | 145 + .../TMP_Bitmap-Custom-Atlas.shader.meta | 9 + .../Shaders/TMP_Bitmap-Mobile.shader | 155 + .../Shaders/TMP_Bitmap-Mobile.shader.meta | 9 + .../TextMesh Pro/Shaders/TMP_Bitmap.shader | 145 + .../Shaders/TMP_Bitmap.shader.meta | 9 + .../Shaders/TMP_SDF Overlay.shader | 326 + .../Shaders/TMP_SDF Overlay.shader.meta | 9 + .../TextMesh Pro/Shaders/TMP_SDF SSD.shader | 321 + .../Shaders/TMP_SDF SSD.shader.meta | 9 + .../Shaders/TMP_SDF-HDRP LIT.shadergraph | 12074 ++++++++++++++++ .../Shaders/TMP_SDF-HDRP LIT.shadergraph.meta | 10 + .../Shaders/TMP_SDF-HDRP UNLIT.shadergraph | 11759 +++++++++++++++ .../TMP_SDF-HDRP UNLIT.shadergraph.meta | 10 + .../Shaders/TMP_SDF-Mobile Masking.shader | 258 + .../TMP_SDF-Mobile Masking.shader.meta | 9 + .../Shaders/TMP_SDF-Mobile Overlay.shader | 252 + .../TMP_SDF-Mobile Overlay.shader.meta | 9 + .../Shaders/TMP_SDF-Mobile SSD.shader | 106 + .../Shaders/TMP_SDF-Mobile SSD.shader.meta | 9 + .../Shaders/TMP_SDF-Mobile-2-Pass.shader | 389 + .../Shaders/TMP_SDF-Mobile-2-Pass.shader.meta | 9 + .../Shaders/TMP_SDF-Mobile.shader | 250 + .../Shaders/TMP_SDF-Mobile.shader.meta | 9 + .../Shaders/TMP_SDF-Surface-Mobile.shader | 139 + .../TMP_SDF-Surface-Mobile.shader.meta | 9 + .../Shaders/TMP_SDF-Surface.shader | 159 + .../Shaders/TMP_SDF-Surface.shader.meta | 9 + .../Shaders/TMP_SDF-URP Lit.shadergraph | 11932 +++++++++++++++ .../Shaders/TMP_SDF-URP Lit.shadergraph.meta | 10 + .../Shaders/TMP_SDF-URP Unlit.shadergraph | 11629 +++++++++++++++ .../TMP_SDF-URP Unlit.shadergraph.meta | 10 + .../TextMesh Pro/Shaders/TMP_SDF.shader | 326 + .../TextMesh Pro/Shaders/TMP_SDF.shader.meta | 9 + .../TextMesh Pro/Shaders/TMP_Sprite.shader | 131 + .../Shaders/TMP_Sprite.shader.meta | 9 + .../Assets/TextMesh Pro/Shaders/TMPro.cginc | 84 + .../TextMesh Pro/Shaders/TMPro.cginc.meta | 9 + .../TextMesh Pro/Shaders/TMPro_Mobile.cginc | 165 + .../Shaders/TMPro_Mobile.cginc.meta | 9 + .../Shaders/TMPro_Properties.cginc | 80 + .../Shaders/TMPro_Properties.cginc.meta | 9 + .../TextMesh Pro/Shaders/TMPro_Surface.cginc | 99 + .../Shaders/TMPro_Surface.cginc.meta | 9 + EintooAR/Assets/TextMesh Pro/Sprites.meta | 8 + .../Sprites/EmojiOne Attribution.txt | 3 + .../Sprites/EmojiOne Attribution.txt.meta | 7 + .../Assets/TextMesh Pro/Sprites/EmojiOne.json | 156 + .../TextMesh Pro/Sprites/EmojiOne.json.meta | 8 + .../Assets/TextMesh Pro/Sprites/EmojiOne.png | Bin 0 -> 112319 bytes .../TextMesh Pro/Sprites/EmojiOne.png.meta | 431 + ...niversalRenderPipelineGlobalSettings.asset | 248 + ...salRenderPipelineGlobalSettings.asset.meta | 8 + 897 files changed, 132361 insertions(+) create mode 100644 EintooAR/Assets/Animancer Settings.asset create mode 100644 EintooAR/Assets/Animancer Settings.asset.meta create mode 100644 EintooAR/Assets/AssetArt.meta create mode 100644 EintooAR/Assets/AssetRaw.meta create mode 100644 EintooAR/Assets/DefaultVolumeProfile.asset create mode 100644 EintooAR/Assets/DefaultVolumeProfile.asset.meta create mode 100644 EintooAR/Assets/Editor.meta create mode 100644 EintooAR/Assets/GameScripts.meta create mode 100644 EintooAR/Assets/Plugins.meta create mode 100644 EintooAR/Assets/Resources.meta create mode 100644 EintooAR/Assets/Scenes.meta create mode 100644 EintooAR/Assets/StreamingAssets.meta create mode 100644 EintooAR/Assets/TEngine.meta create mode 100644 EintooAR/Assets/TEngine/AssetSetting.meta create mode 100644 EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorConfig.xml create mode 100644 EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorConfig.xml.meta create mode 100644 EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorSetting.asset create mode 100644 EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorSetting.asset.meta create mode 100644 EintooAR/Assets/TEngine/AssetSetting/Resources.meta create mode 100644 EintooAR/Assets/TEngine/AssetSetting/Resources/YooAssetSettings.asset create mode 100644 EintooAR/Assets/TEngine/AssetSetting/Resources/YooAssetSettings.asset.meta create mode 100644 EintooAR/Assets/TEngine/Editor.meta create mode 100644 EintooAR/Assets/TEngine/Editor/DefineSymbols.meta create mode 100644 EintooAR/Assets/TEngine/Editor/DefineSymbols/LogScriptingDefineSymbols.cs create mode 100644 EintooAR/Assets/TEngine/Editor/DefineSymbols/LogScriptingDefineSymbols.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/DefineSymbols/ProfilerDefineSymbols.cs create mode 100644 EintooAR/Assets/TEngine/Editor/DefineSymbols/ProfilerDefineSymbols.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/DefineSymbols/ScriptingDefineSymbols.cs create mode 100644 EintooAR/Assets/TEngine/Editor/DefineSymbols/ScriptingDefineSymbols.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/EditorTools.meta create mode 100644 EintooAR/Assets/TEngine/Editor/EditorTools/LubanTools.cs create mode 100644 EintooAR/Assets/TEngine/Editor/EditorTools/LubanTools.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/EventInterface.meta create mode 100644 EintooAR/Assets/TEngine/Editor/EventInterface/EventInterfaceGenerate.cs create mode 100644 EintooAR/Assets/TEngine/Editor/EventInterface/EventInterfaceGenerate.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/GameSettings.meta create mode 100644 EintooAR/Assets/TEngine/Editor/GameSettings/SettingsMenu.cs create mode 100644 EintooAR/Assets/TEngine/Editor/GameSettings/SettingsMenu.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/GameSettings/SynAssemblysContent.cs create mode 100644 EintooAR/Assets/TEngine/Editor/GameSettings/SynAssemblysContent.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/GameSettings/TEngineSettingsProvider.cs create mode 100644 EintooAR/Assets/TEngine/Editor/GameSettings/TEngineSettingsProvider.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/HybridCLR.meta create mode 100644 EintooAR/Assets/TEngine/Editor/HybridCLR/BuildDLLCommand.cs create mode 100644 EintooAR/Assets/TEngine/Editor/HybridCLR/BuildDLLCommand.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/Asset.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/Asset/DefaultAssetInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/Asset/DefaultAssetInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/Asset/TextAssetInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/Asset/TextAssetInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/AudioModuleInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/AudioModuleInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/Core.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/Core/GameFrameworkInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/Core/GameFrameworkInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/FsmComponentInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/FsmComponentInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/MemoryPoolModuleInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/MemoryPoolModuleInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/ObjectPoolModuleInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/ObjectPoolModuleInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/ProcedureModuleInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/ProcedureModuleInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/ResourceModuleInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/ResourceModuleInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/RootModuleInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/RootModuleInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/SettingModuleInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/SettingModuleInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/UIModuleInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Inspector/UIModuleInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/EditorTools.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/EditorTools.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceAssetInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceAssetInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationEditor.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationEditor.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationParamsManagerInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationParamsManagerInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeDropdownInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeDropdownInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/ResourceManagerInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/ResourceManagerInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/SetLanguageInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/SetLanguageInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/TermsPopup_Drawer.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Inspectors/TermsPopup_Drawer.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Languages.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Languages.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Google.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Google.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Local.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Local.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms_Description.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms_Description.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Categorize.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Categorize.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_CharSet.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_CharSet.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_MergeTerms.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_MergeTerms.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_NoLocalized.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_NoLocalized.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_ParseTerms.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_ParseTerms.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Scenes.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Scenes.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Script.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Script.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Warnings.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Warnings.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_ANDROID.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_ANDROID.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_IOS.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_IOS.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_UnloadLanguages.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_UnloadLanguages.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Unity XCode.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Unity XCode/UnityEditor.iOS_I2Loc.Xcode.dll create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Unity XCode/UnityEditor.iOS_I2Loc.Xcode.dll.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Unity XCode/Xcode.txt create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/Unity XCode/Xcode.txt.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/UpgradeManager.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Localization/UpgradeManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Postprocessor.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ReleaseTools.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ReleaseTools/ReleaseTools.cs create mode 100644 EintooAR/Assets/TEngine/Editor/ReleaseTools/ReleaseTools.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Resource.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Resource/Encryption.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Resource/Encryption.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Resource/ExtensionFilterRule.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Resource/ExtensionFilterRule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/TEngine.Editor.asmdef create mode 100644 EintooAR/Assets/TEngine/Editor/TEngine.Editor.asmdef.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/EditorResourceMode.cs create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/EditorResourceMode.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/SceneSwitcher.cs create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/SceneSwitcher.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarCallback.cs create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarExtender.cs create mode 100644 EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarExtender.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/UI.meta create mode 100644 EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool.meta create mode 100644 EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSetting.cs create mode 100644 EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSetting.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSettingInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSettingInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/ComponentAutoBindToolInspector.cs create mode 100644 EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/ComponentAutoBindToolInspector.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/UI/ScriptGenerator.cs create mode 100644 EintooAR/Assets/TEngine/Editor/UI/ScriptGenerator.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/UI/TEUIHelper.cs create mode 100644 EintooAR/Assets/TEngine/Editor/UI/TEUIHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/UI/TEUIHelperWindiw.cs create mode 100644 EintooAR/Assets/TEngine/Editor/UI/TEUIHelperWindiw.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Utility.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/ClassHelper.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/ClassHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/CommandLineReader.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/CommandLineReader.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/GetAssetHelper.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/GetAssetHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/HelperInfo.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/HelperInfo.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/LogRedirection.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/LogRedirection.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/OpenFolderHelper.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/OpenFolderHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/ShellHelper.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/ShellHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/Type.cs create mode 100644 EintooAR/Assets/TEngine/Editor/Utility/Type.cs.meta create mode 100644 EintooAR/Assets/TEngine/ResRaw.meta create mode 100644 EintooAR/Assets/TEngine/ResRaw/AutoBindGlobalSetting.asset create mode 100644 EintooAR/Assets/TEngine/ResRaw/AutoBindGlobalSetting.asset.meta create mode 100644 EintooAR/Assets/TEngine/ResRaw/Resources.meta create mode 100644 EintooAR/Assets/TEngine/ResRaw/Resources/TEngineGlobalSettings.asset create mode 100644 EintooAR/Assets/TEngine/ResRaw/Resources/TEngineGlobalSettings.asset.meta create mode 100644 EintooAR/Assets/TEngine/Runtime.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Constant.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Constant/Constant.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Constant/Constant.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkDictionary.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkDictionary.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedList.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedList.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedListRange.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedListRange.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkMultiDictionary.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkMultiDictionary.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkSerializer.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkSerializer.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/SerializableDictionary.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/SerializableDictionary.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/TypeNamePair.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/DataStruct/TypeNamePair.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Exception.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Exception/GameFrameworkException.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Exception/GameFrameworkException.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/ActorEventDispatcher.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/ActorEventDispatcher.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDelegateData.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDelegateData.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDispatcher.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDispatcher.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventInterfaceAttribute.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventInterfaceAttribute.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventMgr.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventMgr.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEvent.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEvent.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/RuntimeId.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameEvent/RuntimeId.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/AppStageEnum.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/AppStageEnum.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/ServerTypeEnum.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/ServerTypeEnum.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework/FrameworkGlobalSettings.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework/FrameworkGlobalSettings.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR/HybridCLRCustomGlobalSettings.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR/HybridCLRCustomGlobalSettings.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/SettingsUtils.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/SettingsUtils.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/TEngineSettings.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameSettings/TEngineSettings.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameTime.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameTime/GameTime.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/GameTime/GameTime.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Log.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.ILogHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.ILogHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLogLevel.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLogLevel.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Log/Log.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Log/Log.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/IMemory.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/IMemory.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolExtension.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolExtension.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolInfo.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolInfo.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Profiler.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Profiler/TProfiler.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Profiler/TProfiler.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultJsonHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultJsonHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultLogHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultLogHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultTextHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultTextHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultVersionHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultVersionHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/UnityJsonHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/UnityJsonHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Assembly.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Assembly.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Converter.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Converter.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Encryption.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Encryption.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.File.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.File.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Http.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Http.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.IJsonHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.IJsonHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Marshal.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Marshal.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Path.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Path.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Reflection.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Reflection.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.ITextHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.ITextHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Unity.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Unity.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Version.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Version/Version.IVersionHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Version/Version.IVersionHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Version/Version.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Core/Version/Version.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/BinaryExtension.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/BinaryExtension.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/StringBuilderCache.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/StringBuilderCache.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/EmptyGraph.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/EmptyGraph.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/DragHandler.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/DragHandler.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/EventTriggerListener.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/EventTriggerListener.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/ImageBackGroundStretch.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/ImageBackGroundStretch.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/PointerLongPress.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/PointerLongPress.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/SafeTop.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/SafeTop.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/UIButtonScale.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/UIButtonScale.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper/UIButtonSuper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper/UIButtonSuper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIExtension.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIExtension.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UnityExtension.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Extension/UnityExtension.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Libraries.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Libraries/System.Runtime.CompilerServices.Unsafe.dll create mode 100644 EintooAR/Assets/TEngine/Runtime/Libraries/System.Runtime.CompilerServices.Unsafe.dll.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgent.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgent.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgentRuntimeState.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgentRuntimeState.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioCategory.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioCategory.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioGroupConfig.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioGroupConfig.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModuleImp.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModuleImp.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioType.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioType.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/IAudioModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/IAudioModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources/AudioMixer.mixer create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources/AudioMixer.mixer.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.EnvironmentInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.EnvironmentInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.GraphicsInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.GraphicsInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputAccelerationInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputAccelerationInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputCompassInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputCompassInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputGyroscopeInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputGyroscopeInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputLocationInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputLocationInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputSummaryInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputSummaryInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputTouchInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputTouchInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.LogNode.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.LogNode.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.MemoryPoolInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.MemoryPoolInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.NetworkInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.NetworkInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ObjectPoolInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ObjectPoolInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.OperationsWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.OperationsWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.PathInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.PathInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ProfilerInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ProfilerInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.QualityInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.QualityInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.Sample.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.Sample.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.Record.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.Record.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SceneInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SceneInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScreenInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScreenInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScrollableDebuggerWindowBase.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScrollableDebuggerWindowBase.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SettingsWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SettingsWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SystemInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SystemInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.TimeInformationWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.TimeInformationWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerActiveWindowType.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerActiveWindowType.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.ConsoleWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.ConsoleWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.FpsCounter.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.FpsCounter.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.DebuggerWindowGroup.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.DebuggerWindowGroup.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerSkin.guiskin create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerSkin.guiskin.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindowGroup.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindowGroup.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/SkipUnityLogo.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/SkipUnityLogo.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/Fsm.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/Fsm.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmBase.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmBase.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmState.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmState.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsm.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsm.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsmManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsmManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/GameModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/GameModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Helper.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Helper/Helper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Helper/Helper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables/PersistentStorage.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables/PersistentStorage.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables/SpecializationManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables/SpecializationManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/EventCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/EventCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Extension.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Extension/RealTimeTranslation.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Extension/RealTimeTranslation.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleLanguages.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleLanguages.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Post.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Post.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Queries.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Queries.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/SimpleJSON.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/SimpleJSON.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_GET.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_GET.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_Main.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_Main.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_POST.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_POST.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_WEB.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_WEB.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageData.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageData.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSource.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSource.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceAsset.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceAsset.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Assets.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Assets.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_CSV.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_CSV.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_Google.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_Google.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_CSV.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_CSV.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_Google.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_Google.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Languages.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Languages.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Misc.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Misc.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Terms.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Terms.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizationReader.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizationReader.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Localize.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Localize.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizeDropdown.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizeDropdown.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Language.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Language.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Parameters.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Parameters.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_RTL.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_RTL.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Sources.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Sources.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_SystemLanguage.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_SystemLanguage.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Targets.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Targets.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Translation.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Translation.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTarget.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTarget.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTargetDesc.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTargetDesc.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Label.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Label.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Sprite.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Sprite.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Label.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Label.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Sprite.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Sprite.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Texture.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Texture.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Image.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Image.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Renderer.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Renderer.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_Label.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_Label.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_UGUI.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_UGUI.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_AudioSource.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_AudioSource.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Child.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Child.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_MeshRenderer.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_MeshRenderer.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Prefab.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Prefab.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_SpriteRenderer.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_SpriteRenderer.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_TextMesh.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_TextMesh.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_VideoPlayer.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_VideoPlayer.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Image.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Image.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_RawImage.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_RawImage.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Text.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Text.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/TermData.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/TermData.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/AutoChangeCultureInfo.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/AutoChangeCultureInfo.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CoroutineManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CoroutineManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CustomLocalizeCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CustomLocalizeCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/HindiFixer.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/HindiFixer.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/I2Utils.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/I2Utils.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizationParamsManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizationParamsManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizedString.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizedString.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RTLFixer.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RTLFixer.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterCallback_AllowSyncFromGoogle.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterCallback_AllowSyncFromGoogle.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterGlobalParameters.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterGlobalParameters.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/ResourceManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/ResourceManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguage.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguage.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguageDropdown.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguageDropdown.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/StringObfuscator.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/StringObfuscator.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/DefaultLocalizationHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/DefaultLocalizationHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Language.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/Language.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/LocalizationModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/Localization/LocalizationModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/Module.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/Module.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImp.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImp.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImpSystem.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImpSystem.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleSystem.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleSystem.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ShutdownType.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ShutdownType.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPool.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPool.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPoolManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPoolManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectBase.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectBase.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectInfo.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectInfo.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolBase.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolBase.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.Object.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.Object.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.ObjectPool.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.ObjectPool.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ReleaseObjectFilterCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ReleaseObjectFilterCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/IProcedureManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/IProcedureManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureBase.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureBase.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/BuildinFileManifest.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/BuildinFileManifest.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetCallbacks.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetCallbacks.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetFailureCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetFailureCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetSuccessCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetSuccessCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetUpdateCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetUpdateCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadResourceStatus.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadResourceStatus.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneCallbacks.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneCallbacks.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneFailureCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneFailureCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneSuccessCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneSuccessCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneUpdateCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneUpdateCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneCallbacks.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneCallbacks.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneFailureCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneFailureCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneSuccessCallback.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneSuccessCallback.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/AssetItemObject.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/AssetItemObject.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ISetAssetObject.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ISetAssetObject.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteExtensions.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteExtensions.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteObject.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteObject.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/LoadAssetObject.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/LoadAssetObject.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.Resource.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.Resource.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/HasAssetResult.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/HasAssetResult.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ReadWritePathType.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ReadWritePathType.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsReference.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsReference.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsSetHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsSetHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceLogger.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceLogger.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.AssetObject.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.AssetObject.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Pool.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Pool.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Services.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Services.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/RootModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/RootModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SceneModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/ISceneModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/ISceneModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModuleImp.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModuleImp.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSetting.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSetting.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingSerializer.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingSerializer.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/PlayerPrefsSettingHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/PlayerPrefsSettingHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingHelperBase.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingHelperBase.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/TimerModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/GameTimerTick.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/GameTimerTick.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/ComponentAutoBindTool.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/ComponentAutoBindTool.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/DefaultAutoBindRuleHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/DefaultAutoBindRuleHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/IAutoBindRuleHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/IAutoBindRuleHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/UIAutoBindRuleHelper.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/UIAutoBindRuleHelper.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/ErrorLogger.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/ErrorLogger.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/LogUI.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/LogUI.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/Resources.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/Resources/LogUI.prefab create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/Resources/LogUI.prefab.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/UIBase.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/UIBase.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/UIModule.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/UIModule.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/UIWidget.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/UIWidget.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/UIWindow.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/UIWindow.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/WindowAttribute.cs create mode 100644 EintooAR/Assets/TEngine/Runtime/Modules/UIModule/WindowAttribute.cs.meta create mode 100644 EintooAR/Assets/TEngine/Runtime/TEngine.Runtime.asmdef create mode 100644 EintooAR/Assets/TEngine/Runtime/TEngine.Runtime.asmdef.meta create mode 100644 EintooAR/Assets/TEngine/package.json create mode 100644 EintooAR/Assets/TEngine/package.json.meta create mode 100644 EintooAR/Assets/TextMesh Pro.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Fonts.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Fonts/LiberationSans - OFL.txt create mode 100644 EintooAR/Assets/TextMesh Pro/Fonts/LiberationSans - OFL.txt.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Fonts/LiberationSans.ttf create mode 100644 EintooAR/Assets/TextMesh Pro/Fonts/LiberationSans.ttf.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Fonts & Materials.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Drop Shadow.mat create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Drop Shadow.mat.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Outline.mat create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Outline.mat.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/LineBreaking Following Characters.txt create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/LineBreaking Following Characters.txt.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/LineBreaking Leading Characters.txt create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/LineBreaking Leading Characters.txt.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Sprite Assets.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Sprite Assets/EmojiOne.asset create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Sprite Assets/EmojiOne.asset.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Style Sheets.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Style Sheets/Default Style Sheet.asset create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/Style Sheets/Default Style Sheet.asset.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/TMP Settings.asset create mode 100644 EintooAR/Assets/TextMesh Pro/Resources/TMP Settings.asset.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/SDFFunctions.hlsl create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/SDFFunctions.hlsl.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_Bitmap-Custom-Atlas.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_Bitmap-Custom-Atlas.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_Bitmap-Mobile.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_Bitmap-Mobile.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_Bitmap.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_Bitmap.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF Overlay.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF Overlay.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF SSD.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF SSD.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-HDRP LIT.shadergraph create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-HDRP LIT.shadergraph.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-HDRP UNLIT.shadergraph create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-HDRP UNLIT.shadergraph.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile Masking.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile Masking.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile Overlay.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile Overlay.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile SSD.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile SSD.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile-2-Pass.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile-2-Pass.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Surface-Mobile.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Surface-Mobile.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Surface.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-Surface.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-URP Lit.shadergraph create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-URP Lit.shadergraph.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-URP Unlit.shadergraph create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF-URP Unlit.shadergraph.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_SDF.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_Sprite.shader create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMP_Sprite.shader.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMPro.cginc create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMPro.cginc.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMPro_Mobile.cginc create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMPro_Mobile.cginc.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMPro_Properties.cginc create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMPro_Properties.cginc.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMPro_Surface.cginc create mode 100644 EintooAR/Assets/TextMesh Pro/Shaders/TMPro_Surface.cginc.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Sprites.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Sprites/EmojiOne Attribution.txt create mode 100644 EintooAR/Assets/TextMesh Pro/Sprites/EmojiOne Attribution.txt.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Sprites/EmojiOne.json create mode 100644 EintooAR/Assets/TextMesh Pro/Sprites/EmojiOne.json.meta create mode 100644 EintooAR/Assets/TextMesh Pro/Sprites/EmojiOne.png create mode 100644 EintooAR/Assets/TextMesh Pro/Sprites/EmojiOne.png.meta create mode 100644 EintooAR/Assets/UniversalRenderPipelineGlobalSettings.asset create mode 100644 EintooAR/Assets/UniversalRenderPipelineGlobalSettings.asset.meta diff --git a/EintooAR/Assets/Animancer Settings.asset b/EintooAR/Assets/Animancer Settings.asset new file mode 100644 index 00000000..5634d4ad --- /dev/null +++ b/EintooAR/Assets/Animancer Settings.asset @@ -0,0 +1,61 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 16 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 18bd840b706853d4a934ec3199f63a41, type: 3} + m_Name: Animancer Settings + m_EditorClassIdentifier: + _Data: + - rid: 4686946972895019210 + - rid: 4686946972895019211 + - rid: 4686946972895019212 + - rid: 4686946972895019213 + - rid: 4686946972895019214 + - rid: 4686946972895019215 + references: + version: 2 + RefIds: + - rid: 4686946972895019210 + type: {class: AnimancerComponentPreviewSettings, ns: Animancer.Editor.Previews, asm: Kybernetik.Animancer.Editor} + data: + _RepaintRate: 30 + - rid: 4686946972895019211 + type: {class: AnimancerGraphControls, ns: Animancer.Editor, asm: Kybernetik.Animancer.Editor} + data: + _FrameStep: 0.02 + - rid: 4686946972895019212 + type: {class: TransitionPreviewSettings, ns: Animancer.Editor.Previews, asm: Kybernetik.Animancer.Editor} + data: + _AutoClose: 1 + _SceneLighting: 0 + _ShowSkybox: 0 + _FrameStep: 0.02 + _SceneEnvironment: {fileID: 0} + _Models: [] + - rid: 4686946972895019213 + type: {class: SerializableEventSequenceDrawerSettings, ns: Animancer.Editor, asm: Kybernetik.Animancer.Editor} + data: + _HideEventCallbacks: 0 + - rid: 4686946972895019214 + type: {class: AnimationTimeAttributeSettings, ns: Animancer.Units.Editor, asm: Kybernetik.Animancer.Editor} + data: + showApproximations: 1 + showNormalized: 1 + showSeconds: 1 + showFrames: 1 + - rid: 4686946972895019215 + type: {class: GenerateSpriteAnimationsSettings, ns: Animancer.Editor.Tools, asm: Kybernetik.Animancer.Editor} + data: + _FrameRate: 12 + _HierarchyPath: + _TargetType: + _QualifiedName: UnityEngine.SpriteRenderer, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + _PropertyName: m_Sprite diff --git a/EintooAR/Assets/Animancer Settings.asset.meta b/EintooAR/Assets/Animancer Settings.asset.meta new file mode 100644 index 00000000..4128e696 --- /dev/null +++ b/EintooAR/Assets/Animancer Settings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5fe825ea12eca744ab2410e203856c2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/AssetArt.meta b/EintooAR/Assets/AssetArt.meta new file mode 100644 index 00000000..ecd49c60 --- /dev/null +++ b/EintooAR/Assets/AssetArt.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ab86ad0f95d7fd438621794de0e0f95 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/AssetRaw.meta b/EintooAR/Assets/AssetRaw.meta new file mode 100644 index 00000000..bc0d5a69 --- /dev/null +++ b/EintooAR/Assets/AssetRaw.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8de5bf9d0c58b9042907faa7cfe9a7de +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/DefaultVolumeProfile.asset b/EintooAR/Assets/DefaultVolumeProfile.asset new file mode 100644 index 00000000..36c3781a --- /dev/null +++ b/EintooAR/Assets/DefaultVolumeProfile.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3} + m_Name: DefaultVolumeProfile + m_EditorClassIdentifier: + components: [] diff --git a/EintooAR/Assets/DefaultVolumeProfile.asset.meta b/EintooAR/Assets/DefaultVolumeProfile.asset.meta new file mode 100644 index 00000000..045ca8f3 --- /dev/null +++ b/EintooAR/Assets/DefaultVolumeProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 885a73187e1fd1746bed2b42b85ebfaa +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/Editor.meta b/EintooAR/Assets/Editor.meta new file mode 100644 index 00000000..a218c824 --- /dev/null +++ b/EintooAR/Assets/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b549395c8849674b9cafbbf4c694e57 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/GameScripts.meta b/EintooAR/Assets/GameScripts.meta new file mode 100644 index 00000000..cdeed4da --- /dev/null +++ b/EintooAR/Assets/GameScripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c3a047ecd3df324f8173b18e341b00c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/Plugins.meta b/EintooAR/Assets/Plugins.meta new file mode 100644 index 00000000..31f5e631 --- /dev/null +++ b/EintooAR/Assets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 96b331509cb4a2d4b8ee2e2231163061 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/Resources.meta b/EintooAR/Assets/Resources.meta new file mode 100644 index 00000000..3bd71238 --- /dev/null +++ b/EintooAR/Assets/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c9f44168256b58449b48c5beb13c07aa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/Scenes.meta b/EintooAR/Assets/Scenes.meta new file mode 100644 index 00000000..dac72239 --- /dev/null +++ b/EintooAR/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f46b2e8a7bdbd6e4cb5b2477d7bd38a4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/StreamingAssets.meta b/EintooAR/Assets/StreamingAssets.meta new file mode 100644 index 00000000..e8475155 --- /dev/null +++ b/EintooAR/Assets/StreamingAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1707a36949a8cc4d8a16aae67a41802 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine.meta b/EintooAR/Assets/TEngine.meta new file mode 100644 index 00000000..2e5c0ce3 --- /dev/null +++ b/EintooAR/Assets/TEngine.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e25f00a32f8e7ca4eaa2c45d3c20530f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/AssetSetting.meta b/EintooAR/Assets/TEngine/AssetSetting.meta new file mode 100644 index 00000000..8eddc302 --- /dev/null +++ b/EintooAR/Assets/TEngine/AssetSetting.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 99f69e470317dae4baa94d3f4d000253 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorConfig.xml b/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorConfig.xml new file mode 100644 index 00000000..8a611403 --- /dev/null +++ b/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorConfig.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorConfig.xml.meta b/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorConfig.xml.meta new file mode 100644 index 00000000..3ae38d6b --- /dev/null +++ b/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorConfig.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 218816e46e4f6304eaecd6fdc3a99f4d +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorSetting.asset b/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorSetting.asset new file mode 100644 index 00000000..32d26934 --- /dev/null +++ b/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorSetting.asset @@ -0,0 +1,203 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 185f6993d5150494d98da50e26cb1c25, type: 3} + m_Name: AssetBundleCollectorSetting + m_EditorClassIdentifier: + ShowPackageView: 0 + ShowEditorAlias: 0 + UniqueBundleName: 0 + Packages: + - PackageName: DefaultPackage + PackageDesc: "\u9ED8\u8BA4\u8D44\u6E90\u5305" + EnableAddressable: 1 + LocationToLower: 0 + IncludeAssetGUID: 0 + AutoCollectShaders: 1 + IgnoreRuleName: NormalIgnoreRule + Groups: + - GroupName: Actor + GroupDesc: "\u89D2\u8272" + AssetTags: Actor + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/Actor + CollectorGUID: 9c67ce0c9edfd4e4aa1006ee39846d66 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: UIRaw + GroupDesc: "\u56FE\u7247\u8D44\u6E90" + AssetTags: UIRaw + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/UIRaw/Atlas + CollectorGUID: 6d11fa91acc253840a648b58f23db139 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: + - CollectPath: Assets/AssetRaw/UIRaw/Raw + CollectorGUID: 6bc134b912ac6bb4399ea1bec4c11636 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: Audios + GroupDesc: "\u97F3\u9891" + AssetTags: Audios + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/Audios + CollectorGUID: 8ef7a411b66e70f4cb65c2233c9a0868 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: Configs + GroupDesc: "\u914D\u7F6E\u8868" + AssetTags: Configs + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/Configs + CollectorGUID: dd2928019aef34248af368b99bc53bea + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: WEBGL_PRELOAD + UserData: + - GroupName: DLL + GroupDesc: "\u4EE3\u7801" + AssetTags: DLL + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/DLL + CollectorGUID: 3aad79ec1ea08c24c891bd3c669d4125 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: Effects + GroupDesc: "\u7279\u6548" + AssetTags: Effects + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/Effects + CollectorGUID: 0fe175e1e1bd49a4ca71e66b6a9b7237 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: Materials + GroupDesc: "\u6750\u8D28\u7403" + AssetTags: Materials + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/Materials + CollectorGUID: 228b1547e7065d546ad0bf215fd6a276 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: Scenes + GroupDesc: "\u573A\u666F" + AssetTags: Scenes + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/Scenes + CollectorGUID: cace6ee6539f661419b5e5f8ae1c0146 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackSeparately + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: Shaders + GroupDesc: "\u7740\u8272\u5668" + AssetTags: Shaders + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/Shaders + CollectorGUID: 2a4bceb84ed685447ace957f497eb810 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackSeparately + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: UI + GroupDesc: "UI\u9762\u677F" + AssetTags: UI + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/UI + CollectorGUID: 27e87d83814156648b58f380b834e046 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackSeparately + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: Fonts + GroupDesc: "\u5B57\u4F53" + AssetTags: Fonts + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/Fonts + CollectorGUID: 2473375c9ee163a4b861278b38091455 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: ScriptableObject + GroupDesc: "\u5E8F\u5217\u5316\u8D44\u6E90" + AssetTags: + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/ScriptableObject + CollectorGUID: 1b58ac5eefb69124eb767cd325772350 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: + - GroupName: Animation + GroupDesc: "\u52A8\u753B" + AssetTags: + ActiveRuleName: EnableGroup + Collectors: + - CollectPath: Assets/AssetRaw/Animation + CollectorGUID: acc72186faad1b74db841ed9f4de45a1 + CollectorType: 0 + AddressRuleName: AddressByFileName + PackRuleName: PackDirectory + FilterRuleName: CollectAll + AssetTags: + UserData: diff --git a/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorSetting.asset.meta b/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorSetting.asset.meta new file mode 100644 index 00000000..b35e5acb --- /dev/null +++ b/EintooAR/Assets/TEngine/AssetSetting/AssetBundleCollectorSetting.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 007a65bdc7416fd4a8823ff50f753d50 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/AssetSetting/Resources.meta b/EintooAR/Assets/TEngine/AssetSetting/Resources.meta new file mode 100644 index 00000000..1c20db44 --- /dev/null +++ b/EintooAR/Assets/TEngine/AssetSetting/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5bee0ab9d1e77fa409a7ddf10bf7fa7f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/AssetSetting/Resources/YooAssetSettings.asset b/EintooAR/Assets/TEngine/AssetSetting/Resources/YooAssetSettings.asset new file mode 100644 index 00000000..a307713e --- /dev/null +++ b/EintooAR/Assets/TEngine/AssetSetting/Resources/YooAssetSettings.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5bd1afdce9715f84eb4cbc901922afc2, type: 3} + m_Name: YooAssetSettings + m_EditorClassIdentifier: + ManifestFileName: PackageManifest + DefaultYooFolderName: package diff --git a/EintooAR/Assets/TEngine/AssetSetting/Resources/YooAssetSettings.asset.meta b/EintooAR/Assets/TEngine/AssetSetting/Resources/YooAssetSettings.asset.meta new file mode 100644 index 00000000..3fc35863 --- /dev/null +++ b/EintooAR/Assets/TEngine/AssetSetting/Resources/YooAssetSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7637ee5d97b976b4ca47bcf91324aca5 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor.meta b/EintooAR/Assets/TEngine/Editor.meta new file mode 100644 index 00000000..c541d1eb --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2125a57c5434d7842a5f97624829667e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/DefineSymbols.meta b/EintooAR/Assets/TEngine/Editor/DefineSymbols.meta new file mode 100644 index 00000000..640b36a2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/DefineSymbols.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d9e289b71d5448498e7ee52d1da52d8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/DefineSymbols/LogScriptingDefineSymbols.cs b/EintooAR/Assets/TEngine/Editor/DefineSymbols/LogScriptingDefineSymbols.cs new file mode 100644 index 00000000..0b53399c --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/DefineSymbols/LogScriptingDefineSymbols.cs @@ -0,0 +1,172 @@ +using UnityEditor; + +namespace TEngine.Editor +{ + /// + /// 日志脚本宏定义操作类。 + /// + public static class LogScriptingDefineSymbols + { + private const string EnableLogScriptingDefineSymbol = "ENABLE_LOG"; + private const string EnableDebugAndAboveLogScriptingDefineSymbol = "ENABLE_DEBUG_AND_ABOVE_LOG"; + private const string EnableInfoAndAboveLogScriptingDefineSymbol = "ENABLE_INFO_AND_ABOVE_LOG"; + private const string EnableWarningAndAboveLogScriptingDefineSymbol = "ENABLE_WARNING_AND_ABOVE_LOG"; + private const string EnableErrorAndAboveLogScriptingDefineSymbol = "ENABLE_ERROR_AND_ABOVE_LOG"; + private const string EnableFatalAndAboveLogScriptingDefineSymbol = "ENABLE_FATAL_AND_ABOVE_LOG"; + private const string EnableDebugLogScriptingDefineSymbol = "ENABLE_DEBUG_LOG"; + private const string EnableInfoLogScriptingDefineSymbol = "ENABLE_INFO_LOG"; + private const string EnableWarningLogScriptingDefineSymbol = "ENABLE_WARNING_LOG"; + private const string EnableErrorLogScriptingDefineSymbol = "ENABLE_ERROR_LOG"; + private const string EnableFatalLogScriptingDefineSymbol = "ENABLE_FATAL_LOG"; + + private static readonly string[] AboveLogScriptingDefineSymbols = new string[] + { + EnableDebugAndAboveLogScriptingDefineSymbol, + EnableInfoAndAboveLogScriptingDefineSymbol, + EnableWarningAndAboveLogScriptingDefineSymbol, + EnableErrorAndAboveLogScriptingDefineSymbol, + EnableFatalAndAboveLogScriptingDefineSymbol + }; + + private static readonly string[] SpecifyLogScriptingDefineSymbols = new string[] + { + EnableDebugLogScriptingDefineSymbol, + EnableInfoLogScriptingDefineSymbol, + EnableWarningLogScriptingDefineSymbol, + EnableErrorLogScriptingDefineSymbol, + EnableFatalLogScriptingDefineSymbol + }; + + /// + /// 禁用所有日志脚本宏定义。 + /// + [MenuItem("TEngine/Log Scripting Define Symbols/Disable All Logs", false, 30)] + public static void DisableAllLogs() + { + ScriptingDefineSymbols.RemoveScriptingDefineSymbol(EnableLogScriptingDefineSymbol); + + foreach (string specifyLogScriptingDefineSymbol in SpecifyLogScriptingDefineSymbols) + { + ScriptingDefineSymbols.RemoveScriptingDefineSymbol(specifyLogScriptingDefineSymbol); + } + + foreach (string aboveLogScriptingDefineSymbol in AboveLogScriptingDefineSymbols) + { + ScriptingDefineSymbols.RemoveScriptingDefineSymbol(aboveLogScriptingDefineSymbol); + } + } + + /// + /// 开启所有日志脚本宏定义。 + /// + [MenuItem("TEngine/Log Scripting Define Symbols/Enable All Logs", false, 31)] + public static void EnableAllLogs() + { + DisableAllLogs(); + ScriptingDefineSymbols.AddScriptingDefineSymbol(EnableLogScriptingDefineSymbol); + } + + /// + /// 开启调试及以上级别的日志脚本宏定义。 + /// + [MenuItem("TEngine/Log Scripting Define Symbols/Enable Debug And Above Logs", false, 32)] + public static void EnableDebugAndAboveLogs() + { + SetAboveLogScriptingDefineSymbol(EnableDebugAndAboveLogScriptingDefineSymbol); + } + + /// + /// 开启信息及以上级别的日志脚本宏定义。 + /// + [MenuItem("TEngine/Log Scripting Define Symbols/Enable Info And Above Logs", false, 33)] + public static void EnableInfoAndAboveLogs() + { + SetAboveLogScriptingDefineSymbol(EnableInfoAndAboveLogScriptingDefineSymbol); + } + + /// + /// 开启警告及以上级别的日志脚本宏定义。 + /// + [MenuItem("TEngine/Log Scripting Define Symbols/Enable Warning And Above Logs", false, 34)] + public static void EnableWarningAndAboveLogs() + { + SetAboveLogScriptingDefineSymbol(EnableWarningAndAboveLogScriptingDefineSymbol); + } + + /// + /// 开启错误及以上级别的日志脚本宏定义。 + /// + [MenuItem("TEngine/Log Scripting Define Symbols/Enable Error And Above Logs", false, 35)] + public static void EnableErrorAndAboveLogs() + { + SetAboveLogScriptingDefineSymbol(EnableErrorAndAboveLogScriptingDefineSymbol); + } + + /// + /// 开启严重错误及以上级别的日志脚本宏定义。 + /// + [MenuItem("TEngine/Log Scripting Define Symbols/Enable Fatal And Above Logs", false, 36)] + public static void EnableFatalAndAboveLogs() + { + SetAboveLogScriptingDefineSymbol(EnableFatalAndAboveLogScriptingDefineSymbol); + } + + /// + /// 设置日志脚本宏定义。 + /// + /// 要设置的日志脚本宏定义。 + public static void SetAboveLogScriptingDefineSymbol(string aboveLogScriptingDefineSymbol) + { + if (string.IsNullOrEmpty(aboveLogScriptingDefineSymbol)) + { + return; + } + + foreach (string i in AboveLogScriptingDefineSymbols) + { + if (i == aboveLogScriptingDefineSymbol) + { + DisableAllLogs(); + ScriptingDefineSymbols.AddScriptingDefineSymbol(aboveLogScriptingDefineSymbol); + return; + } + } + } + + /// + /// 设置日志脚本宏定义。 + /// + /// 要设置的日志脚本宏定义。 + public static void SetSpecifyLogScriptingDefineSymbols(string[] specifyLogScriptingDefineSymbols) + { + if (specifyLogScriptingDefineSymbols == null || specifyLogScriptingDefineSymbols.Length <= 0) + { + return; + } + + bool removed = false; + foreach (string specifyLogScriptingDefineSymbol in specifyLogScriptingDefineSymbols) + { + if (string.IsNullOrEmpty(specifyLogScriptingDefineSymbol)) + { + continue; + } + + foreach (string i in SpecifyLogScriptingDefineSymbols) + { + if (i == specifyLogScriptingDefineSymbol) + { + if (!removed) + { + removed = true; + DisableAllLogs(); + } + + ScriptingDefineSymbols.AddScriptingDefineSymbol(specifyLogScriptingDefineSymbol); + break; + } + } + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/DefineSymbols/LogScriptingDefineSymbols.cs.meta b/EintooAR/Assets/TEngine/Editor/DefineSymbols/LogScriptingDefineSymbols.cs.meta new file mode 100644 index 00000000..15449fa6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/DefineSymbols/LogScriptingDefineSymbols.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7f38582e7109d344bd714fb29e2cd97 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/DefineSymbols/ProfilerDefineSymbols.cs b/EintooAR/Assets/TEngine/Editor/DefineSymbols/ProfilerDefineSymbols.cs new file mode 100644 index 00000000..e416bb7a --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/DefineSymbols/ProfilerDefineSymbols.cs @@ -0,0 +1,44 @@ +using UnityEditor; + +namespace TEngine.Editor +{ + /// + /// Profiler分析器宏定义操作类。 + /// + public class ProfilerDefineSymbols + { + private const string EnableFirstProfiler = "FIRST_PROFILER"; + private const string EnableTProFiler = "T_PROFILER"; + + private static readonly string[] AllProfilerDefineSymbols = new string[] + { + EnableFirstProfiler, + EnableTProFiler, + }; + + /// + /// 禁用所有日志脚本宏定义。 + /// + [MenuItem("TEngine/Profiler Define Symbols/Disable All Profiler", false, 30)] + public static void DisableAllProfiler() + { + foreach (string aboveLogScriptingDefineSymbol in AllProfilerDefineSymbols) + { + ScriptingDefineSymbols.RemoveScriptingDefineSymbol(aboveLogScriptingDefineSymbol); + } + } + + /// + /// 开启所有日志脚本宏定义。 + /// + [MenuItem("TEngine/Profiler Define Symbols/Enable All Profiler", false, 31)] + public static void EnableAllProfiler() + { + DisableAllProfiler(); + foreach (string aboveLogScriptingDefineSymbol in AllProfilerDefineSymbols) + { + ScriptingDefineSymbols.AddScriptingDefineSymbol(aboveLogScriptingDefineSymbol); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/DefineSymbols/ProfilerDefineSymbols.cs.meta b/EintooAR/Assets/TEngine/Editor/DefineSymbols/ProfilerDefineSymbols.cs.meta new file mode 100644 index 00000000..025f04cf --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/DefineSymbols/ProfilerDefineSymbols.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1503a11737564a498b65d84dc90758c2 +timeCreated: 1694790771 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/DefineSymbols/ScriptingDefineSymbols.cs b/EintooAR/Assets/TEngine/Editor/DefineSymbols/ScriptingDefineSymbols.cs new file mode 100644 index 00000000..01010d88 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/DefineSymbols/ScriptingDefineSymbols.cs @@ -0,0 +1,151 @@ +using System.Collections.Generic; +using UnityEditor; + +namespace TEngine.Editor +{ + /// + /// 脚本宏定义操作类。 + /// + public static class ScriptingDefineSymbols + { + private static readonly BuildTargetGroup[] BuildTargetGroups = new BuildTargetGroup[] + { + BuildTargetGroup.Standalone, + BuildTargetGroup.iOS, + BuildTargetGroup.Android, + BuildTargetGroup.WSA, + BuildTargetGroup.WebGL, + BuildTargetGroup.PS5 + }; + + /// + /// 检查指定平台是否存在指定的脚本宏定义。 + /// + /// 要检查脚本宏定义的平台。 + /// 要检查的脚本宏定义。 + /// 指定平台是否存在指定的脚本宏定义。 + public static bool HasScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol) + { + if (string.IsNullOrEmpty(scriptingDefineSymbol)) + { + return false; + } + + string[] scriptingDefineSymbols = GetScriptingDefineSymbols(buildTargetGroup); + foreach (string i in scriptingDefineSymbols) + { + if (i == scriptingDefineSymbol) + { + return true; + } + } + + return false; + } + + /// + /// 为指定平台增加指定的脚本宏定义。 + /// + /// 要增加脚本宏定义的平台。 + /// 要增加的脚本宏定义。 + public static void AddScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol) + { + if (string.IsNullOrEmpty(scriptingDefineSymbol)) + { + return; + } + + if (HasScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol)) + { + return; + } + + List scriptingDefineSymbols = new List(GetScriptingDefineSymbols(buildTargetGroup)) + { + scriptingDefineSymbol + }; + + SetScriptingDefineSymbols(buildTargetGroup, scriptingDefineSymbols.ToArray()); + } + + /// + /// 为指定平台移除指定的脚本宏定义。 + /// + /// 要移除脚本宏定义的平台。 + /// 要移除的脚本宏定义。 + public static void RemoveScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol) + { + if (string.IsNullOrEmpty(scriptingDefineSymbol)) + { + return; + } + + if (!HasScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol)) + { + return; + } + + List scriptingDefineSymbols = new List(GetScriptingDefineSymbols(buildTargetGroup)); + while (scriptingDefineSymbols.Contains(scriptingDefineSymbol)) + { + scriptingDefineSymbols.Remove(scriptingDefineSymbol); + } + + SetScriptingDefineSymbols(buildTargetGroup, scriptingDefineSymbols.ToArray()); + } + + /// + /// 为所有平台增加指定的脚本宏定义。 + /// + /// 要增加的脚本宏定义。 + public static void AddScriptingDefineSymbol(string scriptingDefineSymbol) + { + if (string.IsNullOrEmpty(scriptingDefineSymbol)) + { + return; + } + + foreach (BuildTargetGroup buildTargetGroup in BuildTargetGroups) + { + AddScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol); + } + } + + /// + /// 为所有平台移除指定的脚本宏定义。 + /// + /// 要移除的脚本宏定义。 + public static void RemoveScriptingDefineSymbol(string scriptingDefineSymbol) + { + if (string.IsNullOrEmpty(scriptingDefineSymbol)) + { + return; + } + + foreach (BuildTargetGroup buildTargetGroup in BuildTargetGroups) + { + RemoveScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol); + } + } + + /// + /// 获取指定平台的脚本宏定义。 + /// + /// 要获取脚本宏定义的平台。 + /// 平台的脚本宏定义。 + public static string[] GetScriptingDefineSymbols(BuildTargetGroup buildTargetGroup) + { + return PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup).Split(';'); + } + + /// + /// 设置指定平台的脚本宏定义。 + /// + /// 要设置脚本宏定义的平台。 + /// 要设置的脚本宏定义。 + public static void SetScriptingDefineSymbols(BuildTargetGroup buildTargetGroup, string[] scriptingDefineSymbols) + { + PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, string.Join(";", scriptingDefineSymbols)); + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/DefineSymbols/ScriptingDefineSymbols.cs.meta b/EintooAR/Assets/TEngine/Editor/DefineSymbols/ScriptingDefineSymbols.cs.meta new file mode 100644 index 00000000..5d7cb7c2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/DefineSymbols/ScriptingDefineSymbols.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 654ee3e03c534f841bf22040608d720e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/EditorTools.meta b/EintooAR/Assets/TEngine/Editor/EditorTools.meta new file mode 100644 index 00000000..65cf4b8d --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/EditorTools.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 654d71b5910a48b686279708db8865e2 +timeCreated: 1710744353 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/EditorTools/LubanTools.cs b/EintooAR/Assets/TEngine/Editor/EditorTools/LubanTools.cs new file mode 100644 index 00000000..d90ffd00 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/EditorTools/LubanTools.cs @@ -0,0 +1,20 @@ +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor +{ + public static class LubanTools + { + [MenuItem("TEngine/Tools/Luban 转表")] + public static void BuildLubanExcel() + { + Application.OpenURL(Application.dataPath + @"/../../Configs/GameConfig/gen_code_bin_to_project_lazyload.bat"); + } + + [MenuItem("TEngine/Tools/打开表格目录")] + public static void OpenConfigFolder() + { + OpenFolderHelper.Execute(Application.dataPath + @"/../../Configs/GameConfig"); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/EditorTools/LubanTools.cs.meta b/EintooAR/Assets/TEngine/Editor/EditorTools/LubanTools.cs.meta new file mode 100644 index 00000000..c06325dd --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/EditorTools/LubanTools.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0d51346d2ce24afaba0b8c9e8095fff4 +timeCreated: 1708583331 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/EventInterface.meta b/EintooAR/Assets/TEngine/Editor/EventInterface.meta new file mode 100644 index 00000000..22841d96 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/EventInterface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 86094b7c7ca31ab4da174cc7eae14a3c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/EventInterface/EventInterfaceGenerate.cs b/EintooAR/Assets/TEngine/Editor/EventInterface/EventInterfaceGenerate.cs new file mode 100644 index 00000000..fd398f35 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/EventInterface/EventInterfaceGenerate.cs @@ -0,0 +1,307 @@ +/*#region Class Documentation +/************************************************************************************************************ +Class Name: EventInterfaceGenerate.cs +Type: Editor, Generator, Util, Static +Definition: + 用法,在目录"Assets/GameScripts/HotFix/GameLogic/Event/Interface/"下分组照示例声明Interface 模块待抛出事件的接口。编译后自动生成接口实现抛出的脚本。 +Example: + + 旧版抛出事件方式: GameEvent.Send(RuntimeId.ToRuntimeId("OnMainPlayerCurrencyChange"),CurrencyType.Gold,oldVal,newVal); + + 新版抛出事件方式 : GameEvent.Get().OnMainPlayerCurrencyChange(CurrencyType.Gold,oldVal,newVal); + +***********************************************************************************************************#1# +#endregion + +using HybridCLR.Editor.Settings; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using TEngine; +using Unity.EditorCoroutines.Editor; +using UnityEditor; +using UnityEngine; + +[InitializeOnLoad] +public static class EventInterfaceGenerate +{ + public static string NameSpace = @"GameLogic"; + + + public const string EventInterfacePath = "Assets/GameScripts/HotFix/GameLogic/Event/Interface/"; + + public static bool BOpenAutoGenerate = false; + + static EventInterfaceGenerate() + { + BOpenAutoGenerate = EditorPrefs.GetBool("EventInterfaceGenerate.BOpenAutoGenerate", true); + if (BOpenAutoGenerate) + { + Generate(); + } + } + + [MenuItem("TEngine/EventInterface/OpenAutoGenerate", false, 300)] + public static void OpenAutoGenerate() + { + EditorPrefs.SetBool("EventInterfaceGenerate.BOpenAutoGenerate", true); + Debug.Log("OpenAutoGenerate"); + } + + [MenuItem("TEngine/EventInterface/CloseAutoGenerate", false, 301)] + public static void CloseAutoGenerate() + { + EditorPrefs.SetBool("EventInterfaceGenerate.BOpenAutoGenerate", false); + Debug.Log("CloseAutoGenerate"); + } + + [MenuItem("TEngine/EventInterface/Generate EventInterface", false, 302)] + public static void Generate() + { + if (EventInterfaceGenerateTag.HadGenerate) + { + return; + } + + EventInterfaceGenerateTag.HadGenerate = true; + + // 加载程序集 + Assembly assembly = null; + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach(var type in asm.GetTypes()) + { + if (type.Name == "GameApp") + { + assembly = asm; + break; + } + } + } + if(assembly == null) + { + Debug.LogError("Game App Class Not Found"); + return; + } + + // 获取程序集中的所有类型 + Type[] types = assembly.GetTypes(); + + // 遍历每个类型 + foreach (Type type in types) + { + // 检查类型是否是接口 + if (!type.IsInterface) + { + continue; + } + + var attribute = type.GetCustomAttributes(typeof(EventInterfaceAttribute), false).FirstOrDefault(); + + if (attribute != null) + { + EventInterfaceAttribute eventInterfaceAttribute = attribute as EventInterfaceAttribute; + + GenAutoBindCode(type, eventInterfaceAttribute); + } + } + + AssetDatabase.Refresh(); + Debug.Log("Generate EventInterface Complete"); + // EditorUtility.DisplayDialog("提示", "代码生成完毕", "OK"); + + EditorCoroutineUtility.StartCoroutine(EventInterfaceGenerateTag.Reset(), null); + } + + /// + /// 生成自动绑定代码 + /// + private static void GenAutoBindCode(Type interfaceType, EventInterfaceAttribute eventInterfaceAttribute) + { + string interfaceName = interfaceType.Name; + string className = $"{interfaceName}_Gen"; + string codePath = $"{Application.dataPath}/GameScripts/HotFix/GameLogic/Event/Gen/{eventInterfaceAttribute.EventGroup}"; + + if (!Directory.Exists(codePath)) + { + Directory.CreateDirectory(codePath); + } + + using (StreamWriter sw = new StreamWriter($"{codePath}/{className}.cs")) + { + sw.WriteLine( + $"//------------------------------------------------------------------------------\n//\t\n//\t\tThis code was generated by autoBindTool.\n//\t\tChanges to this file may cause incorrect behavior and will be lost if\n//\t\tthe code is regenerated.\n//\t\n//------------------------------------------------------------------------------"); + sw.WriteLine("using UnityEngine;"); + sw.WriteLine("using UnityEngine.UI;"); + sw.WriteLine("using TEngine;"); + sw.WriteLine(""); + + if (!string.IsNullOrEmpty(NameSpace)) + { + //命名空间 + sw.WriteLine("namespace " + NameSpace); + sw.WriteLine("{"); + } + + #region EventId生成 + + sw.WriteLine($"\tpublic partial class {interfaceName}_Event"); + sw.WriteLine("\t{"); + + // 获取接口中的所有方法 + MethodInfo[] methods = interfaceType.GetMethods(); + + HashSet hadGenerate = new HashSet(); + + //组件字段 + foreach (MethodInfo method in methods) + { + if (hadGenerate.Contains(method.Name)) + { + continue; + } + sw.WriteLine($"\t\tpublic static readonly int {method.Name} = RuntimeId.ToRuntimeId(\"{interfaceName}_Event.{method.Name}\");"); + hadGenerate.Add(method.Name); + } + + sw.WriteLine("\t}"); + sw.WriteLine(""); + + #endregion + + + //类名 + sw.WriteLine($"\t[EventInterfaceImp(EEventGroup.{eventInterfaceAttribute.EventGroup})]"); + sw.WriteLine($"\tpublic partial class {className} : {interfaceName}"); + sw.WriteLine("\t{"); + + sw.WriteLine("\t\tprivate EventDispatcher _dispatcher;"); + sw.WriteLine($"\t\tpublic {className}(EventDispatcher dispatcher)"); + sw.WriteLine("\t\t{"); + sw.WriteLine($"\t\t\t_dispatcher = dispatcher;"); + sw.WriteLine("\t\t}"); + sw.WriteLine(""); + + //组件字段 + foreach (MethodInfo methodInfo in methods) + { + ParameterInfo[] parameterInfos = methodInfo.GetParameters(); //得到指定方法的参数列表 + if (parameterInfos.Length <= 0) + { + sw.WriteLine( + $" public void {methodInfo.Name}()\n {{\n _dispatcher.Send({interfaceName}_Event.{methodInfo.Name});\n }}"); + } + else + { + string paramStr = ""; + string paramStr2 = ""; + for (int i = 0; i < parameterInfos.Length; i++) + { + var parameterInfo = parameterInfos[i]; + Type type = parameterInfo.ParameterType; + string paramName = parameterInfo.Name; + + if (type.FullName.StartsWith("System.Collections.Generic.List")) + { + Debug.Log("123"); + } + + if (i == parameterInfos.Length - 1) + { + paramStr += $"{GetTypeName(parameterInfo)} {paramName}"; + paramStr2 += $"{paramName}"; + } + else + { + paramStr += $"{GetTypeName(parameterInfo)} {paramName},"; + paramStr2 += $"{paramName},"; + } + } + + sw.WriteLine( + $" public void {methodInfo.Name}({paramStr})\n {{\n _dispatcher.Send({interfaceName}_Event.{methodInfo.Name},{paramStr2});\n }}"); + } + + sw.WriteLine(""); + } + + sw.WriteLine("\t}"); + + if (!string.IsNullOrEmpty(NameSpace)) + { + sw.WriteLine("}"); + } + } + } + + private static string GetTypeName(ParameterInfo parameterInfo) + { + if (parameterInfo.ParameterType.IsList() && parameterInfo.ParameterType.IsGenericType) + { + string typeName = parameterInfo.ParameterType.FullName.Split('`')[0]; + + return $"{typeName}<{parameterInfo.ParameterType.GenericTypeArguments[0].FullName}>"; + } + else if (parameterInfo.ParameterType.IsDictionary() && parameterInfo.ParameterType.IsGenericType) + { + string typeName = parameterInfo.ParameterType.FullName.Split('`')[0]; + + return $"{typeName}<{parameterInfo.ParameterType.GenericTypeArguments[0].FullName},{parameterInfo.ParameterType.GenericTypeArguments[1].FullName}>"; + } + else + { + return parameterInfo.ParameterType.FullName; + } + } + + /// + /// 判断类型是否为可操作的列表类型 + /// + /// + /// + public static bool IsList(this Type type) + { + if (typeof (System.Collections.IList).IsAssignableFrom(type)) + { + return true; + } + + foreach (var it in type.GetInterfaces()) + { + if (it.IsGenericType && typeof (IList<>) == it.GetGenericTypeDefinition()) + return true; + } + + return false; + } + + public static bool IsDictionary(this Type type) + { + if (typeof (System.Collections.IDictionary).IsAssignableFrom(type)) + { + return true; + } + + foreach (var it in type.GetInterfaces()) + { + if (it.IsGenericType && typeof (IDictionary) == it.GetGenericTypeDefinition()) + return true; + } + + return false; + } +} + +public static class EventInterfaceGenerateTag +{ + public static bool HadGenerate = false; + + public static IEnumerator Reset() + { + yield return new WaitForSeconds(10f); + HadGenerate = false; + } +}*/ \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/EventInterface/EventInterfaceGenerate.cs.meta b/EintooAR/Assets/TEngine/Editor/EventInterface/EventInterfaceGenerate.cs.meta new file mode 100644 index 00000000..2d2f0d43 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/EventInterface/EventInterfaceGenerate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e3af172e88343e4cb49c9e870518ede +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/GameSettings.meta b/EintooAR/Assets/TEngine/Editor/GameSettings.meta new file mode 100644 index 00000000..3b266102 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/GameSettings.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8886f3797aa14b80ab35d4d5e20d32e6 +timeCreated: 1695127130 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/GameSettings/SettingsMenu.cs b/EintooAR/Assets/TEngine/Editor/GameSettings/SettingsMenu.cs new file mode 100644 index 00000000..b368883e --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/GameSettings/SettingsMenu.cs @@ -0,0 +1,7 @@ +using UnityEditor; + +public static class SettingsMenu +{ + [MenuItem("TEngine/Settings/TEngineSettings", priority = -1)] + public static void OpenSettings() => SettingsService.OpenProjectSettings("TEngine/TEngineSettings"); +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/GameSettings/SettingsMenu.cs.meta b/EintooAR/Assets/TEngine/Editor/GameSettings/SettingsMenu.cs.meta new file mode 100644 index 00000000..39aa9c82 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/GameSettings/SettingsMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1afcc6b01c286a54d84a1c6a27deceb8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/GameSettings/SynAssemblysContent.cs b/EintooAR/Assets/TEngine/Editor/GameSettings/SynAssemblysContent.cs new file mode 100644 index 00000000..784a5772 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/GameSettings/SynAssemblysContent.cs @@ -0,0 +1,35 @@ +using UnityEditor; +using UnityEngine; + +/// +/// 同步程序集上下文。 +/// +public static class SyncAssemblyContent +{ + public static void RefreshAssembly() + { + var hotUpdateAssemblyFiles = HybridCLR.Editor.SettingsUtil.HotUpdateAssemblyFilesIncludePreserved; + var aotAssemblyNames = HybridCLR.Editor.SettingsUtil.AOTAssemblyNames; + + // 检查两个列表是否都为空,如果是,记录日志并返回。 + if (hotUpdateAssemblyFiles.Count == 0 && aotAssemblyNames.Count == 0) + { + Debug.Log("HybridCLR.Editor.SettingsUtil 程序集列表值为空"); + return; + } + + // 如果列表不为空,则更新相应的设置。 + if (hotUpdateAssemblyFiles.Count > 0) + { + SettingsUtils.SetHybridCLRHotUpdateAssemblies(hotUpdateAssemblyFiles); + } + + if (aotAssemblyNames.Count > 0) + { + SettingsUtils.SetHybridCLRAOTMetaAssemblies(aotAssemblyNames); + } + + AssetDatabase.Refresh(); + AssetDatabase.SaveAssets(); + } +} diff --git a/EintooAR/Assets/TEngine/Editor/GameSettings/SynAssemblysContent.cs.meta b/EintooAR/Assets/TEngine/Editor/GameSettings/SynAssemblysContent.cs.meta new file mode 100644 index 00000000..fcdafeab --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/GameSettings/SynAssemblysContent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04407344026702f4ebd61f63c8a35c69 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/GameSettings/TEngineSettingsProvider.cs b/EintooAR/Assets/TEngine/Editor/GameSettings/TEngineSettingsProvider.cs new file mode 100644 index 00000000..0d16fc28 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/GameSettings/TEngineSettingsProvider.cs @@ -0,0 +1,115 @@ +using System.IO; +using UnityEditor; +using UnityEngine.UIElements; +using System.Collections.Generic; +using UnityEngine; + +public class TEngineSettingsProvider : SettingsProvider +{ + const string k_SettingsPathHeader = "Assets/TEngine/ResRaw/Resources/"; + const string k_SettingsPath = "Assets/TEngine/ResRaw/Resources/TEngineGlobalSettings.asset"; + private const string headerName = "TEngine/TEngineSettings"; + private SerializedObject m_CustomSettings; + + private static string m_SettingsPath = k_SettingsPath; + internal static SerializedObject GetSerializedSettings() + { + return new SerializedObject(SettingsUtils.GlobalSettings); + } + + public static bool IsSettingsAvailable() + { + var pathes = AssetDatabase.FindAssets("TEngineGlobalSettings", new string[2] { k_SettingsPathHeader,"Packages/com.tengine/" }); + if (pathes.Length > 0) + { + m_SettingsPath = AssetDatabase.GUIDToAssetPath(pathes[0]); + } + return pathes.Length > 0; + } + + public override void OnActivate(string searchContext, VisualElement rootElement) + { + base.OnActivate(searchContext, rootElement); + m_CustomSettings = GetSerializedSettings(); + } + + public override void OnDeactivate() + { + base.OnDeactivate(); + + // 确保只有在有修改时才保存 + if (m_CustomSettings != null && m_CustomSettings.hasModifiedProperties) + { + EditorApplication.delayCall += () => SaveAssetData(k_SettingsPath); + } + } + + void SaveAssetData(string path) + { + TEngineSettings old = AssetDatabase.LoadAssetAtPath(k_SettingsPath); + if (old == null) + { + Debug.LogError($"Failed to load TEngineSettings from path: {k_SettingsPath}"); + return; + } + + TEngineSettings data = ScriptableObject.CreateInstance(); + data.Set(old.FrameworkGlobalSettings, old.BybridCLRCustomGlobalSettings); + + if (AssetDatabase.DeleteAsset(path)) + { + AssetDatabase.CreateAsset(data, path); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + else + { + Debug.LogError($"Failed to delete existing asset at path: {path}"); + } + } + + + public override void OnGUI(string searchContext) + { + base.OnGUI(searchContext); + using var changeCheckScope = new EditorGUI.ChangeCheckScope(); + EditorGUILayout.PropertyField(m_CustomSettings.FindProperty("m_FrameworkGlobalSettings")); + + if (GUILayout.Button("Refresh HotUpdateAssemblies")) + { + SyncAssemblyContent.RefreshAssembly(); + m_CustomSettings.ApplyModifiedPropertiesWithoutUndo(); + m_CustomSettings = null; + m_CustomSettings = GetSerializedSettings(); + } + + EditorGUILayout.PropertyField(m_CustomSettings.FindProperty("m_HybridCLRCustomGlobalSettings")); + EditorGUILayout.Space(20); + if (!changeCheckScope.changed) + { + return; + } + m_CustomSettings.ApplyModifiedPropertiesWithoutUndo(); + } + + public TEngineSettingsProvider(string path, SettingsScope scopes, IEnumerable keywords = null) : base(path, scopes, keywords) + { + } + + [SettingsProvider] + private static SettingsProvider CreateSettingProvider() + { + if (IsSettingsAvailable()) + { + var provider = new TEngineSettingsProvider(headerName, SettingsScope.Project); + provider.keywords = GetSearchKeywordsFromGUIContentProperties(); + return provider; + } + else + { + Debug.LogError($"Open TEngine Settings error,Please Create TEngine TEngineGlobalSettings.assets File in Path TEngine/ResRaw/Resources/"); + } + + return null; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/GameSettings/TEngineSettingsProvider.cs.meta b/EintooAR/Assets/TEngine/Editor/GameSettings/TEngineSettingsProvider.cs.meta new file mode 100644 index 00000000..f88cb196 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/GameSettings/TEngineSettingsProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 09fb422339ad47ec86205963c369718b +timeCreated: 1678946531 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/HybridCLR.meta b/EintooAR/Assets/TEngine/Editor/HybridCLR.meta new file mode 100644 index 00000000..714d76dc --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/HybridCLR.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 71b72a5760a04a4c8a3d8197729c3d10 +timeCreated: 1695127841 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/HybridCLR/BuildDLLCommand.cs b/EintooAR/Assets/TEngine/Editor/HybridCLR/BuildDLLCommand.cs new file mode 100644 index 00000000..6ad5d3e6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/HybridCLR/BuildDLLCommand.cs @@ -0,0 +1,99 @@ +#if ENABLE_HYBRIDCLR +using HybridCLR.Editor; +using HybridCLR.Editor.Commands; +#endif +using TEngine.Editor; +using UnityEditor; +using UnityEngine; + +public static class BuildDLLCommand +{ + private const string EnableHybridClrScriptingDefineSymbol = "ENABLE_HYBRIDCLR"; + + /// + /// 禁用HybridCLR宏定义。 + /// + [MenuItem("HybridCLR/Define Symbols/Disable HybridCLR", false, 30)] + public static void Disable() + { + ScriptingDefineSymbols.RemoveScriptingDefineSymbol(EnableHybridClrScriptingDefineSymbol); + HybridCLR.Editor.SettingsUtil.Enable = false; + SyncAssemblyContent.RefreshAssembly(); + } + + /// + /// 开启HybridCLR宏定义。 + /// + [MenuItem("HybridCLR/Define Symbols/Enable HybridCLR", false, 31)] + public static void Enable() + { + ScriptingDefineSymbols.RemoveScriptingDefineSymbol(EnableHybridClrScriptingDefineSymbol); + ScriptingDefineSymbols.AddScriptingDefineSymbol(EnableHybridClrScriptingDefineSymbol); + HybridCLR.Editor.SettingsUtil.Enable = true; + SyncAssemblyContent.RefreshAssembly(); + } + + [MenuItem("HybridCLR/Build/BuildAssets And CopyTo AssemblyTextAssetPath")] + public static void BuildAndCopyDlls() + { +#if ENABLE_HYBRIDCLR + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + CompileDllCommand.CompileDll(target); + CopyAOTHotUpdateDlls(target); +#endif + } + + public static void BuildAndCopyDlls(BuildTarget target) + { +#if ENABLE_HYBRIDCLR + CompileDllCommand.CompileDll(target); + CopyAOTHotUpdateDlls(target); +#endif + } + + public static void CopyAOTHotUpdateDlls(BuildTarget target) + { + CopyAOTAssembliesToAssetPath(); + CopyHotUpdateAssembliesToAssetPath(); + AssetDatabase.Refresh(); + } + + public static void CopyAOTAssembliesToAssetPath() + { +#if ENABLE_HYBRIDCLR + var target = EditorUserBuildSettings.activeBuildTarget; + string aotAssembliesSrcDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); + string aotAssembliesDstDir = Application.dataPath +"/"+ SettingsUtils.HybridCLRCustomGlobalSettings.AssemblyTextAssetPath; + + foreach (var dll in SettingsUtils.HybridCLRCustomGlobalSettings.AOTMetaAssemblies) + { + string srcDllPath = $"{aotAssembliesSrcDir}/{dll}"; + if (!System.IO.File.Exists(srcDllPath)) + { + Debug.LogError($"ab中添加AOT补充元数据dll:{srcDllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成,因此需要你先构建一次游戏App后再打包。"); + continue; + } + string dllBytesPath = $"{aotAssembliesDstDir}/{dll}.bytes"; + System.IO.File.Copy(srcDllPath, dllBytesPath, true); + Debug.Log($"[CopyAOTAssembliesToStreamingAssets] copy AOT dll {srcDllPath} -> {dllBytesPath}"); + } +#endif + } + + public static void CopyHotUpdateAssembliesToAssetPath() + { +#if ENABLE_HYBRIDCLR + var target = EditorUserBuildSettings.activeBuildTarget; + + string hotfixDllSrcDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target); + string hotfixAssembliesDstDir = Application.dataPath +"/"+ SettingsUtils.HybridCLRCustomGlobalSettings.AssemblyTextAssetPath; + foreach (var dll in SettingsUtil.HotUpdateAssemblyFilesExcludePreserved) + { + string dllPath = $"{hotfixDllSrcDir}/{dll}"; + string dllBytesPath = $"{hotfixAssembliesDstDir}/{dll}.bytes"; + System.IO.File.Copy(dllPath, dllBytesPath, true); + Debug.Log($"[CopyHotUpdateAssembliesToStreamingAssets] copy hotfix dll {dllPath} -> {dllBytesPath}"); + } +#endif + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/HybridCLR/BuildDLLCommand.cs.meta b/EintooAR/Assets/TEngine/Editor/HybridCLR/BuildDLLCommand.cs.meta new file mode 100644 index 00000000..0d759b52 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/HybridCLR/BuildDLLCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b43c8d69a58c066469f4f28e310d8181 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector.meta b/EintooAR/Assets/TEngine/Editor/Inspector.meta new file mode 100644 index 00000000..cf5ab3b2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d070fe16674cbe240be91ed06370b6be +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/Asset.meta b/EintooAR/Assets/TEngine/Editor/Inspector/Asset.meta new file mode 100644 index 00000000..ad882a4e --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/Asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d6f43591dfb9c54fbbebda60c1210fa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/Asset/DefaultAssetInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/Asset/DefaultAssetInspector.cs new file mode 100644 index 00000000..58d309e0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/Asset/DefaultAssetInspector.cs @@ -0,0 +1,52 @@ +using UnityEngine; +using UnityEditor; +using System.IO; + +[CanEditMultipleObjects, CustomEditor(typeof(DefaultAsset), false)] +public class DefaultAssetInspector : Editor +{ + private const int MaxColum = 10240; + + private GUIStyle _textStyle; + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + if (_textStyle == null) + { + _textStyle = "ScriptText"; + } + + bool enabled = GUI.enabled; + GUI.enabled = true; + string assetPath = AssetDatabase.GetAssetPath(target); + if (assetPath.EndsWith(".lua") || + assetPath.EndsWith(".properties") || + assetPath.EndsWith(".gradle") + ) + { + string luaFile = File.ReadAllText(assetPath); + string text; + if (targets.Length > 1) + { + text = Path.GetFileName(assetPath); + } + else + { + text = luaFile; + if (text.Length > MaxColum) + { + text = text.Substring(0, MaxColum) + "...\n\n<...etc...>"; + } + } + + Rect rect = GUILayoutUtility.GetRect(new GUIContent(text), _textStyle); + rect.x = 0f; + rect.y -= 3f; + rect.width = EditorGUIUtility.currentViewWidth + 1f; + GUI.Box(rect, text, _textStyle); + } + + GUI.enabled = enabled; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/Asset/DefaultAssetInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/Asset/DefaultAssetInspector.cs.meta new file mode 100644 index 00000000..3fe57bdc --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/Asset/DefaultAssetInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83f53d2e775d0ff449616ff946f1be55 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/Asset/TextAssetInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/Asset/TextAssetInspector.cs new file mode 100644 index 00000000..b2e7ea4f --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/Asset/TextAssetInspector.cs @@ -0,0 +1,53 @@ +using UnityEngine; +using UnityEditor; +using System.IO; + +[CanEditMultipleObjects, CustomEditor(typeof(TextAsset))] +public class TextAssetInspector : Editor +{ + private const int MaxColum = 10240; + + private GUIStyle _textStyle; + + public override void OnInspectorGUI() + { + if (_textStyle == null) + { + _textStyle = "ScriptText"; + } + + bool enabled = GUI.enabled; + GUI.enabled = true; + string assetPath = AssetDatabase.GetAssetPath(target); + if (assetPath.EndsWith(".md") + || assetPath.EndsWith(".xml") + || assetPath.EndsWith(".txt") + || assetPath.EndsWith(".html") + || assetPath.EndsWith(".csv") + ) + { + string luaFile = File.ReadAllText(assetPath); + string text; + if (base.targets.Length > 1) + { + text = Path.GetFileName(assetPath); + } + else + { + text = luaFile; + if (text.Length > MaxColum) + { + text = text.Substring(0, MaxColum) + "...\n\n<...etc...>"; + } + } + + Rect rect = GUILayoutUtility.GetRect(new GUIContent(text), _textStyle); + rect.x = 0f; + rect.y -= 3f; + rect.width = EditorGUIUtility.currentViewWidth + 1f; + GUI.Box(rect, text, _textStyle); + } + + GUI.enabled = enabled; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/Asset/TextAssetInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/Asset/TextAssetInspector.cs.meta new file mode 100644 index 00000000..7d2cb6fc --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/Asset/TextAssetInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad0327765273616459117746a53a35e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/AudioModuleInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/AudioModuleInspector.cs new file mode 100644 index 00000000..4dbc50f5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/AudioModuleInspector.cs @@ -0,0 +1,54 @@ +using UnityEditor; + +namespace TEngine.Editor.Inspector +{ + [CustomEditor(typeof(AudioModule))] + internal sealed class AudioModuleInspector : GameFrameworkInspector + { + private SerializedProperty m_InstanceRoot = null; + private SerializedProperty m_AudioMixer = null; + private SerializedProperty m_AudioGroupConfigs = null; + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + serializedObject.Update(); + + AudioModule t = (AudioModule)target; + + EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode); + { + EditorGUILayout.PropertyField(m_InstanceRoot); + EditorGUILayout.PropertyField(m_AudioMixer); + + EditorGUILayout.PropertyField(m_AudioGroupConfigs, true); + } + EditorGUI.EndDisabledGroup(); + + serializedObject.ApplyModifiedProperties(); + + Repaint(); + } + + protected override void OnCompileComplete() + { + base.OnCompileComplete(); + + RefreshTypeNames(); + } + + private void OnEnable() + { + m_InstanceRoot = serializedObject.FindProperty("m_InstanceRoot"); + m_AudioMixer = serializedObject.FindProperty("m_AudioMixer"); + m_AudioGroupConfigs = serializedObject.FindProperty("m_AudioGroupConfigs"); + RefreshTypeNames(); + } + + private void RefreshTypeNames() + { + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/AudioModuleInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/AudioModuleInspector.cs.meta new file mode 100644 index 00000000..9d6ae3f5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/AudioModuleInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ab21fc9c6dd70744a63b928446497bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/Core.meta b/EintooAR/Assets/TEngine/Editor/Inspector/Core.meta new file mode 100644 index 00000000..39b3a8ad --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b430ccb333d3963468369c50283c6174 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/Core/GameFrameworkInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/Core/GameFrameworkInspector.cs new file mode 100644 index 00000000..078713d8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/Core/GameFrameworkInspector.cs @@ -0,0 +1,57 @@ +using UnityEditor; + +namespace TEngine.Editor.Inspector +{ + /// + /// 游戏框架 Inspector 抽象类。 + /// + public abstract class GameFrameworkInspector : UnityEditor.Editor + { + private bool m_IsCompiling = false; + + /// + /// 绘制事件。 + /// + public override void OnInspectorGUI() + { + if (m_IsCompiling && !EditorApplication.isCompiling) + { + m_IsCompiling = false; + OnCompileComplete(); + } + else if (!m_IsCompiling && EditorApplication.isCompiling) + { + m_IsCompiling = true; + OnCompileStart(); + } + } + + /// + /// 编译开始事件。 + /// + protected virtual void OnCompileStart() + { + } + + /// + /// 编译完成事件。 + /// + protected virtual void OnCompileComplete() + { + } + + protected bool IsPrefabInHierarchy(UnityEngine.Object obj) + { + if (obj == null) + { + return false; + } + +#if UNITY_2018_3_OR_NEWER + return PrefabUtility.GetPrefabAssetType(obj) != PrefabAssetType.Regular; +#else + return PrefabUtility.GetPrefabType(obj) != PrefabType.Prefab; +#endif + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/Core/GameFrameworkInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/Core/GameFrameworkInspector.cs.meta new file mode 100644 index 00000000..ae6810e8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/Core/GameFrameworkInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d91af5de1cd262429b9414da4df0a4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/FsmComponentInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/FsmComponentInspector.cs new file mode 100644 index 00000000..b0978fdc --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/FsmComponentInspector.cs @@ -0,0 +1,40 @@ +using UnityEditor; + +namespace TEngine.Editor.Inspector +{ + [CustomEditor(typeof(FsmModule))] + internal sealed class FsmComponentInspector : GameFrameworkInspector + { + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + if (!EditorApplication.isPlaying) + { + EditorGUILayout.HelpBox("Available during runtime only.", MessageType.Info); + return; + } + + FsmModule t = (FsmModule)target; + + if (IsPrefabInHierarchy(t.gameObject)) + { + EditorGUILayout.LabelField("FSM Count", t.Count.ToString()); + + FsmBase[] fsms = t.GetAllFsms(); + foreach (FsmBase fsm in fsms) + { + DrawFsm(fsm); + } + } + + Repaint(); + } + + private void DrawFsm(FsmBase fsm) + { + EditorGUILayout.LabelField(fsm.FullName, + fsm.IsRunning ? Utility.Text.Format("{0}, {1:F1} s", fsm.CurrentStateName, fsm.CurrentStateTime) : (fsm.IsDestroyed ? "Destroyed" : "Not Running")); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/FsmComponentInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/FsmComponentInspector.cs.meta new file mode 100644 index 00000000..7f6da490 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/FsmComponentInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70767d883b439f84d8daaed6ca3f6d35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/MemoryPoolModuleInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/MemoryPoolModuleInspector.cs new file mode 100644 index 00000000..012209b3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/MemoryPoolModuleInspector.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor.Inspector +{ + [CustomEditor(typeof(MemoryPoolModule))] + internal sealed class MemoryPoolModuleInspector : GameFrameworkInspector + { + private readonly Dictionary> m_MemoryPoolInfos = new Dictionary>(StringComparer.Ordinal); + private readonly HashSet m_OpenedItems = new HashSet(); + + private SerializedProperty m_EnableStrictCheck = null; + + private bool m_ShowFullClassName = false; + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + serializedObject.Update(); + + MemoryPoolModule t = (MemoryPoolModule)target; + + if (EditorApplication.isPlaying && IsPrefabInHierarchy(t.gameObject)) + { + bool enableStrictCheck = EditorGUILayout.Toggle("Enable Strict Check", t.EnableStrictCheck); + if (enableStrictCheck != t.EnableStrictCheck) + { + t.EnableStrictCheck = enableStrictCheck; + } + + EditorGUILayout.LabelField("Memory Pool Count", MemoryPool.Count.ToString()); + m_ShowFullClassName = EditorGUILayout.Toggle("Show Full Class Name", m_ShowFullClassName); + m_MemoryPoolInfos.Clear(); + MemoryPoolInfo[] memoryPoolInfos = MemoryPool.GetAllMemoryPoolInfos(); + foreach (MemoryPoolInfo memoryPoolInfo in memoryPoolInfos) + { + string assemblyName = memoryPoolInfo.Type.Assembly.GetName().Name; + List results = null; + if (!m_MemoryPoolInfos.TryGetValue(assemblyName, out results)) + { + results = new List(); + m_MemoryPoolInfos.Add(assemblyName, results); + } + + results.Add(memoryPoolInfo); + } + + foreach (KeyValuePair> assemblyMemoryPoolInfo in m_MemoryPoolInfos) + { + bool lastState = m_OpenedItems.Contains(assemblyMemoryPoolInfo.Key); + bool currentState = EditorGUILayout.Foldout(lastState, assemblyMemoryPoolInfo.Key); + if (currentState != lastState) + { + if (currentState) + { + m_OpenedItems.Add(assemblyMemoryPoolInfo.Key); + } + else + { + m_OpenedItems.Remove(assemblyMemoryPoolInfo.Key); + } + } + + if (currentState) + { + EditorGUILayout.BeginVertical("box"); + { + EditorGUILayout.LabelField(m_ShowFullClassName ? "Full Class Name" : "Class Name", "Unused\tUsing\tAcquire\tRelease\tAdd\tRemove"); + assemblyMemoryPoolInfo.Value.Sort(Comparison); + foreach (MemoryPoolInfo memoryPoolInfo in assemblyMemoryPoolInfo.Value) + { + DrawMemoryPoolInfo(memoryPoolInfo); + } + + if (GUILayout.Button("Export CSV Data")) + { + string exportFileName = EditorUtility.SaveFilePanel("Export CSV Data", string.Empty, Utility.Text.Format("Memory Pool Data - {0}.csv", assemblyMemoryPoolInfo.Key), string.Empty); + if (!string.IsNullOrEmpty(exportFileName)) + { + try + { + int index = 0; + string[] data = new string[assemblyMemoryPoolInfo.Value.Count + 1]; + data[index++] = "Class Name,Full Class Name,Unused,Using,Acquire,Release,Add,Remove"; + foreach (MemoryPoolInfo memoryPoolInfo in assemblyMemoryPoolInfo.Value) + { + data[index++] = Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7}", memoryPoolInfo.Type.Name, memoryPoolInfo.Type.FullName, memoryPoolInfo.UnusedMemoryCount.ToString(), memoryPoolInfo.UsingMemoryCount.ToString(), memoryPoolInfo.AcquireMemoryCount.ToString(), memoryPoolInfo.ReleaseMemoryCount.ToString(), memoryPoolInfo.AddMemoryCount.ToString(), memoryPoolInfo.RemoveMemoryCount.ToString()); + } + + File.WriteAllLines(exportFileName, data, Encoding.UTF8); + Debug.Log(Utility.Text.Format("Export memory pool CSV data to '{0}' success.", exportFileName)); + } + catch (Exception exception) + { + Debug.LogError(Utility.Text.Format("Export memory pool CSV data to '{0}' failure, exception is '{1}'.", exportFileName, exception.ToString())); + } + } + } + } + EditorGUILayout.EndVertical(); + + EditorGUILayout.Separator(); + } + } + } + else + { + EditorGUILayout.PropertyField(m_EnableStrictCheck); + } + + serializedObject.ApplyModifiedProperties(); + + Repaint(); + } + + private void OnEnable() + { + m_EnableStrictCheck = serializedObject.FindProperty("m_EnableStrictCheck"); + } + + private void DrawMemoryPoolInfo(MemoryPoolInfo memoryPoolInfo) + { + EditorGUILayout.LabelField(m_ShowFullClassName ? memoryPoolInfo.Type.FullName : memoryPoolInfo.Type.Name, Utility.Text.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", memoryPoolInfo.UnusedMemoryCount.ToString(), memoryPoolInfo.UsingMemoryCount.ToString(), memoryPoolInfo.AcquireMemoryCount.ToString(), memoryPoolInfo.ReleaseMemoryCount.ToString(), memoryPoolInfo.AddMemoryCount.ToString(), memoryPoolInfo.RemoveMemoryCount.ToString())); + } + + private int Comparison(MemoryPoolInfo a, MemoryPoolInfo b) + { + if (m_ShowFullClassName) + { + return a.Type.FullName.CompareTo(b.Type.FullName); + } + else + { + return a.Type.Name.CompareTo(b.Type.Name); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/MemoryPoolModuleInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/MemoryPoolModuleInspector.cs.meta new file mode 100644 index 00000000..c3cd948b --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/MemoryPoolModuleInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 17406c25c88f31948b13eed588b32244 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/ObjectPoolModuleInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/ObjectPoolModuleInspector.cs new file mode 100644 index 00000000..de504bd5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/ObjectPoolModuleInspector.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor.Inspector +{ + [CustomEditor(typeof(ObjectPoolModule))] + internal sealed class ObjectPoolModuleInspector : GameFrameworkInspector + { + private readonly HashSet m_OpenedItems = new HashSet(); + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + if (!EditorApplication.isPlaying) + { + EditorGUILayout.HelpBox("Available during runtime only.", MessageType.Info); + return; + } + + ObjectPoolModule t = (ObjectPoolModule)target; + + if (IsPrefabInHierarchy(t.gameObject)) + { + EditorGUILayout.LabelField("Object Pool Count", t.Count.ToString()); + + ObjectPoolBase[] objectPools = t.GetAllObjectPools(true); + foreach (ObjectPoolBase objectPool in objectPools) + { + DrawObjectPool(objectPool); + } + } + + Repaint(); + } + + private void OnEnable() + { + } + + private void DrawObjectPool(ObjectPoolBase objectPool) + { + bool lastState = m_OpenedItems.Contains(objectPool.FullName); + bool currentState = EditorGUILayout.Foldout(lastState, objectPool.FullName); + if (currentState != lastState) + { + if (currentState) + { + m_OpenedItems.Add(objectPool.FullName); + } + else + { + m_OpenedItems.Remove(objectPool.FullName); + } + } + + if (currentState) + { + EditorGUILayout.BeginVertical("box"); + { + EditorGUILayout.LabelField("Name", objectPool.Name); + EditorGUILayout.LabelField("Type", objectPool.ObjectType.FullName); + EditorGUILayout.LabelField("Auto Release Interval", objectPool.AutoReleaseInterval.ToString()); + EditorGUILayout.LabelField("Capacity", objectPool.Capacity.ToString()); + EditorGUILayout.LabelField("Used Count", objectPool.Count.ToString()); + EditorGUILayout.LabelField("Can Release Count", objectPool.CanReleaseCount.ToString()); + EditorGUILayout.LabelField("Expire Time", objectPool.ExpireTime.ToString()); + EditorGUILayout.LabelField("Priority", objectPool.Priority.ToString()); + ObjectInfo[] objectInfos = objectPool.GetAllObjectInfos(); + if (objectInfos.Length > 0) + { + EditorGUILayout.LabelField("Name", + objectPool.AllowMultiSpawn ? "Locked\tCount\tFlag\tPriority\tLast Use Time" : "Locked\tIn Use\tFlag\tPriority\tLast Use Time"); + foreach (ObjectInfo objectInfo in objectInfos) + { + EditorGUILayout.LabelField(string.IsNullOrEmpty(objectInfo.Name) ? "" : objectInfo.Name, + objectPool.AllowMultiSpawn + ? Utility.Text.Format("{0}\t{1}\t{2}\t{3}\t{4:yyyy-MM-dd HH:mm:ss}", objectInfo.Locked, objectInfo.SpawnCount, + objectInfo.CustomCanReleaseFlag, + objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime()) + : Utility.Text.Format("{0}\t{1}\t{2}\t{3}\t{4:yyyy-MM-dd HH:mm:ss}", objectInfo.Locked, objectInfo.IsInUse, + objectInfo.CustomCanReleaseFlag, + objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime())); + } + + if (GUILayout.Button("Release")) + { + objectPool.Release(); + } + + if (GUILayout.Button("Release All Unused")) + { + objectPool.ReleaseAllUnused(); + } + + if (GUILayout.Button("Export CSV Data")) + { + string exportFileName = EditorUtility.SaveFilePanel("Export CSV Data", string.Empty, + Utility.Text.Format("Object Pool Data - {0}.csv", objectPool.Name), + string.Empty); + if (!string.IsNullOrEmpty(exportFileName)) + { + try + { + int index = 0; + string[] data = new string[objectInfos.Length + 1]; + data[index++] = Utility.Text.Format("Name,Locked,{0},Custom Can Release Flag,Priority,Last Use Time", + objectPool.AllowMultiSpawn ? "Count" : "In Use"); + foreach (ObjectInfo objectInfo in objectInfos) + { + data[index++] = objectPool.AllowMultiSpawn + ? Utility.Text.Format("{0},{1},{2},{3},{4},{5:yyyy-MM-dd HH:mm:ss}", objectInfo.Name, objectInfo.Locked, + objectInfo.SpawnCount, + objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime()) + : Utility.Text.Format("{0},{1},{2},{3},{4},{5:yyyy-MM-dd HH:mm:ss}", objectInfo.Name, objectInfo.Locked, + objectInfo.IsInUse, + objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime()); + } + + File.WriteAllLines(exportFileName, data, Encoding.UTF8); + Debug.Log(Utility.Text.Format("Export object pool CSV data to '{0}' success.", exportFileName)); + } + catch (Exception exception) + { + Debug.LogError(Utility.Text.Format("Export object pool CSV data to '{0}' failure, exception is '{1}'.", exportFileName, + exception)); + } + } + } + } + else + { + GUILayout.Label("Object Pool is Empty ..."); + } + } + EditorGUILayout.EndVertical(); + + EditorGUILayout.Separator(); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/ObjectPoolModuleInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/ObjectPoolModuleInspector.cs.meta new file mode 100644 index 00000000..9c73a738 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/ObjectPoolModuleInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 581eaf027c4a96d4d8227e2e16a6645b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/ProcedureModuleInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/ProcedureModuleInspector.cs new file mode 100644 index 00000000..0eedc1cb --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/ProcedureModuleInspector.cs @@ -0,0 +1,163 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor.Inspector +{ + [CustomEditor(typeof(ProcedureModule))] + internal sealed class ProcedureModuleInspector : GameFrameworkInspector + { + private SerializedProperty m_AvailableProcedureTypeNames = null; + private SerializedProperty m_EntranceProcedureTypeName = null; + + private string[] m_ProcedureTypeNames = null; + private List m_CurrentAvailableProcedureTypeNames = null; + private int m_EntranceProcedureIndex = -1; + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + serializedObject.Update(); + + ProcedureModule t = (ProcedureModule)target; + + if (string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue)) + { + EditorGUILayout.HelpBox("Entrance procedure is invalid.", MessageType.Error); + } + else if (EditorApplication.isPlaying) + { + EditorGUILayout.LabelField("Current Procedure", t.CurrentProcedure == null ? "None" : t.CurrentProcedure.GetType().ToString()); + } + + EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode); + { + GUILayout.Label("Available Procedures", EditorStyles.boldLabel); + if (m_ProcedureTypeNames.Length > 0) + { + EditorGUILayout.BeginVertical("box"); + { + foreach (string procedureTypeName in m_ProcedureTypeNames) + { + bool selected = m_CurrentAvailableProcedureTypeNames.Contains(procedureTypeName); + if (selected != EditorGUILayout.ToggleLeft(procedureTypeName, selected)) + { + if (!selected) + { + m_CurrentAvailableProcedureTypeNames.Add(procedureTypeName); + WriteAvailableProcedureTypeNames(); + } + else if (procedureTypeName != m_EntranceProcedureTypeName.stringValue) + { + m_CurrentAvailableProcedureTypeNames.Remove(procedureTypeName); + WriteAvailableProcedureTypeNames(); + } + } + } + } + EditorGUILayout.EndVertical(); + } + else + { + EditorGUILayout.HelpBox("There is no available procedure.", MessageType.Warning); + } + + if (m_CurrentAvailableProcedureTypeNames.Count > 0) + { + EditorGUILayout.Separator(); + + int selectedIndex = EditorGUILayout.Popup("Entrance Procedure", m_EntranceProcedureIndex, m_CurrentAvailableProcedureTypeNames.ToArray()); + if (selectedIndex != m_EntranceProcedureIndex) + { + m_EntranceProcedureIndex = selectedIndex; + m_EntranceProcedureTypeName.stringValue = m_CurrentAvailableProcedureTypeNames[selectedIndex]; + } + } + else + { + EditorGUILayout.HelpBox("Select available procedures first.", MessageType.Info); + } + } + EditorGUI.EndDisabledGroup(); + + serializedObject.ApplyModifiedProperties(); + + Repaint(); + } + + protected override void OnCompileComplete() + { + base.OnCompileComplete(); + + RefreshTypeNames(); + } + + private void OnEnable() + { + m_AvailableProcedureTypeNames = serializedObject.FindProperty("availableProcedureTypeNames"); + m_EntranceProcedureTypeName = serializedObject.FindProperty("entranceProcedureTypeName"); + + RefreshTypeNames(); + } + + private void RefreshTypeNames() + { + m_ProcedureTypeNames = Type.GetRuntimeTypeNames(typeof(ProcedureBase)); + ReadAvailableProcedureTypeNames(); + int oldCount = m_CurrentAvailableProcedureTypeNames.Count; + m_CurrentAvailableProcedureTypeNames = m_CurrentAvailableProcedureTypeNames.Where(x => m_ProcedureTypeNames.Contains(x)).ToList(); + if (m_CurrentAvailableProcedureTypeNames.Count != oldCount) + { + WriteAvailableProcedureTypeNames(); + } + else if (!string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue)) + { + m_EntranceProcedureIndex = m_CurrentAvailableProcedureTypeNames.IndexOf(m_EntranceProcedureTypeName.stringValue); + if (m_EntranceProcedureIndex < 0) + { + m_EntranceProcedureTypeName.stringValue = null; + } + } + + serializedObject.ApplyModifiedProperties(); + } + + private void ReadAvailableProcedureTypeNames() + { + m_CurrentAvailableProcedureTypeNames = new List(); + int count = m_AvailableProcedureTypeNames.arraySize; + for (int i = 0; i < count; i++) + { + m_CurrentAvailableProcedureTypeNames.Add(m_AvailableProcedureTypeNames.GetArrayElementAtIndex(i).stringValue); + } + } + + private void WriteAvailableProcedureTypeNames() + { + m_AvailableProcedureTypeNames.ClearArray(); + if (m_CurrentAvailableProcedureTypeNames == null) + { + return; + } + + m_CurrentAvailableProcedureTypeNames.Sort(); + int count = m_CurrentAvailableProcedureTypeNames.Count; + for (int i = 0; i < count; i++) + { + m_AvailableProcedureTypeNames.InsertArrayElementAtIndex(i); + m_AvailableProcedureTypeNames.GetArrayElementAtIndex(i).stringValue = m_CurrentAvailableProcedureTypeNames[i]; + } + + if (!string.IsNullOrEmpty(m_EntranceProcedureTypeName.stringValue)) + { + m_EntranceProcedureIndex = m_CurrentAvailableProcedureTypeNames.IndexOf(m_EntranceProcedureTypeName.stringValue); + if (m_EntranceProcedureIndex < 0) + { + m_EntranceProcedureTypeName.stringValue = null; + } + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/ProcedureModuleInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/ProcedureModuleInspector.cs.meta new file mode 100644 index 00000000..affc01b3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/ProcedureModuleInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f8673b671dafe048a9fcd213c958166 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/ResourceModuleInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/ResourceModuleInspector.cs new file mode 100644 index 00000000..abe51a2a --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/ResourceModuleInspector.cs @@ -0,0 +1,290 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using YooAsset.Editor; + +namespace TEngine.Editor.Inspector +{ + [CustomEditor(typeof(ResourceModule))] + internal sealed class ResourceModuleInspector : GameFrameworkInspector + { + private static readonly string[] _resourceModeNames = new string[] + { + "EditorSimulateMode (编辑器下的模拟模式)", + "OfflinePlayMode (单机模式)", + "HostPlayMode (联机运行模式)", + "WebPlayMode (WebGL运行模式)" + }; + + private static readonly string[] _verifyLevelNames = new string[] + { + "Low (验证文件存在)", + "Middle (验证文件大小)", + "High (验证文件大小和CRC)" + }; + + private SerializedProperty m_PlayMode = null; + private SerializedProperty m_UpdatableWhilePlaying = null; + private SerializedProperty m_VerifyLevel = null; + private SerializedProperty m_Milliseconds = null; + private SerializedProperty m_ReadWritePathType = null; + private SerializedProperty m_MinUnloadUnusedAssetsInterval = null; + private SerializedProperty m_MaxUnloadUnusedAssetsInterval = null; + private SerializedProperty m_UseSystemUnloadUnusedAssets = null; + private SerializedProperty m_AssetAutoReleaseInterval = null; + private SerializedProperty m_AssetCapacity = null; + private SerializedProperty m_AssetExpireTime = null; + private SerializedProperty m_AssetPriority = null; + private SerializedProperty m_DownloadingMaxNum = null; + private SerializedProperty m_FailedTryAgain = null; + private SerializedProperty m_PackageName = null; + private int m_ResourceModeIndex = 0; + private int m_VerifyIndex = 0; + + private int m_PackageNameIndex = 0; + private string[] m_PackageNames; + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + serializedObject.Update(); + + ResourceModule t = (ResourceModule)target; + + EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode); + { + if (EditorApplication.isPlaying && IsPrefabInHierarchy(t.gameObject)) + { + EditorGUILayout.EnumPopup("Resource Mode", t.PlayMode); + + EditorGUILayout.EnumPopup("VerifyLevel", t.VerifyLevel); + } + else + { + int selectedIndex = EditorGUILayout.Popup("Resource Mode", m_ResourceModeIndex, _resourceModeNames); + if (selectedIndex != m_ResourceModeIndex) + { + m_ResourceModeIndex = selectedIndex; + m_PlayMode.enumValueIndex = selectedIndex; + } + + int selectedVerifyIndex = EditorGUILayout.Popup("VerifyLevel", m_VerifyIndex, _verifyLevelNames); + if (selectedVerifyIndex != m_VerifyIndex) + { + m_VerifyIndex = selectedVerifyIndex; + m_VerifyLevel.enumValueIndex = selectedVerifyIndex; + } + } + + m_ReadWritePathType.enumValueIndex = (int)(ReadWritePathType)EditorGUILayout.EnumPopup("Read-Write Path Type", t.ReadWritePathType); + } + EditorGUILayout.PropertyField(m_UpdatableWhilePlaying); + + EditorGUI.EndDisabledGroup(); + + m_PackageNames = GetBuildPackageNames().ToArray(); + m_PackageNameIndex = Array.IndexOf(m_PackageNames, m_PackageName.stringValue); + if (m_PackageNameIndex < 0) + { + m_PackageNameIndex = 0; + } + m_PackageNameIndex = EditorGUILayout.Popup("Package Name", m_PackageNameIndex, m_PackageNames); + if (m_PackageName.stringValue != m_PackageNames[m_PackageNameIndex]) + { + m_PackageName.stringValue = m_PackageNames[m_PackageNameIndex]; + } + + int milliseconds = EditorGUILayout.DelayedIntField("Milliseconds", m_Milliseconds.intValue); + if (milliseconds != m_Milliseconds.intValue) + { + if (EditorApplication.isPlaying) + { + t.Milliseconds = milliseconds; + } + else + { + m_Milliseconds.longValue = milliseconds; + } + } + + EditorGUILayout.PropertyField(m_UseSystemUnloadUnusedAssets); + + float minUnloadUnusedAssetsInterval = + EditorGUILayout.Slider("Min Unload Unused Assets Interval", m_MinUnloadUnusedAssetsInterval.floatValue, 0f, 3600f); + if (Math.Abs(minUnloadUnusedAssetsInterval - m_MinUnloadUnusedAssetsInterval.floatValue) > 0.01f) + { + if (EditorApplication.isPlaying) + { + t.MinUnloadUnusedAssetsInterval = minUnloadUnusedAssetsInterval; + } + else + { + m_MinUnloadUnusedAssetsInterval.floatValue = minUnloadUnusedAssetsInterval; + } + } + + float maxUnloadUnusedAssetsInterval = + EditorGUILayout.Slider("Max Unload Unused Assets Interval", m_MaxUnloadUnusedAssetsInterval.floatValue, 0f, 3600f); + if (Math.Abs(maxUnloadUnusedAssetsInterval - m_MaxUnloadUnusedAssetsInterval.floatValue) > 0.01f) + { + if (EditorApplication.isPlaying) + { + t.MaxUnloadUnusedAssetsInterval = maxUnloadUnusedAssetsInterval; + } + else + { + m_MaxUnloadUnusedAssetsInterval.floatValue = maxUnloadUnusedAssetsInterval; + } + } + + float downloadingMaxNum = EditorGUILayout.Slider("Max Downloading Num", m_DownloadingMaxNum.intValue, 1f, 48f); + if (Math.Abs(downloadingMaxNum - m_DownloadingMaxNum.intValue) > 0.001f) + { + if (EditorApplication.isPlaying) + { + t.DownloadingMaxNum = (int)downloadingMaxNum; + } + else + { + m_DownloadingMaxNum.intValue = (int)downloadingMaxNum; + } + } + + float failedTryAgain = EditorGUILayout.Slider("Max FailedTryAgain Count", m_FailedTryAgain.intValue, 1f, 48f); + if (Math.Abs(failedTryAgain - m_FailedTryAgain.intValue) > 0.001f) + { + if (EditorApplication.isPlaying) + { + t.FailedTryAgain = (int)failedTryAgain; + } + else + { + m_FailedTryAgain.intValue = (int)failedTryAgain; + } + } + + EditorGUI.BeginDisabledGroup(EditorApplication.isPlaying); + { + float assetAutoReleaseInterval = EditorGUILayout.DelayedFloatField("Asset Auto Release Interval", m_AssetAutoReleaseInterval.floatValue); + if (Math.Abs(assetAutoReleaseInterval - m_AssetAutoReleaseInterval.floatValue) > 0.01f) + { + if (EditorApplication.isPlaying) + { + t.AssetAutoReleaseInterval = assetAutoReleaseInterval; + } + else + { + m_AssetAutoReleaseInterval.floatValue = assetAutoReleaseInterval; + } + } + + int assetCapacity = EditorGUILayout.DelayedIntField("Asset Capacity", m_AssetCapacity.intValue); + if (assetCapacity != m_AssetCapacity.intValue) + { + if (EditorApplication.isPlaying) + { + t.AssetCapacity = assetCapacity; + } + else + { + m_AssetCapacity.intValue = assetCapacity; + } + } + + float assetExpireTime = EditorGUILayout.DelayedFloatField("Asset Expire Time", m_AssetExpireTime.floatValue); + if (Math.Abs(assetExpireTime - m_AssetExpireTime.floatValue) > 0.01f) + { + if (EditorApplication.isPlaying) + { + t.AssetExpireTime = assetExpireTime; + } + else + { + m_AssetExpireTime.floatValue = assetExpireTime; + } + } + + int assetPriority = EditorGUILayout.DelayedIntField("Asset Priority", m_AssetPriority.intValue); + if (assetPriority != m_AssetPriority.intValue) + { + if (EditorApplication.isPlaying) + { + t.AssetPriority = assetPriority; + } + else + { + m_AssetPriority.intValue = assetPriority; + } + } + } + EditorGUI.EndDisabledGroup(); + + if (EditorApplication.isPlaying && IsPrefabInHierarchy(t.gameObject)) + { + EditorGUILayout.LabelField("Unload Unused Assets", + Utility.Text.Format("{0:F2} / {1:F2}", t.LastUnloadUnusedAssetsOperationElapseSeconds, t.MaxUnloadUnusedAssetsInterval)); + EditorGUILayout.LabelField("Read-Only Path", t?.ReadOnlyPath?.ToString()); + EditorGUILayout.LabelField("Read-Write Path", t?.ReadWritePath?.ToString()); + EditorGUILayout.LabelField("Applicable Game Version", t.ApplicableGameVersion ?? ""); + } + + serializedObject.ApplyModifiedProperties(); + + Repaint(); + } + + protected override void OnCompileComplete() + { + base.OnCompileComplete(); + + RefreshTypeNames(); + } + + private void OnEnable() + { + m_PlayMode = serializedObject.FindProperty("playMode"); + m_UpdatableWhilePlaying = serializedObject.FindProperty("m_UpdatableWhilePlaying"); + m_VerifyLevel = serializedObject.FindProperty("VerifyLevel"); + m_Milliseconds = serializedObject.FindProperty("Milliseconds"); + m_ReadWritePathType = serializedObject.FindProperty("m_ReadWritePathType"); + m_MinUnloadUnusedAssetsInterval = serializedObject.FindProperty("m_MinUnloadUnusedAssetsInterval"); + m_MaxUnloadUnusedAssetsInterval = serializedObject.FindProperty("m_MaxUnloadUnusedAssetsInterval"); + m_UseSystemUnloadUnusedAssets = serializedObject.FindProperty("m_UseSystemUnloadUnusedAssets"); + m_AssetAutoReleaseInterval = serializedObject.FindProperty("m_AssetAutoReleaseInterval"); + m_AssetCapacity = serializedObject.FindProperty("m_AssetCapacity"); + m_AssetExpireTime = serializedObject.FindProperty("m_AssetExpireTime"); + m_AssetPriority = serializedObject.FindProperty("m_AssetPriority"); + m_DownloadingMaxNum = serializedObject.FindProperty("m_DownloadingMaxNum"); + m_FailedTryAgain = serializedObject.FindProperty("m_FailedTryAgain"); + m_PackageName = serializedObject.FindProperty("packageName"); + + RefreshModes(); + RefreshTypeNames(); + } + + private void RefreshModes() + { + m_ResourceModeIndex = m_PlayMode.enumValueIndex > 0 ? m_PlayMode.enumValueIndex : 0; + m_VerifyIndex = m_VerifyLevel.enumValueIndex > 0 ? m_VerifyLevel.enumValueIndex : 0; + } + + private void RefreshTypeNames() + { + serializedObject.ApplyModifiedProperties(); + } + + /// + /// 获取构建包名称列表,用于下拉可选择 + /// + /// + private List GetBuildPackageNames() + { + List result = new List(); + foreach (var package in AssetBundleCollectorSettingData.Setting.Packages) + { + result.Add(package.PackageName); + } + return result; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/ResourceModuleInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/ResourceModuleInspector.cs.meta new file mode 100644 index 00000000..2744c7d3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/ResourceModuleInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3331df47456eb44388680ac13979201 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/RootModuleInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/RootModuleInspector.cs new file mode 100644 index 00000000..c9d70136 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/RootModuleInspector.cs @@ -0,0 +1,278 @@ +using System; +using TEngine; +using System.Collections.Generic; +using TEngine.Editor.Inspector; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor +{ + [CustomEditor(typeof(RootModule))] + internal sealed class RootModuleInspector : GameFrameworkInspector + { + private const string NoneOptionName = ""; + private static readonly float[] GameSpeed = new float[] { 0f, 0.01f, 0.1f, 0.25f, 0.5f, 1f, 1.5f, 2f, 4f, 8f }; + private static readonly string[] GameSpeedForDisplay = new string[] { "0x", "0.01x", "0.1x", "0.25x", "0.5x", "1x", "1.5x", "2x", "4x", "8x" }; + + private SerializedProperty m_EditorLanguage = null; + private SerializedProperty m_TextHelperTypeName = null; + private SerializedProperty m_VersionHelperTypeName = null; + private SerializedProperty m_LogHelperTypeName = null; + private SerializedProperty m_CompressionHelperTypeName = null; + private SerializedProperty m_JsonHelperTypeName = null; + private SerializedProperty m_FrameRate = null; + private SerializedProperty m_GameSpeed = null; + private SerializedProperty m_RunInBackground = null; + private SerializedProperty m_NeverSleep = null; + + private string[] m_TextHelperTypeNames = null; + private int m_TextHelperTypeNameIndex = 0; + private string[] m_VersionHelperTypeNames = null; + private int m_VersionHelperTypeNameIndex = 0; + private string[] m_LogHelperTypeNames = null; + private int m_LogHelperTypeNameIndex = 0; + private string[] m_JsonHelperTypeNames = null; + private int m_JsonHelperTypeNameIndex = 0; + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + serializedObject.Update(); + + RootModule t = (RootModule)target; + + EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode); + { + EditorGUILayout.PropertyField(m_EditorLanguage); + + EditorGUILayout.BeginVertical("box"); + { + EditorGUILayout.LabelField("Global Helpers", EditorStyles.boldLabel); + + int textHelperSelectedIndex = EditorGUILayout.Popup("Text Helper", m_TextHelperTypeNameIndex, m_TextHelperTypeNames); + if (textHelperSelectedIndex != m_TextHelperTypeNameIndex) + { + m_TextHelperTypeNameIndex = textHelperSelectedIndex; + m_TextHelperTypeName.stringValue = textHelperSelectedIndex <= 0 ? null : m_TextHelperTypeNames[textHelperSelectedIndex]; + } + + int versionHelperSelectedIndex = EditorGUILayout.Popup("Version Helper", m_VersionHelperTypeNameIndex, m_VersionHelperTypeNames); + if (versionHelperSelectedIndex != m_VersionHelperTypeNameIndex) + { + m_VersionHelperTypeNameIndex = versionHelperSelectedIndex; + m_VersionHelperTypeName.stringValue = versionHelperSelectedIndex <= 0 ? null : m_VersionHelperTypeNames[versionHelperSelectedIndex]; + } + + int logHelperSelectedIndex = EditorGUILayout.Popup("Log Helper", m_LogHelperTypeNameIndex, m_LogHelperTypeNames); + if (logHelperSelectedIndex != m_LogHelperTypeNameIndex) + { + m_LogHelperTypeNameIndex = logHelperSelectedIndex; + m_LogHelperTypeName.stringValue = logHelperSelectedIndex <= 0 ? null : m_LogHelperTypeNames[logHelperSelectedIndex]; + } + + int jsonHelperSelectedIndex = EditorGUILayout.Popup("JSON Helper", m_JsonHelperTypeNameIndex, m_JsonHelperTypeNames); + if (jsonHelperSelectedIndex != m_JsonHelperTypeNameIndex) + { + m_JsonHelperTypeNameIndex = jsonHelperSelectedIndex; + m_JsonHelperTypeName.stringValue = jsonHelperSelectedIndex <= 0 ? null : m_JsonHelperTypeNames[jsonHelperSelectedIndex]; + } + } + EditorGUILayout.EndVertical(); + } + EditorGUI.EndDisabledGroup(); + + int frameRate = EditorGUILayout.IntSlider("Frame Rate", m_FrameRate.intValue, 1, 120); + if (frameRate != m_FrameRate.intValue) + { + if (EditorApplication.isPlaying) + { + t.FrameRate = frameRate; + } + else + { + m_FrameRate.intValue = frameRate; + } + } + + EditorGUILayout.BeginVertical("box"); + { + float gameSpeed = EditorGUILayout.Slider("Game Speed", m_GameSpeed.floatValue, 0f, 8f); + int selectedGameSpeed = GUILayout.SelectionGrid(GetSelectedGameSpeed(gameSpeed), GameSpeedForDisplay, 5); + if (selectedGameSpeed >= 0) + { + gameSpeed = GetGameSpeed(selectedGameSpeed); + } + + if (Math.Abs(gameSpeed - m_GameSpeed.floatValue) > 0.01f) + { + if (EditorApplication.isPlaying) + { + t.GameSpeed = gameSpeed; + } + else + { + m_GameSpeed.floatValue = gameSpeed; + } + } + } + EditorGUILayout.EndVertical(); + + bool runInBackground = EditorGUILayout.Toggle("Run in Background", m_RunInBackground.boolValue); + if (runInBackground != m_RunInBackground.boolValue) + { + if (EditorApplication.isPlaying) + { + t.RunInBackground = runInBackground; + } + else + { + m_RunInBackground.boolValue = runInBackground; + } + } + + bool neverSleep = EditorGUILayout.Toggle("Never Sleep", m_NeverSleep.boolValue); + if (neverSleep != m_NeverSleep.boolValue) + { + if (EditorApplication.isPlaying) + { + t.NeverSleep = neverSleep; + } + else + { + m_NeverSleep.boolValue = neverSleep; + } + } + + serializedObject.ApplyModifiedProperties(); + } + + protected override void OnCompileComplete() + { + base.OnCompileComplete(); + + RefreshTypeNames(); + } + + private void OnEnable() + { + m_EditorLanguage = serializedObject.FindProperty("m_EditorLanguage"); + m_TextHelperTypeName = serializedObject.FindProperty("m_TextHelperTypeName"); + m_VersionHelperTypeName = serializedObject.FindProperty("m_VersionHelperTypeName"); + m_LogHelperTypeName = serializedObject.FindProperty("m_LogHelperTypeName"); + m_CompressionHelperTypeName = serializedObject.FindProperty("m_CompressionHelperTypeName"); + m_JsonHelperTypeName = serializedObject.FindProperty("m_JsonHelperTypeName"); + m_FrameRate = serializedObject.FindProperty("m_FrameRate"); + m_GameSpeed = serializedObject.FindProperty("m_GameSpeed"); + m_RunInBackground = serializedObject.FindProperty("m_RunInBackground"); + m_NeverSleep = serializedObject.FindProperty("m_NeverSleep"); + + RefreshTypeNames(); + } + + private void RefreshTypeNames() + { + List textHelperTypeNames = new List + { + NoneOptionName + }; + + textHelperTypeNames.AddRange(Type.GetRuntimeTypeNames(typeof(Utility.Text.ITextHelper))); + m_TextHelperTypeNames = textHelperTypeNames.ToArray(); + m_TextHelperTypeNameIndex = 0; + if (!string.IsNullOrEmpty(m_TextHelperTypeName.stringValue)) + { + m_TextHelperTypeNameIndex = textHelperTypeNames.IndexOf(m_TextHelperTypeName.stringValue); + if (m_TextHelperTypeNameIndex <= 0) + { + m_TextHelperTypeNameIndex = 0; + m_TextHelperTypeName.stringValue = null; + } + } + + List versionHelperTypeNames = new List + { + NoneOptionName + }; + + versionHelperTypeNames.AddRange(Type.GetRuntimeTypeNames(typeof(Version.IVersionHelper))); + m_VersionHelperTypeNames = versionHelperTypeNames.ToArray(); + m_VersionHelperTypeNameIndex = 0; + if (!string.IsNullOrEmpty(m_VersionHelperTypeName.stringValue)) + { + m_VersionHelperTypeNameIndex = versionHelperTypeNames.IndexOf(m_VersionHelperTypeName.stringValue); + if (m_VersionHelperTypeNameIndex <= 0) + { + m_VersionHelperTypeNameIndex = 0; + m_VersionHelperTypeName.stringValue = null; + } + } + + List logHelperTypeNames = new List + { + NoneOptionName + }; + + logHelperTypeNames.AddRange(Type.GetRuntimeTypeNames(typeof(GameFrameworkLog.ILogHelper))); + m_LogHelperTypeNames = logHelperTypeNames.ToArray(); + m_LogHelperTypeNameIndex = 0; + if (!string.IsNullOrEmpty(m_LogHelperTypeName.stringValue)) + { + m_LogHelperTypeNameIndex = logHelperTypeNames.IndexOf(m_LogHelperTypeName.stringValue); + if (m_LogHelperTypeNameIndex <= 0) + { + m_LogHelperTypeNameIndex = 0; + m_LogHelperTypeName.stringValue = null; + } + } + + List jsonHelperTypeNames = new List + { + NoneOptionName + }; + + jsonHelperTypeNames.AddRange(Type.GetRuntimeTypeNames(typeof(Utility.Json.IJsonHelper))); + m_JsonHelperTypeNames = jsonHelperTypeNames.ToArray(); + m_JsonHelperTypeNameIndex = 0; + if (!string.IsNullOrEmpty(m_JsonHelperTypeName.stringValue)) + { + m_JsonHelperTypeNameIndex = jsonHelperTypeNames.IndexOf(m_JsonHelperTypeName.stringValue); + if (m_JsonHelperTypeNameIndex <= 0) + { + m_JsonHelperTypeNameIndex = 0; + m_JsonHelperTypeName.stringValue = null; + } + } + + serializedObject.ApplyModifiedProperties(); + } + + private float GetGameSpeed(int selectedGameSpeed) + { + if (selectedGameSpeed < 0) + { + return GameSpeed[0]; + } + + if (selectedGameSpeed >= GameSpeed.Length) + { + return GameSpeed[GameSpeed.Length - 1]; + } + + return GameSpeed[selectedGameSpeed]; + } + + private int GetSelectedGameSpeed(float gameSpeed) + { + for (int i = 0; i < GameSpeed.Length; i++) + { + if (gameSpeed == GameSpeed[i]) + { + return i; + } + } + + return -1; + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/RootModuleInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/RootModuleInspector.cs.meta new file mode 100644 index 00000000..5c178008 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/RootModuleInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 250c436df9563f04881e590c3fc80e81 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/SettingModuleInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/SettingModuleInspector.cs new file mode 100644 index 00000000..5e215bc1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/SettingModuleInspector.cs @@ -0,0 +1,73 @@ +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor.Inspector +{ + [CustomEditor(typeof(SettingModule))] + internal sealed class SettingModuleInspector : GameFrameworkInspector + { + private HelperInfo m_SettingHelperInfo = new HelperInfo("Setting"); + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + SettingModule t = (SettingModule)target; + + EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode); + { + m_SettingHelperInfo.Draw(); + } + EditorGUI.EndDisabledGroup(); + + if (EditorApplication.isPlaying && IsPrefabInHierarchy(t.gameObject)) + { + EditorGUILayout.LabelField("Setting Count", t.Count >= 0 ? t.Count.ToString() : ""); + if (t.Count > 0) + { + string[] settingNames = t.GetAllSettingNames(); + foreach (string settingName in settingNames) + { + EditorGUILayout.LabelField(settingName, t.GetString(settingName)); + } + } + } + + if (EditorApplication.isPlaying) + { + if (GUILayout.Button("Save Settings")) + { + t.Save(); + } + if (GUILayout.Button("Remove All Settings")) + { + t.RemoveAllSettings(); + } + } + + serializedObject.ApplyModifiedProperties(); + + Repaint(); + } + + protected override void OnCompileComplete() + { + base.OnCompileComplete(); + + RefreshTypeNames(); + } + + private void OnEnable() + { + m_SettingHelperInfo.Init(serializedObject); + + RefreshTypeNames(); + } + + private void RefreshTypeNames() + { + m_SettingHelperInfo.Refresh(); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/SettingModuleInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/SettingModuleInspector.cs.meta new file mode 100644 index 00000000..74fa2ef8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/SettingModuleInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5ef9a06ba6ea31f47bf3f0ef922cf41b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/UIModuleInspector.cs b/EintooAR/Assets/TEngine/Editor/Inspector/UIModuleInspector.cs new file mode 100644 index 00000000..4a65ab7e --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/UIModuleInspector.cs @@ -0,0 +1,57 @@ +using UnityEditor; + +namespace TEngine.Editor.Inspector +{ + [CustomEditor(typeof(UIModule))] + internal sealed class UIModuleInspector : GameFrameworkInspector + { + private SerializedProperty m_InstanceRoot = null; + private SerializedProperty m_enableErrorLog = null; + private SerializedProperty m_dontDestroyUIRoot = null; + private SerializedProperty m_UICamera = null; + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + serializedObject.Update(); + + UIModule t = (UIModule)target; + + EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode); + { + EditorGUILayout.PropertyField(m_InstanceRoot); + EditorGUILayout.PropertyField(m_enableErrorLog); + EditorGUILayout.PropertyField(m_dontDestroyUIRoot); + EditorGUILayout.PropertyField(m_UICamera); + } + EditorGUI.EndDisabledGroup(); + + serializedObject.ApplyModifiedProperties(); + + Repaint(); + } + + protected override void OnCompileComplete() + { + base.OnCompileComplete(); + + RefreshTypeNames(); + } + + private void OnEnable() + { + m_InstanceRoot = serializedObject.FindProperty("m_InstanceRoot"); + m_enableErrorLog = serializedObject.FindProperty("m_enableErrorLog"); + m_dontDestroyUIRoot = serializedObject.FindProperty("m_dontDestroyUIRoot"); + m_UICamera = serializedObject.FindProperty("m_UICamera"); + + RefreshTypeNames(); + } + + private void RefreshTypeNames() + { + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Inspector/UIModuleInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Inspector/UIModuleInspector.cs.meta new file mode 100644 index 00000000..d3afc96f --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Inspector/UIModuleInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3d5af6a82ddad247810928f33f2c609 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization.meta b/EintooAR/Assets/TEngine/Editor/Localization.meta new file mode 100644 index 00000000..b95318b5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eee776b99f3e76a4c968d6943979829b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/EditorTools.cs b/EintooAR/Assets/TEngine/Editor/Localization/EditorTools.cs new file mode 100644 index 00000000..0ecd5f0d --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/EditorTools.cs @@ -0,0 +1,764 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; +using Object = UnityEngine.Object; + +namespace TEngine.Localization +{ + public class GUITools + { + static public Color White = Color.white; + static public Color LightGray = Color.Lerp(Color.gray, Color.white, 0.5f); + static public Color DarkGray = Color.Lerp(Color.gray, Color.white, 0.2f); + static public Color LightYellow = Color.Lerp(Color.yellow, Color.white, 0.5f); + + static public GUILayoutOption DontExpandWidth = GUILayout.ExpandWidth(false); + static public GUIContent EmptyContent = new GUIContent (); + + static List mDelayedEditorCallbacks = new List(); + + #region Delayed Editor Callback + + public static void DelayedCall( System.Action action ) + { + if (mDelayedEditorCallbacks.Count == 0) + EditorApplication.update += OnDelayedCall; + + mDelayedEditorCallbacks.Add(action); + } + + static void OnDelayedCall() + { + EditorApplication.update -= OnDelayedCall; + var calls = mDelayedEditorCallbacks.ToArray(); + mDelayedEditorCallbacks.Clear(); + + foreach (var call in calls) + call(); + } + + + #endregion + + #region Header + public delegate void fnOnToggled(bool enabled); + static public bool DrawHeader (string text, string key, bool ShowToggle=false, bool ToggleState=false, fnOnToggled OnToggle = null, string HelpURL=default(string), Color disabledColor = default(Color)) + { + bool state = EditorPrefs.GetBool(key, false); + + bool newState = DrawHeader (text, state, ShowToggle, ToggleState, OnToggle, HelpURL, disabledColor); + + if (state!=newState) EditorPrefs.SetBool(key, newState); + return newState; + } + + static public bool DrawHeader (string text, bool state, bool ShowToggle=false, bool ToggleState=false, fnOnToggled OnToggle = null, string HelpURL=default(string), Color disabledColor = default(Color), bool allowCollapsing = true) + { + GUIStyle Style = new GUIStyle(EditorStyles.foldout); + Style.richText = true; + EditorStyles.foldout.richText = true; + if (state) + { + //GUI.backgroundColor=DarkGray; + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea/*, GUILayout.Height(1)*/); + GUILayout.BeginHorizontal(); + if (!string.IsNullOrEmpty(text)) + { + if (allowCollapsing) + state = GUILayout.Toggle(state, text, Style, GUILayout.ExpandWidth(true)); + else + GUILayout.Label(text, GUILayout.ExpandWidth(true)); + } + + if (!string.IsNullOrEmpty(HelpURL)) + { + if (GUILayout.Button (Icon_Help, EditorStyles.label, GUILayout.ExpandWidth(false))) + Application.OpenURL(HelpURL); + } + if (ShowToggle) + { + GUI.changed = false; + bool newBool = GUILayout.Toggle(ToggleState, "", "OL Toggle", GUILayout.ExpandWidth(false)); + if (GUI.changed && OnToggle!=null) + OnToggle(newBool); + } + GUILayout.EndHorizontal(); + GUILayout.Space(2); + + //GUI.backgroundColor = Color.white; + } + else + { + if (ShowToggle && !ToggleState) + GUI.color = disabledColor; + + GUILayout.BeginHorizontal("Box"); + //GUILayout.BeginHorizontal(EditorStyles.toolbar); + state = GUILayout.Toggle(state, text, Style, GUILayout.ExpandWidth(true)); + if (ShowToggle) + { + GUI.changed = false; + bool newBool = GUILayout.Toggle(ToggleState, "", "OL Toggle", GUILayout.ExpandWidth(false)); + if (GUI.changed && OnToggle!=null) + OnToggle(newBool); + } + GUILayout.EndHorizontal(); + GUI.color = White; + } + return state; + } + + static public void CloseHeader() + { + GUILayout.EndHorizontal(); + } + + public static void OnGUI_Footer(string pluginName, string pluginVersion, string helpURL, string documentationURL, string assetStoreURL) + { + GUILayout.BeginHorizontal(); + string versionTip = ""; + /*if (I2Analytics.HasNewVersion(pluginName)) + { + versionTip = "There is a new version of " + pluginName + ".\nClick here for more details"; + if (GUILayout.Button(new GUIContent("", versionTip), EditorStyles.label, GUILayout.Width(25))) + I2AboutWindow.DoShowScreen(); + + var rect = GUILayoutUtility.GetLastRect(); + rect.yMin = rect.yMax - 25; + rect.xMax = rect.xMin + 25; + rect.y += 3; + GUITools.DrawSkinIcon(rect, "CN EntryWarnIcon", "CN EntryWarn"); + }*/ + + if (GUILayout.Button(new GUIContent("v" + pluginVersion, versionTip), EditorStyles.miniLabel)) + { + Application.OpenURL(assetStoreURL); + //I2AboutWindow.DoShowScreen(); + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ask a Question", EditorStyles.miniLabel)) + Application.OpenURL(helpURL); + + GUILayout.Space(10); + + if (GUILayout.Button("Documentation", EditorStyles.miniLabel)) + Application.OpenURL(documentationURL); + GUILayout.EndHorizontal(); + } + + + #endregion + + #region Content + + static public void BeginContents () + { + EditorGUILayout.BeginHorizontal(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.MinHeight(10f)); + GUILayout.Space(2f); + EditorGUILayout.BeginVertical(); + GUILayout.Space(2f); + } + + static public void EndContents () { EndContents(true); } + static public void EndContents ( bool closeHeader ) + { + GUILayout.Space(2f); + EditorGUILayout.EndVertical(); + GUILayout.Space(3f); + GUILayout.EndHorizontal(); + + if (closeHeader) CloseHeader(); + } + + #endregion + + #region Tabs + + static public void DrawTabs( SerializedProperty mProperty, GUIStyle Style=null, int height=25 ) + { + int curIndex = mProperty.enumValueIndex; + int newIndex = DrawTabs( curIndex, mProperty.enumNames, Style, height); + + if (curIndex!=newIndex) + mProperty.enumValueIndex = newIndex; + } + + static public int DrawTabs( int Index, string[] Tabs, GUIStyle Style=null, int height=25, bool expand = true) + { + GUIStyle MyStyle = new GUIStyle(Style!=null?Style:GUI.skin.FindStyle("dragtab")); + MyStyle.fixedHeight=0; + + GUILayout.BeginHorizontal(); + for (int i=0; i0) + { + string text = Tabs[i].Substring(0, idx); + string tooltip = Tabs[i].Substring(idx+1); + if ( GUILayout.Toggle(Index==i, new GUIContent(text, tooltip), MyStyle, GUILayout.Height(height), GUILayout.ExpandWidth(expand)) && Index!=i) + { + Index=i; + GUI.FocusControl(string.Empty); + } + } + else + { + if ( GUILayout.Toggle(Index==i, Tabs[i], MyStyle, GUILayout.Height(height), GUILayout.ExpandWidth(expand)) && Index!=i) + { + Index=i; + GUI.FocusControl(string.Empty); + } + } + } + GUILayout.EndHorizontal(); + return Index; + } + + static public void DrawShadowedTabs( SerializedProperty mProperty, GUIStyle Style=null, int height=25, bool expand=true ) + { + int curIndex = mProperty.enumValueIndex; + int newIndex = DrawShadowedTabs( curIndex, mProperty.enumNames, height, expand); + + if (curIndex!=newIndex) + mProperty.enumValueIndex = newIndex; + } + + static public int DrawShadowedTabs( int Index, string[] Tabs, int height = 25, bool expand=true ) + { + GUI.backgroundColor=Color.Lerp (Color.gray, Color.white, 0.2f); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1)); + GUI.backgroundColor=Color.white; + GUILayout.Space(2); + Index = DrawTabs( Index, Tabs, height: height, expand:expand ); + GUILayout.EndVertical(); + return Index; + } + + static public int DrawTabs( int Index, Texture2D[] Tabs, GUIStyle Style, int height ) + { + GUIStyle MyStyle = new GUIStyle(Style!=null?Style:GUI.skin.FindStyle("dragtab")); + MyStyle.fixedHeight=0; + + //width = Mathf.Max (width, height * Tabs[0].width/(float)Tabs[0].height); + + GUILayout.BeginHorizontal(); + float width = (EditorGUIUtility.currentViewWidth-(MyStyle.border.left+MyStyle.border.right)*(Tabs.Length-1)) / Tabs.Length; + for (int i=0; i1) + GUILayout.Space (18); + } + else + { + if (GUILayout.Button( "\u25B2", EditorStyles.toolbarButton, GUILayout.Width(18))) + MoveUpElement = i; + } + + GUILayout.EndHorizontal(); + } + + GUILayout.BeginHorizontal(EditorStyles.toolbar); + Object NewObj = EditorGUILayout.ObjectField( null, typeof(Object), allowSceneObj, GUILayout.ExpandWidth(true)); + if (testAdd != null) + { + NewObj = testAdd; + } + + if (!allowResources && NewObj != null) + { + var path = AssetDatabase.GetAssetPath(NewObj); + if (path != null && path.Contains("/Resources/")) + NewObj = null; + } + if (NewObj && (allowDuplicates || !ObjectsArrayHasReference(PropArray, NewObj))) + { + int Index = PropArray.arraySize; + PropArray.InsertArrayElementAtIndex( Index ); + PropArray.GetArrayElementAtIndex(Index).objectReferenceValue = NewObj; + hasChanged = true; + } + GUILayout.EndHorizontal(); + + if (DeleteElement>=0) + { + PropArray.DeleteArrayElementAtIndex( DeleteElement ); + //PropArray.DeleteArrayElementAtIndex( DeleteElement ); + hasChanged = true; + } + + if (MoveUpElement>=0) + { + PropArray.MoveArrayElement(MoveUpElement, MoveUpElement-1); + hasChanged = true; + } + + GUILayout.EndVertical(); + return hasChanged; + } + + static public bool ObjectsArrayHasReference(SerializedProperty PropArray, Object obj) + { + for (int i = 0, imax = PropArray.arraySize; i < imax; ++i) + { + SerializedProperty Prop = PropArray.GetArrayElementAtIndex(i); + if (Prop.objectReferenceValue == obj) + return true; + } + return false; + } + + + #endregion + + #region Toggle + + static public int ToggleToolbar( int Index, string[] Options ) + { + GUILayout.BeginHorizontal(); + for (int i=0; i 0) + return false; + + // We are not interested in Prefab, unless they are Prefab Instances + PrefabType pfType = PrefabUtility.GetPrefabType(Obj); + if(pfType == PrefabType.Prefab || pfType == PrefabType.ModelPrefab) + return false; + + // If the database contains the object then its not an scene object, + // but the previous test should get rid of them, so I will just comment this + // unless an false positive object is found in the future + //if (AssetDatabase.Contains(Obj)) + // return false; + + return true;*/ + } + + public static IEnumerable SceneRoots() + { + var prop = new HierarchyProperty(HierarchyType.GameObjects); + var expanded = new int[0]; + while (prop.Next(expanded)) { + yield return prop.pptrValue as GameObject; + } + } + + public static List SceneRootsList() + { + return new List(SceneRoots()); + } + + public static IEnumerable AllSceneObjects() + { + var queue = new Queue(); + + foreach (var root in SceneRoots()) { + var tf = root.transform; + yield return tf; + queue.Enqueue(tf); + } + + while (queue.Count > 0) { + foreach (Transform child in queue.Dequeue()) { + yield return child; + queue.Enqueue(child); + } + } + } + + public static string GetScenePath(Transform tr) + { + if (tr==null) + return string.Empty; + + string path = tr.name; + while (tr.parent != null) + { + tr = tr.parent; + path = tr.name + "/" + path; + } + return path; + } + + public static Transform FindObjectInEditor( string scenePath ) + { + if (string.IsNullOrEmpty(scenePath)) + return null; + + int index = scenePath.IndexOfAny("/\\".ToCharArray()); + string first = index<0 ? scenePath : scenePath.Substring(0, index); + + foreach (var root in AllSceneObjects()) + if (root.name==first) + { + if (index<0) + return root; + + return root.Find(scenePath.Substring(index+1)); + } + return null; + } + + + public static GUIContent Icon_Help { + get{ + if (mIconHelp == null) + mIconHelp = EditorGUIUtility.IconContent("_Help"); + return mIconHelp; + } + } + static GUIContent mIconHelp; + + public static GUIStyle FindSkinStyle(string name) + { + var allStyles = GUI.skin.customStyles; + for (int i = 0, imax = allStyles.Length; i < imax; ++i) + { + if (allStyles[i].name == name) + return allStyles[i]; + } + return null; + } + public static void DrawSkinIcon(Rect rect, params string[] iconNames) + { + foreach (var icon in iconNames) + { + var style = FindSkinStyle(icon); + if (style == null || style.normal == null || style.normal.background == null) + continue; + + GUI.DrawTexture(rect, style.normal.background); + return; + } + //Debug.Log("unable to find icon"); + } + + #endregion + + #region Angle Drawer + private static Vector2 mAngle_lastMousePosition; + static Texture mAngle_TextureCircle; + static Texture pAngle_TextureCircle { + get{ + if (mAngle_TextureCircle) return mAngle_TextureCircle; + mAngle_TextureCircle = GUI.skin.GetStyle("CN CountBadge").normal.background; + return mAngle_TextureCircle; + } + } + + public static float FloatAngle(Rect rect, float value) + { + return FloatAngle(rect, value, -1, -1, -1); + } + + public static float FloatAngle(Rect rect, float value, float snap) + { + return FloatAngle(rect, value, snap, -1, -1); + } + + public static float FloatAngle(Rect rect, float value, float snap, float min, float max) + { + int id = GUIUtility.GetControlID(FocusType.Passive, rect); + + Rect knobRect = new Rect(rect.x, rect.y, rect.height, rect.height); + + float delta; + if (min != max) + delta = (max - min) / 360; + else + delta = 1; + + if (UnityEngine.Event.current != null) + { + if (UnityEngine.Event.current.type == EventType.MouseDown && knobRect.Contains(UnityEngine.Event.current.mousePosition)) + { + GUIUtility.hotControl = id; + mAngle_lastMousePosition = UnityEngine.Event.current.mousePosition; + } + else if (UnityEngine.Event.current.type == EventType.MouseUp && GUIUtility.hotControl == id) + GUIUtility.hotControl = -1; + else if (UnityEngine.Event.current.type == EventType.MouseDrag && GUIUtility.hotControl == id) + { + Vector2 move = mAngle_lastMousePosition - UnityEngine.Event.current.mousePosition; + value += delta * (-move.x - move.y); + + if (snap > 0) + { + float mod = value % snap; + + if (mod < delta * 3 || Mathf.Abs(mod - snap) < delta * 3) + value = Mathf.Round(value / snap) * snap; + } + + mAngle_lastMousePosition = UnityEngine.Event.current.mousePosition; + GUI.changed = true; + } + } + + if (pAngle_TextureCircle) GUI.DrawTexture(knobRect, pAngle_TextureCircle); + Matrix4x4 matrix = GUI.matrix; + + if (min != max) + GUIUtility.RotateAroundPivot(value * (360 / (max - min)), knobRect.center); + else + GUIUtility.RotateAroundPivot(value, knobRect.center); + + knobRect.height = 5; + knobRect.width = 5; + if (pAngle_TextureCircle) GUI.DrawTexture(knobRect, pAngle_TextureCircle); + GUI.matrix = matrix; + + Rect label = new Rect(rect.x + rect.height, rect.y + rect.height / 2 - 9, rect.height, 18); + value = EditorGUI.FloatField(label, value); + + if (min != max) + value = Mathf.Clamp(value, min, max); + + return value; + } + + public static float AngleCircle(Rect rect, float angle, float snap, float min, float max, Texture background=null, Texture knobLine=null) + { + Rect knobRect = new Rect(rect.x, rect.y, rect.height, rect.height); + + float delta; + if (min != max) + delta = (max - min) / 360; + else + delta = 1; + + if (UnityEngine.Event.current != null && GUIUtility.hotControl<=0 && (UnityEngine.Event.current.type==EventType.MouseDown || UnityEngine.Event.current.type==EventType.MouseDrag) && knobRect.Contains(UnityEngine.Event.current.mousePosition)) + { + angle = Vector2.Angle( Vector2.right, UnityEngine.Event.current.mousePosition-knobRect.center); + if (UnityEngine.Event.current.mousePosition.y 0) + { + float mod = Mathf.Repeat(angle, snap); + + if (mod < delta * 3 || Mathf.Abs(mod - snap) < delta * 3) + angle = Mathf.Round(angle / snap) * snap; + } + + GUI.changed = true; + } + + if (background==null) background = pAngle_TextureCircle; + if (background) GUI.DrawTexture (knobRect, background); + + Matrix4x4 matrix = GUI.matrix; + + if (min != max) + GUIUtility.RotateAroundPivot(angle * (360 / (max - min))+90, knobRect.center); + else + GUIUtility.RotateAroundPivot(angle+90, knobRect.center); + + float Radius = Mathf.Min (knobRect.width, knobRect.height) * 0.5f; + knobRect.x = knobRect.x + 0.5f * knobRect.width - 4; + knobRect.y += 2; + knobRect.width = 8; + knobRect.height = Radius+2; + if (knobLine == null) + knobLine = GUI.skin.FindStyle ("MeBlendPosition").normal.background; + if (knobLine) GUI.DrawTexture(knobRect, knobLine); + GUI.matrix = matrix; + + return Mathf.Repeat(angle, 360); + } + #endregion + + #region Unity Version branching + + public static string Editor_GetCurrentScene() + { + #if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 + return EditorApplication.currentScene; + #else + return SceneManager.GetActiveScene().path; + #endif + } + + public static void Editor_MarkSceneDirty() + { + #if UNITY_5_3 || UNITY_5_3_OR_NEWER + EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + #else + EditorApplication.MarkSceneDirty(); + #endif + } + + public static void Editor_SaveScene() + { + #if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 + EditorApplication.SaveScene (); + #else + EditorSceneManager.SaveOpenScenes(); + #endif + } + + public static void Editor_OpenScene( string sceneName ) + { + #if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 + EditorApplication.OpenScene( sceneName ); + #else + EditorSceneManager.OpenScene(sceneName); + #endif + } + + #endregion + + #region Reflection + static public object Reflection_InvokeMethod ( object instanceObject, string methodName, params object[] p_args ) + { + BindingFlags _flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static; + MethodInfo mi = instanceObject.GetType().GetMethods( _flags ).Where( x => x.Name==methodName ).FirstOrDefault(); + if (mi == null) return null; + return mi.Invoke( instanceObject, p_args ); + } + static public object Reflection_InvokeMethod ( Type targetType, string methodName, params object[] p_args ) + { + BindingFlags _flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static; + MethodInfo mi = targetType.GetMethods( _flags ).Where( x => x.Name==methodName ).FirstOrDefault(); + if (mi == null) return null; + return mi.Invoke( null, p_args ); + } + + + public static object s_RecycledEditor; + public static string TextField ( Rect position, string text, int maxLength, GUIStyle style, int controlID ) + { + if (s_RecycledEditor==null) + { + FieldInfo info = typeof(EditorGUI).GetField("s_RecycledEditor", BindingFlags.NonPublic | BindingFlags.Static); + s_RecycledEditor = info?.GetValue(null); + } + + if (s_RecycledEditor == null) + return ""; + + return Reflection_InvokeMethod( typeof( EditorGUI ), "DoTextField", s_RecycledEditor, controlID, position, text, style, null, false, false, false, false ) as string; + + } + + static public void RepaintInspectors() + { + EditorApplication.update -= RepaintInspectors; + var assemblyEditor = Assembly.GetAssembly(typeof(UnityEditor.Editor)); + var typeInspectorWindow = assemblyEditor.GetType("UnityEditor.InspectorWindow"); + typeInspectorWindow.GetMethod("RepaintAllInspectors", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null); + } + + public static void ScheduleRepaintInspectors() + { + EditorApplication.update += RepaintInspectors; + } + + + #endregion + + #if UNITY_2022_3_OR_NEWER + public const string Style_ToolbarSearchTextField = "ToolbarSearchTextField"; + public const string Style_ToolbarSearchCancelButtonEmpty = "ToolbarSearchCancelButtonEmpty"; + public const string Style_ToolbarSearchCancelButton = "ToolbarSearchCancelButton"; + #else + public const string Style_ToolbarSearchTextField = "ToolbarSeachTextField"; + public const string Style_ToolbarSearchCancelButtonEmpty = "ToolbarSeachCancelButtonEmpty"; + public const string Style_ToolbarSearchCancelButton = "ToolbarSeachCancelButton"; + #endif + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Localization/EditorTools.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/EditorTools.cs.meta new file mode 100644 index 00000000..de59c6b6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/EditorTools.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: df33c1000ac895241a433812e40a2096 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors.meta new file mode 100644 index 00000000..8a09e58e --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a500716e59f61824ba1fa6b418ce31a7 +folderAsset: yes +timeCreated: 1461137613 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceAssetInspector.cs b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceAssetInspector.cs new file mode 100644 index 00000000..f6187b4c --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceAssetInspector.cs @@ -0,0 +1,20 @@ +using UnityEditor; + +namespace TEngine.Localization +{ + [CustomEditor(typeof(LanguageSourceAsset))] + public class LanguageSourceAssetInspector : LocalizationEditor + { + void OnEnable() + { + var newSource = target as LanguageSourceAsset; + SerializedProperty propSource = serializedObject.FindProperty("mSource"); + + Custom_OnEnable(newSource.mSource, propSource); + } + public override LanguageSourceData GetSourceData() + { + return (target as LanguageSourceAsset).mSource; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceAssetInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceAssetInspector.cs.meta new file mode 100644 index 00000000..ef8182c4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceAssetInspector.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f03a75bf70a306a4fb36646f24c1c1f1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceInspector.cs b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceInspector.cs new file mode 100644 index 00000000..b11b01ae --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceInspector.cs @@ -0,0 +1,22 @@ +using UnityEditor; + +namespace TEngine.Localization +{ + [CustomEditor(typeof(LanguageSource))] + public class LanguageSourceInspector : LocalizationEditor + { + void OnEnable() + { + var newSource = target as LanguageSource; + SerializedProperty propSource = serializedObject.FindProperty("mSource"); + + Custom_OnEnable(newSource.mSource, propSource); + } + + public override LanguageSourceData GetSourceData() + { + return (target as LanguageSource).mSource; + } + + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceInspector.cs.meta new file mode 100644 index 00000000..ce993bdf --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LanguageSourceInspector.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a441ed994a43a0a4a9d33be67a8d3f15 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationEditor.cs b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationEditor.cs new file mode 100644 index 00000000..a9c4cfcc --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationEditor.cs @@ -0,0 +1,200 @@ +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public abstract partial class LocalizationEditor : UnityEditor.Editor + { + #region Variables + + SerializedProperty mProp_Assets, mProp_Languages, + mProp_Google_WebServiceURL, mProp_GoogleUpdateFrequency, mProp_GoogleUpdateDelay, mProp_Google_SpreadsheetKey, mProp_Google_SpreadsheetName, mProp_Google_Password, + mProp_Spreadsheet_LocalFileName, mProp_Spreadsheet_LocalCSVSeparator, mProp_CaseInsensitiveTerms, mProp_Spreadsheet_LocalCSVEncoding, + mProp_OnMissingTranslation, mProp_AppNameTerm, mProp_IgnoreDeviceLanguage, mProp_Spreadsheet_SpecializationAsRows, mProp_Spreadsheet_SortRows, mProp_GoogleInEditorCheckFrequency, + mProp_HighlightLocalizedTargets, mProp_GoogleLiveSyncIsUptoDate, mProp_AllowUnloadingLanguages, mProp_GoogleUpdateSynchronization; + + public static LanguageSourceData mLanguageSource; + public static Object mLanguageSourceObject; + public static LocalizationEditor mLanguageSourceEditor; + public static UnityEditor.Editor mCurrentInspector; + + static bool mIsParsing; // This is true when the editor is opening several scenes to avoid reparsing objects + + #endregion + + #region Variables GUI + + GUIStyle Style_ToolBar_Big, Style_ToolBarButton_Big; + + + public GUISkin CustomSkin; + + static Vector3 mScrollPos_Languages; + public static string mLanguages_NewLanguage = ""; + + #endregion + + #region Styles + + public static GUIStyle Style_WrapTextField { + get{ + if (mStyle_WrapTextField==null) + { + mStyle_WrapTextField = new GUIStyle(EditorStyles.textArea); + mStyle_WrapTextField.wordWrap = true; + mStyle_WrapTextField.fixedHeight = 0; + } + return mStyle_WrapTextField; + } + } + static GUIStyle mStyle_WrapTextField; + + #endregion + + #region Inspector + + public void Custom_OnEnable( LanguageSourceData sourceData, SerializedProperty propSource) + { + bool ForceParse = mLanguageSource != sourceData; + + mLanguageSource = sourceData; + mLanguageSourceEditor = this; + mCurrentInspector = this; + + if (!LocalizationManager.Sources.Contains(mLanguageSource)) + LocalizationManager.UpdateSources(); + + mProp_Assets = propSource.FindPropertyRelative("Assets"); + mProp_Languages = propSource.FindPropertyRelative("mLanguages"); + mProp_Google_WebServiceURL = propSource.FindPropertyRelative("Google_WebServiceURL"); + mProp_GoogleUpdateFrequency = propSource.FindPropertyRelative("GoogleUpdateFrequency"); + mProp_GoogleUpdateSynchronization = propSource.FindPropertyRelative("GoogleUpdateSynchronization"); + mProp_GoogleInEditorCheckFrequency = propSource.FindPropertyRelative("GoogleInEditorCheckFrequency"); + mProp_GoogleUpdateDelay = propSource.FindPropertyRelative("GoogleUpdateDelay"); + mProp_Google_SpreadsheetKey = propSource.FindPropertyRelative("Google_SpreadsheetKey"); + mProp_Google_SpreadsheetName = propSource.FindPropertyRelative("Google_SpreadsheetName"); + mProp_Google_Password = propSource.FindPropertyRelative("Google_Password"); + mProp_CaseInsensitiveTerms = propSource.FindPropertyRelative("CaseInsensitiveTerms"); + mProp_Spreadsheet_LocalFileName = propSource.FindPropertyRelative("Spreadsheet_LocalFileName"); + mProp_Spreadsheet_LocalCSVSeparator = propSource.FindPropertyRelative("Spreadsheet_LocalCSVSeparator"); + mProp_Spreadsheet_LocalCSVEncoding = propSource.FindPropertyRelative("Spreadsheet_LocalCSVEncoding"); + mProp_Spreadsheet_SpecializationAsRows = propSource.FindPropertyRelative("Spreadsheet_SpecializationAsRows"); + mProp_Spreadsheet_SortRows = propSource.FindPropertyRelative("Spreadsheet_SortRows"); + mProp_OnMissingTranslation = propSource.FindPropertyRelative("OnMissingTranslation"); + mProp_AppNameTerm = propSource.FindPropertyRelative("mTerm_AppName"); + mProp_IgnoreDeviceLanguage = propSource.FindPropertyRelative("IgnoreDeviceLanguage"); + mProp_GoogleLiveSyncIsUptoDate = propSource.FindPropertyRelative("GoogleLiveSyncIsUptoDate"); + mProp_AllowUnloadingLanguages = propSource.FindPropertyRelative("_AllowUnloadingLanguages"); + + if (!mIsParsing) + { + if (string.IsNullOrEmpty(mLanguageSource.Google_SpreadsheetKey)) + mSpreadsheetMode = eSpreadsheetMode.Local; + else + mSpreadsheetMode = eSpreadsheetMode.Google; + + mCurrentViewMode = mLanguageSource.mLanguages.Count>0 ? eViewMode.Keys : eViewMode.Languages; + + UpdateSelectedKeys(); + + if (ForceParse || mParsedTerms.Count < mLanguageSource.mTerms.Count) + { + mSelectedCategories.Clear(); + ParseTerms(true, false, true); + } + } + ScheduleUpdateTermsToShowInList(); + LoadSelectedCategories(); + //UpgradeManager.EnablePlugins(); + } + + void OnDisable() + { + //LocalizationManager.LocalizeAll(); + SaveSelectedCategories(); + mLanguageSourceEditor = null; + if (mCurrentInspector==this) mCurrentInspector = null; + } + + + void UpdateSelectedKeys() + { + // Remove all keys that are not in this source + string trans; + for (int i=mSelectedKeys.Count-1; i>=0; --i) + if (!mLanguageSource.TryGetTranslation(mSelectedKeys[i], out trans)) + mSelectedKeys.RemoveAt(i); + + // Remove all Categories that are not in this source + /*var mCateg = mLanguageSource.GetCategories(); + for (int i=mSelectedCategories.Count-1; i>=0; --i) + if (!mCateg.Contains(mSelectedCategories[i])) + mSelectedCategories.RemoveAt(i); + if (mSelectedCategories.Count==0) + mSelectedCategories = mCateg;*/ + + if (mSelectedScenes.Count==0) + mSelectedScenes.Add (Editor_GetCurrentScene()); + } + + public override void OnInspectorGUI() + { + // Load Test: + /*if (mLanguageSource.mTerms.Count<40000) + { + mLanguageSource.mTerms.Clear(); + for (int i=0; i<40020; ++i) + mLanguageSource.AddTerm("ahh"+i.ToString("00000"), eTermType.Text, false); + mLanguageSource.UpdateDictionary(); + }*/ + //Profiler.maxNumberOfSamplesPerFrame = -1; // REMOVE --------------------------------------------------- + + mIsParsing = false; + + //#if UNITY_5_6_OR_NEWER + // serializedObject.UpdateIfRequiredOrScript(); + //#else + // serializedObject.UpdateIfDirtyOrScript(); + //#endif + + if (mLanguageSource.mTerms.Count<1000) + Undo.RecordObject(target, "LanguageSource"); + + //GUI.backgroundColor = Color.Lerp (Color.black, Color.gray, 1); + //GUILayout.BeginVertical(LocalizeInspector.GUIStyle_Background); + //GUI.backgroundColor = Color.white; + + if (GUILayout.Button("Language Source", LocalizeInspector.GUIStyle_Header)) + { + Application.OpenURL(LocalizeInspector.HelpURL_Documentation); + } + + InitializeStyles(); + + GUILayout.Space(10); + + //GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f); + //GUILayout.BeginVertical(LocalizeInspector.GUIStyle_Background); + //GUI.backgroundColor = Color.white; + OnGUI_Main(); + //GUILayout.EndVertical(); + + GUILayout.Space (10); + GUILayout.FlexibleSpace(); + + GUITools.OnGUI_Footer("I2 Localization", LocalizationManager.GetVersion(), LocalizeInspector.HelpURL_forum, LocalizeInspector.HelpURL_Documentation, LocalizeInspector.HelpURL_AssetStore); + + //GUILayout.EndVertical(); + + serializedObject.ApplyModifiedProperties(); + if (UnityEngine.Event.current.type == EventType.Repaint) + { + mTestAction = eTest_ActionType.None; + mTestActionArg = null; + mTestActionArg2 = null; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationEditor.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationEditor.cs.meta new file mode 100644 index 00000000..34e4a0e9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 90c932abd0dc445448366dfe101408ba +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationParamsManagerInspector.cs b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationParamsManagerInspector.cs new file mode 100644 index 00000000..b8603c12 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationParamsManagerInspector.cs @@ -0,0 +1,107 @@ +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace TEngine.Localization +{ + [CustomEditor(typeof(LocalizationParamsManager))] + public class LocalizationParamsManagerInspector : UnityEditor.Editor + { + private ReorderableList mList; + private SerializedProperty mProp_IsGlobalManager; + + + private ReorderableList getList(SerializedObject serObject) + { + if (mList == null) { + mList = new ReorderableList (serObject, serObject.FindProperty ("_Params"), true, true, true, true); + mList.drawElementCallback = drawElementCallback; + mList.drawHeaderCallback = drawHeaderCallback; + mList.onAddCallback = addElementCallback; + mList.onRemoveCallback = removeElementCallback; + } + else + { + mList.serializedProperty = serObject.FindProperty ("_Params"); + } + return mList; + } + + private void addElementCallback( ReorderableList list ) + { + serializedObject.ApplyModifiedProperties(); + var objParams = target as LocalizationParamsManager; + objParams._Params.Add(new LocalizationParamsManager.ParamValue()); + list.index = objParams._Params.Count - 1; + serializedObject.Update(); + } + + private void removeElementCallback( ReorderableList list ) + { + if (list.index < 0) + return; + serializedObject.ApplyModifiedProperties(); + var objParams = target as LocalizationParamsManager; + objParams._Params.RemoveAt(list.index); + serializedObject.Update(); + } + + private void drawHeaderCallback(Rect rect) + { + GUI.Label(rect, "Parameters:"); + } + + private void drawElementCallback(Rect rect, int index, bool isActive, bool isFocused) + { + var serializedElement = mList.serializedProperty.GetArrayElementAtIndex (index); + var content = new GUIContent (); + + Rect r = rect; r.xMax = r.xMin+40; + GUI.Label(r, "Name"); + + r = rect; r.xMax = (r.xMax + r.xMin)/2 - 2; r.xMin = r.xMin+40; + EditorGUI.PropertyField (r, serializedElement.FindPropertyRelative ("Name"),content); + + r = rect; r.xMin = (r.xMax + r.xMin) / 2 + 2; r.xMax = r.xMin+40; + GUI.Label(r, "Value"); + + r = rect; r.xMin = (r.xMax + r.xMin)/2 + 2 + 40; + EditorGUI.PropertyField (r, serializedElement.FindPropertyRelative ("Value"), content); + } + + void OnEnable() + { + mList = getList(serializedObject); + mProp_IsGlobalManager = serializedObject.FindProperty("_IsGlobalManager"); + } + public override void OnInspectorGUI() + { + #if UNITY_5_6_OR_NEWER + serializedObject.UpdateIfRequiredOrScript(); + #else + serializedObject.UpdateIfDirtyOrScript(); + #endif + + GUI.backgroundColor = Color.Lerp (Color.black, Color.gray, 1); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_Background); + GUI.backgroundColor = Color.white; + + if (GUILayout.Button("Dynamic Parameters", LocalizeInspector.GUIStyle_Header)) + { + Application.OpenURL(LocalizeInspector.HelpURL_Documentation); + } + + GUILayout.Space(5); + mProp_IsGlobalManager.boolValue = EditorGUILayout.Popup(new GUIContent("Manager Type", "Local Manager only apply parameters to the Localize component in the same GameObject\n\nGlobal Manager apply parameters to all Localize components"), mProp_IsGlobalManager.boolValue ? 1 : 0, new[] { new GUIContent("Local"), new GUIContent("Global") }) == 1; + + + GUILayout.Space(5); + mList.DoLayoutList(); + + //EditorGUILayout.PropertyField(serializedObject.FindProperty("_AutoRegister"), new GUIContent("Auto Register")); + + GUILayout.EndVertical(); + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationParamsManagerInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationParamsManagerInspector.cs.meta new file mode 100644 index 00000000..8c96c158 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizationParamsManagerInspector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 93f1f9aecf6f7ed40ad1a082c22c47e5 +timeCreated: 1468111539 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeDropdownInspector.cs b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeDropdownInspector.cs new file mode 100644 index 00000000..0244d51a --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeDropdownInspector.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace TEngine.Localization +{ + #if !UNITY_5_0 && !UNITY_5_1 + + [CustomEditor(typeof(LocalizeDropdown))] + public class LocalizeDropdownInspector : UnityEditor.Editor + { + private ReorderableList mList; + + private List terms; + + private ReorderableList getList(SerializedObject serObject) + { + if (mList == null) { + mList = new ReorderableList (serObject, serObject.FindProperty ("_Terms"), true, true, true, true); + mList.drawElementCallback = drawElementCallback; + mList.drawHeaderCallback = drawHeaderCallback; + mList.onAddCallback = addElementCallback; + mList.onRemoveCallback = removeElementCallback; + } + else + { + mList.serializedProperty = serObject.FindProperty ("_Terms"); + } + return mList; + } + + private void addElementCallback( ReorderableList list ) + { + serializedObject.ApplyModifiedProperties(); + + var objParams = target as LocalizeDropdown; + objParams._Terms.Add(string.Empty); + + list.index = objParams._Terms.Count - 1; + + serializedObject.Update(); + } + + private void removeElementCallback( ReorderableList list ) + { + if (list.index < 0) + return; + serializedObject.ApplyModifiedProperties(); + + var objParams = target as LocalizeDropdown; + objParams._Terms.RemoveAt(list.index); + + serializedObject.Update(); + } + + private void drawHeaderCallback(Rect rect) + { + GUI.Label(rect, "Terms:"); + } + + private void drawElementCallback(Rect rect, int index, bool isActive, bool isFocused) + { + var serializedElement = mList.serializedProperty.GetArrayElementAtIndex (index); + + EditorGUI.BeginChangeCheck (); + + var prvIndex = serializedElement.stringValue == "-" || serializedElement.stringValue == "" ? terms.Count - 1 : + serializedElement.stringValue == " " ? terms.Count - 2 : + terms.IndexOf(serializedElement.stringValue); + + var newIndex = EditorGUI.Popup(rect, prvIndex, terms.ToArray()); + + if (EditorGUI.EndChangeCheck ()) + { + if (newIndex == terms.Count - 1) + serializedElement.stringValue = "-"; + else + if (newIndex < 0 || newIndex == terms.Count - 2) + serializedElement.stringValue = string.Empty; + else + serializedElement.stringValue = terms[newIndex]; + } + } + + void OnEnable() + { + mList = getList(serializedObject); + } + + public override void OnInspectorGUI() + { + #if UNITY_5_6_OR_NEWER + serializedObject.UpdateIfRequiredOrScript(); + #else + serializedObject.UpdateIfDirtyOrScript(); + #endif + terms = LocalizationManager.GetTermsList (); + terms.Sort(StringComparer.OrdinalIgnoreCase); + terms.Add(""); + terms.Add(""); + terms.Add(""); + + GUI.backgroundColor = Color.Lerp (Color.black, Color.gray, 1); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_Background); + GUI.backgroundColor = Color.white; + + if (GUILayout.Button("Localize DropDown", LocalizeInspector.GUIStyle_Header)) + { + Application.OpenURL(LocalizeInspector.HelpURL_Documentation); + } + + + GUILayout.Space(5); + mList.DoLayoutList(); + + GUILayout.Space (10); + + GUITools.OnGUI_Footer("I2 Localization", LocalizationManager.GetVersion(), LocalizeInspector.HelpURL_forum, LocalizeInspector.HelpURL_Documentation, LocalizeInspector.HelpURL_AssetStore); + + EditorGUIUtility.labelWidth = 0; + + + GUILayout.EndVertical(); + serializedObject.ApplyModifiedProperties(); + terms = null; + } + } + #endif +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeDropdownInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeDropdownInspector.cs.meta new file mode 100644 index 00000000..fb4a5ed1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeDropdownInspector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 65bbef08e6e42d24d9834945c3769202 +timeCreated: 1468111539 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeInspector.cs b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeInspector.cs new file mode 100644 index 00000000..c80e822b --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeInspector.cs @@ -0,0 +1,896 @@ +//#define UGUI +//#define NGUI +//#define DFGUI + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace TEngine.Localization +{ + [CustomEditor(typeof(Localize))] + [CanEditMultipleObjects] + public class LocalizeInspector : UnityEditor.Editor + { + #region Variables + + Localize mLocalize; + SerializedProperty mProp_mTerm, mProp_mTermSecondary, + mProp_TranslatedObjects, mProp_LocalizeOnAwake, mProp_AlwaysForceLocalize, mProp_AllowLocalizedParameters, mProp_AllowParameters, + mProp_IgnoreRTL, mProp_MaxCharactersInRTL, mProp_CorrectAlignmentForRTL, mProp_IgnoreNumbersInRTL, mProp_TermSuffix, mProp_TermPrefix, mProp_SeparateWords, + mProp_CallbackEvent; + + + bool mAllowEditKeyName; + string mNewKeyName = ""; + + string[] mTermsArray; + + + public static string HelpURL_forum = "http://goo.gl/Uiyu8C";//http://www.inter-illusion.com/forum/i2-localization"; + public static string HelpURL_Documentation = "http://www.inter-illusion.com/assets/I2LocalizationManual/I2LocalizationManual.html"; + public static string HelpURL_Tutorials = "http://inter-illusion.com/tools/i2-localization"; + public static string HelpURL_ReleaseNotes = "http://inter-illusion.com/forum/i2-localization/26-release-notes"; + public static string HelpURL_AssetStore = "https://www.assetstore.unity3d.com/#!/content/14884"; + + public static LocalizeInspector mLocalizeInspector; + #endregion + + #region Inspector + + void OnEnable() + { + mLocalize = (Localize)target; + mLocalizeInspector = this; + LocalizationEditor.mCurrentInspector = this; + mProp_mTerm = serializedObject.FindProperty("mTerm"); + mProp_mTermSecondary = serializedObject.FindProperty("mTermSecondary"); + mProp_TranslatedObjects = serializedObject.FindProperty("TranslatedObjects"); + mProp_IgnoreRTL = serializedObject.FindProperty("IgnoreRTL"); + mProp_SeparateWords = serializedObject.FindProperty("AddSpacesToJoinedLanguages"); + mProp_MaxCharactersInRTL = serializedObject.FindProperty ("MaxCharactersInRTL"); + mProp_IgnoreNumbersInRTL = serializedObject.FindProperty("IgnoreNumbersInRTL"); + mProp_CorrectAlignmentForRTL = serializedObject.FindProperty ("CorrectAlignmentForRTL"); + mProp_LocalizeOnAwake = serializedObject.FindProperty("LocalizeOnAwake"); + mProp_AlwaysForceLocalize = serializedObject.FindProperty("AlwaysForceLocalize"); + mProp_TermSuffix = serializedObject.FindProperty("TermSuffix"); + mProp_TermPrefix = serializedObject.FindProperty("TermPrefix"); + mProp_CallbackEvent = serializedObject.FindProperty("LocalizeEvent"); + mProp_AllowLocalizedParameters = serializedObject.FindProperty("AllowLocalizedParameters"); + mProp_AllowParameters = serializedObject.FindProperty("AllowParameters"); + + + if (LocalizationManager.Sources.Count==0) + LocalizationManager.UpdateSources(); + //LocalizationEditor.ParseTerms (true); + + //mGUI_ShowReferences = (mLocalize.TranslatedObjects!=null && mLocalize.TranslatedObjects.Length>0); + //mGUI_ShowCallback = (mLocalize.LocalizeCallBack.Target!=null); + //mGUI_ShowTems = true; + LocalizationEditor.mKeysDesc_AllowEdit = false; + GUI_SelectedTerm = 0; + mNewKeyName = mLocalize.Term; + + if (mLocalize.Source != null) + LocalizationEditor.mLanguageSource = mLocalize.Source.SourceData; + else + { + if (LocalizationManager.Sources.Count==0) + LocalizationManager.UpdateSources(); + LocalizationEditor.mLanguageSource = LocalizationManager.GetSourceContaining( mLocalize.Term ); + } + + //UpgradeManager.EnablePlugins(); + LocalizationEditor.ApplyInferredTerm (mLocalize); + RemoveUnusedReferences(mLocalize); + } + + void OnDisable() + { + mLocalizeInspector = null; + if (LocalizationEditor.mCurrentInspector == this) LocalizationEditor.mCurrentInspector = null; + + + if (mLocalize == null) + return; + + //#if TextMeshPro + //string previous = null; + + //if (!Application.isPlaying && !string.IsNullOrEmpty(mLocalize.TMP_previewLanguage)) + //{ + // previous = LocalizationManager.CurrentLanguage; + // LocalizationManager.PreviewLanguage( mLocalize.TMP_previewLanguage ); + //} + //#endif + + //mLocalize.OnLocalize(); + + // Revert the preview language + // except when in TMPro and not changing to another GameObject (TMPro has a bug where any change causes the inspector to Disable and Enable) + if (!mLocalize.mLocalizeTargetName.Contains("LocalizeTarget_TextMeshPro") || Selection.activeGameObject==null || !Selection.gameObjects.Contains(mLocalize.gameObject)) + { + LocalizationManager.LocalizeAll(); + } + + //#if TextMeshPro + //if (!string.IsNullOrEmpty(previous)) + //{ + // LocalizationManager.PreviewLanguage(previous); + // mLocalize.TMP_previewLanguage = null; + //} + //#endif + + RemoveUnusedReferences(mLocalize); + } + + #endregion + + #region GUI + + public override void OnInspectorGUI() + { + Undo.RecordObject(target, "Localize"); + + //GUI.backgroundColor = Color.Lerp (Color.black, Color.gray, 1); + //GUILayout.BeginVertical(GUIStyle_Background, GUILayout.Height(1)); + //GUI.backgroundColor = Color.white; + + if (GUILayout.Button("Localize", GUIStyle_Header)) + { + //Application.OpenURL(HelpURL_Documentation); + } + GUILayout.Space(-10); + + LocalizationManager.UpdateSources(); + + if (LocalizationManager.Sources.Count==0) + { + EditorGUILayout.HelpBox("Unable to find a Language Source.", MessageType.Warning); + } + else + { + GUILayout.Space(10); + OnGUI_Target (); + GUILayout.Space(10); + OnGUI_Terms(); + + //if (mGUI_ShowTems || mGUI_ShowReferences) GUILayout.Space(5); + + OnGUI_References(); + + if (mLocalize.mGUI_ShowReferences || mLocalize.mGUI_ShowCallback) GUILayout.Space(10); + + //Localize loc = target as Localize; + + //--[ Localize Callback ]---------------------- + EditorGUILayout.PropertyField(mProp_CallbackEvent, new GUIContent("On Localize Callback")); + + //string HeaderTitle = "On Localize Call:"; + //if (!mLocalize.mGUI_ShowCallback && loc.LocalizeCallBack.Target!=null && !string.IsNullOrEmpty(loc.LocalizeCallBack.MethodName)) + // HeaderTitle = string.Concat(HeaderTitle, " ",loc.LocalizeCallBack.Target.name, ".", loc.LocalizeCallBack.MethodName, ""); + //mLocalize.mGUI_ShowCallback = GUITools.DrawHeader(HeaderTitle, mLocalize.mGUI_ShowCallback); + //if (mLocalize.mGUI_ShowCallback) + //{ + // GUITools.BeginContents(); + // DrawEventCallBack( loc.LocalizeCallBack, loc ); + // GUITools.EndContents(); + //} + } + OnGUI_Source (); + + GUILayout.Space (10); + + GUITools.OnGUI_Footer("I2 Localization", LocalizationManager.GetVersion(), HelpURL_forum, HelpURL_Documentation, HelpURL_AssetStore); + + //GUILayout.EndVertical(); + + serializedObject.ApplyModifiedProperties(); + if (UnityEngine.Event.current.type == EventType.Repaint) + { + LocalizationEditor.mTestAction = LocalizationEditor.eTest_ActionType.None; + LocalizationEditor.mTestActionArg = null; + LocalizationEditor.mTestActionArg2 = null; + } + } + + #endregion + + #region References + + void OnGUI_References() + { + if (mLocalize.mGUI_ShowReferences = GUITools.DrawHeader ("References", mLocalize.mGUI_ShowReferences)) + { + GUITools.BeginContents(); + + bool canTest = UnityEngine.Event.current.type == EventType.Repaint; + + var testAddObj = canTest && LocalizationEditor.mTestAction == LocalizationEditor.eTest_ActionType.Button_Assets_Add ? (Object)LocalizationEditor.mTestActionArg : null; + var testReplaceIndx = canTest && LocalizationEditor.mTestAction == LocalizationEditor.eTest_ActionType.Button_Assets_Replace ? (int)LocalizationEditor.mTestActionArg : -1; + var testReplaceObj = canTest && LocalizationEditor.mTestAction == LocalizationEditor.eTest_ActionType.Button_Assets_Replace ? (Object)LocalizationEditor.mTestActionArg2 : null; + var testDeleteIndx = canTest && LocalizationEditor.mTestAction == LocalizationEditor.eTest_ActionType.Button_Assets_Delete ? (int)LocalizationEditor.mTestActionArg : -1; + + bool changed = GUITools.DrawObjectsArray( mProp_TranslatedObjects, false, false, true, testAddObj, testReplaceObj, testReplaceIndx, testDeleteIndx); + if (changed) + { + serializedObject.ApplyModifiedProperties(); + foreach (var obj in serializedObject.targetObjects) + (obj as Localize).UpdateAssetDictionary(); + } + + GUITools.EndContents(); + } + } + + void RemoveUnusedReferences(Localize cmp) + { + cmp.TranslatedObjects.RemoveAll(x => !IsUsingReference(LocalizationManager.GetTermData(cmp.Term), x) && !IsUsingReference(LocalizationManager.GetTermData(cmp.SecondaryTerm), x)); + if (cmp.TranslatedObjects.Count != cmp.mAssetDictionary.Count) + cmp.UpdateAssetDictionary(); + } + + bool IsUsingReference(TermData termData, Object obj ) + { + if (obj == null || termData==null) return false; + + string objName = obj.name; + foreach (string translation in termData.Languages) + { + if (translation != null && translation.Contains(objName)) + return true; + } + return false; + } + + + #endregion + + + #region Terms + + int GUI_SelectedTerm; + void OnGUI_Terms() + { + if ((mLocalize.mGUI_ShowTems=GUITools.DrawHeader ("Terms", mLocalize.mGUI_ShowTems))) + { + //--[ tabs: Main and Secondary Terms ]---------------- + int oldTab = GUI_SelectedTerm; + if (mLocalize.mLocalizeTarget!=null && mLocalize.mLocalizeTarget.CanUseSecondaryTerm()) + { + GUI_SelectedTerm = GUITools.DrawTabs (GUI_SelectedTerm, new[]{"Main", "Secondary"}); + } + else + { + GUI_SelectedTerm = 0; + GUITools.DrawTabs (GUI_SelectedTerm, new[]{"Main", ""}); + } + + GUITools.BeginContents(); + + TermData termData = null; + + if (GUI_SelectedTerm==0) termData = OnGUI_PrimaryTerm( oldTab!=GUI_SelectedTerm ); + else termData = OnGUI_SecondaryTerm(oldTab!=GUI_SelectedTerm); + + GUITools.EndContents(); + + //--[ Modifier ]------------- + if (mLocalize.Term != "-" && termData!=null && termData.TermType==eTermType.Text) + { + EditorGUI.BeginChangeCheck(); + GUILayout.BeginHorizontal(); + GUILayout.Label("Prefix:"); + EditorGUILayout.PropertyField(mProp_TermPrefix, GUITools.EmptyContent); + GUILayout.Label("Suffix:"); + EditorGUILayout.PropertyField(mProp_TermSuffix, GUITools.EmptyContent); + GUILayout.EndHorizontal(); + if (EditorGUI.EndChangeCheck()) + { + EditorApplication.delayCall += () => + { + if (targets != null) + { + foreach (var t in targets) + if (t as Localize != null) + (t as Localize).OnLocalize(true); + } + }; + } + EditorGUI.BeginChangeCheck(); + int val = EditorGUILayout.Popup("Modifier", GUI_SelectedTerm == 0 ? (int)mLocalize.PrimaryTermModifier : (int)mLocalize.SecondaryTermModifier, Enum.GetNames(typeof(Localize.TermModification))); + if (EditorGUI.EndChangeCheck()) + { + serializedObject.FindProperty(GUI_SelectedTerm == 0 ? "PrimaryTermModifier" : "SecondaryTermModifier").enumValueIndex = val; + GUI.changed = false; + } + } + + OnGUI_Options(); + //--[ OnAwake vs OnEnable ]------------- + //GUILayout.BeginHorizontal(); + //mProp_LocalizeOnAwake.boolValue = GUILayout.Toggle(mProp_LocalizeOnAwake.boolValue, new GUIContent(" Pre-Localize on Awake", "Localizing on Awake could result in a lag when the level is loaded but faster later when objects are enabled. If false, it will Localize OnEnable, so will yield faster level load but could have a lag when screens are enabled")); + //GUILayout.FlexibleSpace(); + //if (mLocalize.HasCallback()) + //{ + // GUI.enabled = false; + // GUILayout.Toggle(true, new GUIContent(" Force Localize", "Enable this when the translations have parameters (e.g. Thew winner is {[WINNER}]) to prevent any optimization that could prevent updating the translation when the object is enabled")); + // GUI.enabled = true; + //} + //else + //{ + // mProp_AlwaysForceLocalize.boolValue = GUILayout.Toggle(mProp_AlwaysForceLocalize.boolValue, new GUIContent(" Force Localize", "Enable this when the translations have parameters (e.g. Thew winner is {[WINNER}]) to prevent any optimization that could prevent updating the translation when the object is enabled")); + //} + //GUILayout.EndHorizontal(); + + //--[ Right To Left ]------------- + if (!mLocalize.IgnoreRTL && mLocalize.Term!="-" && termData != null && termData.TermType == eTermType.Text) + { + GUILayout.BeginVertical("Box"); + //GUILayout.BeginHorizontal(); + // mProp_IgnoreRTL.boolValue = GUILayout.Toggle(mProp_IgnoreRTL.boolValue, new GUIContent(" Ignore Right To Left", "Arabic and other RTL languages require processing them so they render correctly, this toogle allows ignoring that processing (in case you are doing it manually during a callback)")); + // GUILayout.FlexibleSpace(); + // mProp_SeparateWords.boolValue = GUILayout.Toggle(mProp_SeparateWords.boolValue, new GUIContent(" Separate Words", " Some languages (e.g. Chinese, Japanese and Thai) don't add spaces to their words (all characters are placed toguether), enabling this checkbox, will add spaces to all characters to allow wrapping long texts into multiple lines.")); + //GUILayout.EndHorizontal(); + { + mProp_MaxCharactersInRTL.intValue = EditorGUILayout.IntField( new GUIContent("Max line length", "If the language is Right To Left, long lines will be split at this length and the RTL fix will be applied to each line, this should be set to the maximum number of characters that fit in this text width. 0 disables the per line fix"), mProp_MaxCharactersInRTL.intValue ); + GUILayout.BeginHorizontal(); + mProp_CorrectAlignmentForRTL.boolValue = GUILayout.Toggle(mProp_CorrectAlignmentForRTL.boolValue, new GUIContent(" Adjust Alignment", "Right-align when Right-To-Left Language, and Left-Align otherwise") ); + GUILayout.FlexibleSpace(); + mProp_IgnoreNumbersInRTL.boolValue = GUILayout.Toggle(mProp_IgnoreNumbersInRTL.boolValue, new GUIContent(" Ignore Numbers", "Preserve numbers as latin characters instead of converting them")); + GUILayout.EndHorizontal(); + } + + GUILayout.EndVertical(); + } + + + ////GUILayout.EndHorizontal(); + } + } + + void OnGUI_Options() + { + int mask = 0; + if (mProp_LocalizeOnAwake.boolValue) mask |= 1 << 0; + if (mProp_AlwaysForceLocalize.boolValue) mask |= 1 << 1; + if (mProp_AllowParameters.boolValue) mask |= 1 << 2; + if (mProp_AllowLocalizedParameters.boolValue) mask |= 1 << 3; + if (mProp_SeparateWords.boolValue) mask |= 1 << 4; + if (mProp_IgnoreRTL.boolValue) mask |= 1 << 5; + + EditorGUI.BeginChangeCheck(); + mask = EditorGUILayout.MaskField(new GUIContent("Options"), mask, new []{ + "Localize On Awake", + "Force Localize", + "Allow Parameters", + "Allow Localized Parameters", + "Separate Words", + "Ignore RTL" + }); + if (EditorGUI.EndChangeCheck()) + { + mProp_LocalizeOnAwake.boolValue = (mask & (1 << 0))> 0; + mProp_AlwaysForceLocalize.boolValue = (mask & (1 << 1))> 0; + mProp_AllowParameters.boolValue = (mask & (1 << 2))> 0; + mProp_AllowLocalizedParameters.boolValue = (mask & (1 << 3))> 0; + mProp_SeparateWords.boolValue = (mask & (1 << 4))> 0; + mProp_IgnoreRTL.boolValue = (mask & (1 << 5))> 0; + } + } + + TermData OnGUI_PrimaryTerm( bool OnOpen ) + { + string Key = mLocalize.mTerm; + if (string.IsNullOrEmpty(Key)) + { + string SecondaryTerm; + mLocalize.GetFinalTerms( out Key, out SecondaryTerm ); + } + + if (OnOpen) mNewKeyName = Key; + if ( OnGUI_SelectKey( ref Key, string.IsNullOrEmpty(mLocalize.mTerm))) + mProp_mTerm.stringValue = Key; + return LocalizationEditor.OnGUI_Keys_Languages( Key, mLocalize ); + } + + TermData OnGUI_SecondaryTerm( bool OnOpen ) + { + string Key = mLocalize.mTermSecondary; + + if (string.IsNullOrEmpty(Key)) + { + string ss; + mLocalize.GetFinalTerms( out ss, out Key ); + } + + if (OnOpen) mNewKeyName = Key; + if ( OnGUI_SelectKey( ref Key, string.IsNullOrEmpty(mLocalize.mTermSecondary))) + mProp_mTermSecondary.stringValue = Key; + return LocalizationEditor.OnGUI_Keys_Languages( Key, mLocalize, false ); + } + + bool OnGUI_SelectKey( ref string Term, bool Inherited ) // Inherited==true means that the mTerm is empty and we are using the Label.text instead + { + GUILayout.Space (5); + GUILayout.BeginHorizontal(); + + GUI.changed = false; + mAllowEditKeyName = GUILayout.Toggle(mAllowEditKeyName, "Term:", EditorStyles.foldout, GUILayout.ExpandWidth(false)); + if (GUI.changed && mAllowEditKeyName) { + mNewKeyName = Term; + mTermsArray = null; + } + + bool bChanged = false; + + if (mTermsArray==null || Term!="-" && Array.IndexOf(mTermsArray, Term)<0) + UpdateTermsList(Term); + + if (Inherited) + GUI.contentColor = Color.Lerp (Color.gray, Color.yellow, 0.1f); + + int Index = Term=="-" || Term=="" ? mTermsArray.Length-1 : Array.IndexOf( mTermsArray, Term ); + + GUI.changed = false; + + int newIndex = EditorGUILayout.Popup( Index, mTermsArray); + + GUI.contentColor = Color.white; + if (/*newIndex != Index && newIndex>=0*/GUI.changed) + { + GUI.changed = false; + if (mLocalize.Source != null && newIndex == mTermsArray.Length - 4) //< show terms from all sources > + { + mLocalize.Source = null; + mTermsArray = null; + } + else + if (newIndex == mTermsArray.Length - 2) // + mNewKeyName = Term = string.Empty; + else + if (newIndex == mTermsArray.Length - 1) // + mNewKeyName = Term = "-"; + else + mNewKeyName = Term = mTermsArray[newIndex]; + + + if (GUI_SelectedTerm==0) + mLocalize.SetTerm (mNewKeyName); + else + mLocalize.SetTerm (null, mNewKeyName); + mAllowEditKeyName = false; + bChanged = true; + } + + LanguageSourceData source = LocalizationManager.GetSourceContaining(Term); + TermData termData = source.GetTermData(Term); + if (termData!=null) + { + if (Inherited) + bChanged = true; // if the term its inferred and a matching term its found, then use that + eTermType NewType = (eTermType)EditorGUILayout.EnumPopup(termData.TermType, GUILayout.Width(90)); + if (termData.TermType != NewType) + termData.TermType = NewType; + } + + GUILayout.EndHorizontal(); + + if (mAllowEditKeyName) + { + GUILayout.BeginHorizontal(GUILayout.Height (1)); + GUILayout.BeginHorizontal(EditorStyles.toolbar); + if(mNewKeyName==null) mNewKeyName = string.Empty; + + GUI.changed = false; + mNewKeyName = EditorGUILayout.TextField(mNewKeyName, new GUIStyle(GUITools.Style_ToolbarSearchTextField), GUILayout.ExpandWidth(true)); + if (GUI.changed) + { + mTermsArray = null; // regenerate this array to apply filtering + GUI.changed = false; + } + + if (GUILayout.Button (string.Empty, string.IsNullOrEmpty(mNewKeyName) ? GUITools.Style_ToolbarSearchCancelButtonEmpty : GUITools.Style_ToolbarSearchCancelButton, GUILayout.ExpandWidth(false))) + { + mTermsArray = null; // regenerate this array to apply filtering + mNewKeyName = string.Empty; + } + + GUILayout.EndHorizontal(); + + string ValidatedName = mNewKeyName; + LanguageSourceData.ValidateFullTerm( ref ValidatedName ); + + bool CanUseNewName = source.GetTermData(ValidatedName)==null; + GUI.enabled = !string.IsNullOrEmpty(mNewKeyName) && CanUseNewName; + if (GUILayout.Button ("Create", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + { + mNewKeyName = ValidatedName; + mTermsArray=null; // this recreates that terms array + + LanguageSourceData Source = null; + #if UNITY_EDITOR + if (mLocalize.Source!=null) + Source = mLocalize.Source.SourceData; + #endif + + if (Source==null) + Source = LocalizationManager.Sources[0]; + Term = mNewKeyName; + var data = Source.AddTerm( mNewKeyName, eTermType.Text, false ); + if (data.Languages.Length > 0) + data.Languages[0] = mLocalize.GetMainTargetsText(); + Source.Editor_SetDirty(); + AssetDatabase.SaveAssets(); + mAllowEditKeyName = false; + bChanged = true; + GUIUtility.keyboardControl = 0; + } + GUI.enabled = termData!=null && !string.IsNullOrEmpty(mNewKeyName) && CanUseNewName; + if (GUILayout.Button (new GUIContent("Rename","Renames the term in the source and updates every object using it in the current scene"), EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + { + mNewKeyName = ValidatedName; + Term = mNewKeyName; + mTermsArray=null; // this recreates that terms array + mAllowEditKeyName = false; + bChanged = true; + LocalizationEditor.TermReplacements = new Dictionary(StringComparer.Ordinal); + LocalizationEditor.TermReplacements[ termData.Term ] = mNewKeyName; + termData.Term = mNewKeyName; + source.UpdateDictionary(true); + LocalizationEditor.ReplaceTermsInCurrentScene(); + GUIUtility.keyboardControl = 0; + EditorApplication.update += LocalizationEditor.DoParseTermsInCurrentScene; + } + GUI.enabled = true; + GUILayout.EndHorizontal(); + + bChanged |= OnGUI_SelectKey_PreviewTerms ( ref Term); + } + + GUILayout.Space (5); + return bChanged; + } + + void UpdateTermsList( string currentTerm ) + { + List Terms = mLocalize.Source==null ? LocalizationManager.GetTermsList() : mLocalize.Source.SourceData.GetTermsList(); + + // If there is a filter, remove all terms not matching that filter + if (mAllowEditKeyName && !string.IsNullOrEmpty(mNewKeyName)) + { + string Filter = mNewKeyName.ToUpper(); + for (int i=Terms.Count-1; i>=0; --i) + if (!Terms[i].ToUpper().Contains(Filter) && Terms[i]!=currentTerm) + Terms.RemoveAt(i); + + } + + if (!string.IsNullOrEmpty(currentTerm) && currentTerm!="-" && !Terms.Contains(currentTerm)) + Terms.Add (currentTerm); + + Terms.Sort(StringComparer.OrdinalIgnoreCase); + Terms.Add(""); + if (mLocalize.Source != null) + { + Terms.Add("< Show Terms from all sources >"); + Terms.Add(""); + } + Terms.Add(""); + Terms.Add(""); + + mTermsArray = Terms.ToArray(); + } + + bool OnGUI_SelectKey_PreviewTerms ( ref string Term) + { + if (mTermsArray==null) + UpdateTermsList(Term); + + int nTerms = mTermsArray.Length; + if (nTerms<=0) + return false; + + if (nTerms==1 && mTermsArray[0]==Term) + return false; + + bool bChanged = false; + GUI.backgroundColor = Color.gray; + GUILayout.BeginVertical (GUIStyle_OldTextArea); + for (int i = 0, imax = Mathf.Min (nTerms, 3); i < imax; ++i) + { + ParsedTerm parsedTerm; + int nUses = -1; + if (LocalizationEditor.mParsedTerms.TryGetValue (mTermsArray [i], out parsedTerm)) + nUses = parsedTerm.Usage; + + string FoundText = mTermsArray [i]; + if (nUses > 0) + FoundText = string.Concat ("(", nUses, ") ", FoundText); + + if (GUILayout.Button (FoundText, EditorStyles.miniLabel, GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth - 70))) + { + if (mTermsArray[i] == "") + mNewKeyName = Term = string.Empty; + else + if (mTermsArray[i] == "") + mNewKeyName = Term = "-"; + else + if (mTermsArray[i] != "< Show Terms from all sources >") + mNewKeyName = Term = mTermsArray[i]; + + //mNewKeyName = Term = (mTermsArray [i]=="" ? string.Empty : mTermsArray [i]); + GUIUtility.keyboardControl = 0; + mAllowEditKeyName = false; + bChanged = true; + } + } + if (nTerms > 3) + GUILayout.Label ("..."); + GUILayout.EndVertical (); + GUI.backgroundColor = Color.white; + + return bChanged; + } + + #endregion + + #region Target + + void OnGUI_Target() + { + List TargetTypes = new List(); + int CurrentTarget = -1; + + mLocalize.FindTarget(); + + foreach (var desc in LocalizationManager.mLocalizeTargets) + { + if (desc.CanLocalize(mLocalize)) + { + TargetTypes.Add(desc.Name); + + if (mLocalize.mLocalizeTarget!=null && desc.GetTargetType() == mLocalize.mLocalizeTarget.GetType()) + CurrentTarget = TargetTypes.Count - 1; + } + } + + if (CurrentTarget==-1) + { + CurrentTarget = TargetTypes.Count; + TargetTypes.Add("None"); + } + + GUILayout.BeginHorizontal(); + GUILayout.Label ("Target:", GUILayout.Width (60)); + EditorGUI.BeginChangeCheck(); + int index = EditorGUILayout.Popup(CurrentTarget, TargetTypes.ToArray()); + if (EditorGUI.EndChangeCheck()) + { + serializedObject.ApplyModifiedProperties(); + foreach (var obj in serializedObject.targetObjects) + { + var cmp = obj as Localize; + if (cmp == null) + continue; + + if (cmp.mLocalizeTarget != null) + DestroyImmediate(cmp.mLocalizeTarget); + cmp.mLocalizeTarget = null; + + foreach (var desc in LocalizationManager.mLocalizeTargets) + { + if (desc.Name == TargetTypes[index]) + { + cmp.mLocalizeTarget = desc.CreateTarget(cmp); + cmp.mLocalizeTargetName = desc.GetTargetType().ToString(); + break; + } + } + } + serializedObject.Update(); + } + GUILayout.EndHorizontal(); + } + + #endregion + + #region Source + + void OnGUI_Source() + { + GUILayout.BeginHorizontal(); + + ILanguageSource currentSource = mLocalize.Source; + if (currentSource==null) + { + LanguageSourceData source = LocalizationManager.GetSourceContaining(mLocalize.Term); + currentSource = source==null ? null : source.owner; + } + + if (GUILayout.Button("Open Source", EditorStyles.toolbarButton, GUILayout.Width (100))) + { + Selection.activeObject = currentSource as Object; + + string sTerm, sSecondary; + mLocalize.GetFinalTerms( out sTerm, out sSecondary ); + if (GUI_SelectedTerm==1) sTerm = sSecondary; + LocalizationEditor.mKeyToExplore = sTerm; + } + + GUILayout.Space (2); + + GUILayout.BeginHorizontal(EditorStyles.toolbar); + EditorGUI.BeginChangeCheck (); + if (mLocalize.Source == null) + { + GUI.contentColor = Color.Lerp (Color.gray, Color.yellow, 0.1f); + } + Object obj = EditorGUILayout.ObjectField(currentSource as Object, typeof(Object), true); + GUI.contentColor = Color.white; + if (EditorGUI.EndChangeCheck()) + { + ILanguageSource NewSource = obj as ILanguageSource; + if (NewSource == null && obj as GameObject != null) + { + NewSource = (obj as GameObject).GetComponent(); + } + + mLocalize.Source = NewSource; + string sTerm, sSecondary; + mLocalize.GetFinalTerms(out sTerm, out sSecondary); + if (GUI_SelectedTerm == 1) sTerm = sSecondary; + UpdateTermsList(sTerm); + } + + if (GUILayout.Button(new GUIContent("Detect", "Finds the LanguageSource containing the selected term, the term list will now only show terms inside that source."), EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + { + string sTerm, sSecondary; + mLocalize.GetFinalTerms(out sTerm, out sSecondary); + if (GUI_SelectedTerm == 1) sTerm = sSecondary; + + var data = LocalizationManager.GetSourceContaining(sTerm, false); + mLocalize.Source = data==null ? null : data.owner; + mTermsArray = null; + } + GUILayout.EndHorizontal(); + + GUILayout.EndHorizontal(); + } + + #endregion + + + #region Event CallBack + + //public void DrawEventCallBack( EventCallback CallBack, Localize loc ) + //{ + //if (CallBack==null) + // return; + + //GUI.changed = false; + + //GUILayout.BeginHorizontal(); + //GUILayout.Label("Target:", GUILayout.ExpandWidth(false)); + //CallBack.Target = EditorGUILayout.ObjectField( CallBack.Target, typeof(MonoBehaviour), true) as MonoBehaviour; + //GUILayout.EndHorizontal(); + + //if (CallBack.Target!=null) + //{ + // GameObject GO = CallBack.Target.gameObject; + // List Infos = new List(); + + // var targets = GO.GetComponents(typeof(MonoBehaviour)); + // foreach (var behavior in targets) + // Infos.AddRange( behavior.GetType().GetMethods() ); + + // List Methods = new List(); + + // for (int i = 0, imax=Infos.Count; i 1) return false; + + if (Params [0].ParameterType.IsSubclassOf (typeof(Object))) return true; + if (Params [0].ParameterType == typeof(Object)) return true; + return false; + } + + + #endregion + + #region Styles + + public static GUIStyle GUIStyle_Header { + get{ + if (mGUIStyle_Header==null) + { + mGUIStyle_Header = new GUIStyle("HeaderLabel"); + mGUIStyle_Header.fontSize = 25; + mGUIStyle_Header.normal.textColor = Color.Lerp(Color.white, Color.gray, 0.5f); + mGUIStyle_Header.fontStyle = FontStyle.BoldAndItalic; + mGUIStyle_Header.alignment = TextAnchor.UpperCenter; + } + return mGUIStyle_Header; + } + } + static GUIStyle mGUIStyle_Header; + + public static GUIStyle GUIStyle_SubHeader { + get{ + if (mGUIStyle_SubHeader==null) + { + mGUIStyle_SubHeader = new GUIStyle("HeaderLabel"); + mGUIStyle_SubHeader.fontSize = 13; + mGUIStyle_SubHeader.fontStyle = FontStyle.Normal; + mGUIStyle_SubHeader.margin.top = -50; + mGUIStyle_SubHeader.alignment = TextAnchor.UpperCenter; + } + return mGUIStyle_SubHeader; + } + } + static GUIStyle mGUIStyle_SubHeader; + + public static GUIStyle GUIStyle_Background { + get{ + if (mGUIStyle_Background==null) + { + mGUIStyle_Background = new GUIStyle(EditorStyles.textArea); + mGUIStyle_Background.fixedHeight = 0; + mGUIStyle_Background.overflow.left = 50; + mGUIStyle_Background.overflow.right = 50; + mGUIStyle_Background.overflow.top = -5; + mGUIStyle_Background.overflow.bottom = 0; + } + return mGUIStyle_Background; + } + } + static GUIStyle mGUIStyle_Background; + + public static GUIStyle GUIStyle_OldTextArea + { + get + { + if (mGUIStyle_OldTextArea == null) + { + mGUIStyle_OldTextArea = new GUIStyle(EditorStyles.textArea); + mGUIStyle_OldTextArea.fixedHeight = 0; + } + return mGUIStyle_OldTextArea; + } + } + static GUIStyle mGUIStyle_OldTextArea; + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeInspector.cs.meta new file mode 100644 index 00000000..6d7f3aad --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/LocalizeInspector.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 675119279b2a30245801272112cfbe38 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/ResourceManagerInspector.cs b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/ResourceManagerInspector.cs new file mode 100644 index 00000000..692c70bd --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/ResourceManagerInspector.cs @@ -0,0 +1,29 @@ +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + [CustomEditor(typeof(ResourceManager))] + public class ResourceManagerInspector : UnityEditor.Editor + { + SerializedProperty mAssets; + + void OnEnable() + { + UpgradeManager.EnablePlugins(); + mAssets = serializedObject.FindProperty("Assets"); + } + + public override void OnInspectorGUI() + { + GUILayout.Space(5); + GUITools.DrawHeader("Assets:", true); + GUITools.BeginContents(); + ///GUILayout.Label ("Assets:"); + GUITools.DrawObjectsArray( mAssets ); + GUITools.EndContents(); + + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/ResourceManagerInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/ResourceManagerInspector.cs.meta new file mode 100644 index 00000000..96076a94 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/ResourceManagerInspector.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ba2fdf8face79dd4f9e1ed80448db843 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/SetLanguageInspector.cs b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/SetLanguageInspector.cs new file mode 100644 index 00000000..17a5e4e9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/SetLanguageInspector.cs @@ -0,0 +1,60 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + [CustomEditor(typeof(SetLanguage))] + public class SetLanguageInspector : UnityEditor.Editor + { + public SetLanguage setLan; + public SerializedProperty mProp_Language; + + public void OnEnable() + { + setLan = (SetLanguage)target; + mProp_Language = serializedObject.FindProperty("_Language"); + } + + public override void OnInspectorGUI() + { + string[] Languages; + LanguageSource sourceObj = setLan.mSource; + if (sourceObj == null) + { + LocalizationManager.UpdateSources(); + Languages = LocalizationManager.GetAllLanguages().ToArray(); + Array.Sort(Languages); + } + else + { + Languages = sourceObj.mSource.GetLanguages().ToArray(); + Array.Sort(Languages); + } + + int index = Array.IndexOf(Languages, mProp_Language.stringValue); + + GUI.changed = false; + index = EditorGUILayout.Popup("Language", index, Languages); + if (GUI.changed) + { + if (index<0 || index>=Languages.Length) + mProp_Language.stringValue = string.Empty; + else + mProp_Language.stringValue = Languages[index]; + GUI.changed = false; + serializedObject.ApplyModifiedProperties(); + } + + GUILayout.Space(5); + if (setLan.mSource==null) GUI.contentColor = Color.Lerp (Color.gray, Color.yellow, 0.1f); + sourceObj = EditorGUILayout.ObjectField("Language Source:", sourceObj, typeof(LanguageSource), true) as LanguageSource; + GUI.contentColor = Color.white; + + if (GUI.changed) + setLan.mSource = sourceObj; + + serializedObject.ApplyModifiedProperties(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/SetLanguageInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/SetLanguageInspector.cs.meta new file mode 100644 index 00000000..8fb138e1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/SetLanguageInspector.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 7af58b4da44670e47a509c59754e8c2b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/TermsPopup_Drawer.cs b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/TermsPopup_Drawer.cs new file mode 100644 index 00000000..05e17645 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/TermsPopup_Drawer.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + [CustomPropertyDrawer (typeof (TermsPopup))] + public class TermsPopup_Drawer : PropertyDrawer + { + GUIContent[] mTerms_Context; + int nFramesLeftBeforeUpdate; + string mPrevFilter; + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var filter = ((TermsPopup)attribute).Filter; + ShowGUICached(position, property, label, null, filter, ref mTerms_Context, ref nFramesLeftBeforeUpdate, ref mPrevFilter); + } + + public static bool ShowGUI(Rect position, SerializedProperty property, GUIContent label, LanguageSourceData source, string filter = "") + { + GUIContent[] terms=null; + int framesLeftBeforeUpdate=0; + string prevFilter = null; + + return ShowGUICached(position, property, label, source, filter, ref terms, ref framesLeftBeforeUpdate, ref prevFilter); + } + + public static bool ShowGUICached(Rect position, SerializedProperty property, GUIContent label, LanguageSourceData source, string filter, ref GUIContent[] terms_Contexts, ref int framesBeforeUpdating, ref string prevFilter) + { + UpdateTermsCache(source, filter, ref terms_Contexts, ref framesBeforeUpdating, ref prevFilter); + + label = EditorGUI.BeginProperty(position, label, property); + + EditorGUI.BeginChangeCheck (); + + var index = property.stringValue == "-" || property.stringValue == "" ? terms_Contexts.Length - 1 : + property.stringValue == " " ? terms_Contexts.Length - 2 : + GetTermIndex(terms_Contexts, property.stringValue); + var newIndex = EditorGUI.Popup(position, label, index, terms_Contexts); + + if (EditorGUI.EndChangeCheck()) + { + property.stringValue = newIndex < 0 || newIndex == terms_Contexts.Length - 1 ? string.Empty : terms_Contexts[newIndex].text; + if (newIndex == terms_Contexts.Length - 1) + property.stringValue = "-"; + else + if (newIndex < 0 || newIndex == terms_Contexts.Length - 2) + property.stringValue = string.Empty; + else + property.stringValue = terms_Contexts[newIndex].text; + + EditorGUI.EndProperty(); + return true; + } + + EditorGUI.EndProperty(); + return false; + } + + static int GetTermIndex(GUIContent[] terms_Contexts, string term ) + { + for (int i = 0; i < terms_Contexts.Length; ++i) + if (terms_Contexts[i].text == term) + return i; + return -1; + } + + + static void UpdateTermsCache(LanguageSourceData source, string filter, ref GUIContent[] terms_Contexts, ref int framesBeforeUpdating, ref string prevFilter) + { + framesBeforeUpdating--; + if (terms_Contexts!=null && framesBeforeUpdating>0 && filter==prevFilter) + { + return; + } + framesBeforeUpdating = 60; + prevFilter = filter; + + var Terms = source == null ? LocalizationManager.GetTermsList() : source.GetTermsList(); + + if (string.IsNullOrEmpty(filter) == false) + { + Terms = Filter(Terms, filter); + } + + Terms.Sort(StringComparer.OrdinalIgnoreCase); + Terms.Add(""); + Terms.Add(""); + Terms.Add(""); + + terms_Contexts = DisplayOptions(Terms); + } + + private static List Filter(List terms, string filter) + { + var filtered = new List(); + for (var i = 0; i < terms.Count; i++) + { + var term = terms[i]; + if (term.Contains(filter)) + { + filtered.Add(term); + } + } + + return filtered; + } + + private static GUIContent[] DisplayOptions(IList terms) + { + var options = new GUIContent[terms.Count]; + for (var i = 0; i < terms.Count; i++) + { + options[i] = new GUIContent(terms[i]); + } + + return options; + } + } + + [CustomPropertyDrawer(typeof(LocalizedString))] + public class LocalizedStringDrawer : PropertyDrawer + { + GUIContent[] mTerms_Context; + int nFramesLeftBeforeUpdate; + string mPrevFilter; + + public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) + { + var termRect = rect; termRect.xMax -= 50; + var termProp = property.FindPropertyRelative("mTerm"); + TermsPopup_Drawer.ShowGUICached(termRect, termProp, label, null, "", ref mTerms_Context, ref nFramesLeftBeforeUpdate, ref mPrevFilter); + + var maskRect = rect; maskRect.xMin = maskRect.xMax - 30; + var termIgnoreRTL = property.FindPropertyRelative("mRTL_IgnoreArabicFix"); + var termConvertNumbers = property.FindPropertyRelative("mRTL_ConvertNumbers"); + var termDontLocalizeParams = property.FindPropertyRelative("m_DontLocalizeParameters"); + int mask = (termIgnoreRTL.boolValue ? 0 : 1) + + (termConvertNumbers.boolValue ? 0 : 2) + + (termDontLocalizeParams.boolValue ? 0 : 4); + + int newMask = EditorGUI.MaskField(maskRect, mask, new[] { "Arabic Fix", "Ignore Numbers in RTL", "Localize Parameters" }); + if (newMask != mask) + { + termIgnoreRTL.boolValue = (newMask & 1) == 0; + termConvertNumbers.boolValue = (newMask & 2) == 0; + termDontLocalizeParams.boolValue = (newMask & 4) == 0; + } + + var showRect = rect; showRect.xMin = termRect.xMax; showRect.xMax=maskRect.xMin; + bool enabled = GUI.enabled; + GUI.enabled = enabled & (!string.IsNullOrEmpty (termProp.stringValue) && termProp.stringValue!="-"); + if (GUI.Button (showRect, "?")) + { + var source = LocalizationManager.GetSourceContaining(termProp.stringValue); + LocalizationEditor.mKeyToExplore = termProp.stringValue; + Selection.activeObject = source.ownerObject; + } + GUI.enabled = enabled; + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/TermsPopup_Drawer.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/TermsPopup_Drawer.cs.meta new file mode 100644 index 00000000..0290190a --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Inspectors/TermsPopup_Drawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 51c22a426b92fa84cb6ca7b75176da8a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization.meta new file mode 100644 index 00000000..f169efc7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8ad136296e8e6e14eaa2726ac1992b6c +folderAsset: yes +timeCreated: 1461137613 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor.cs new file mode 100644 index 00000000..1fecf387 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor.cs @@ -0,0 +1,308 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + + #region Variables + + public enum eViewMode { ImportExport, Keys, Languages, Tools, References } + public static eViewMode mCurrentViewMode = eViewMode.Keys; + + public enum eSpreadsheetMode { Local, Google } + public eSpreadsheetMode mSpreadsheetMode = eSpreadsheetMode.Google; + + + public static string mLocalizationMsg = ""; + public static MessageType mLocalizationMessageType = MessageType.None; + + // These variables are for executing action from Unity Tests + public enum eTest_ActionType { None, Button_AddLanguageFromPopup, Button_AddLanguageManual, + Button_AddTerm_InTermsList, Button_AddSelectedTerms, + Button_RemoveSelectedTerms, Button_DeleteTerm, + Button_SelectTerms_All, Button_SelectTerms_None, Button_SelectTerms_Used, Button_SelectTerms_Missing, + Button_Term_Translate, Button_Term_TranslateAll, Button_Languages_TranslateAll, + Button_Assets_Add, Button_Assets_Replace, Button_Assets_Delete, + Button_GoogleSpreadsheet_RefreshList, Button_GoogleSpreadsheet_Export, Button_GoogleSpreadsheet_Import + } + public static eTest_ActionType mTestAction = eTest_ActionType.None; + public static object mTestActionArg, mTestActionArg2; + + #endregion + + #region Editor + + /*[MenuItem("Window/Localization", false)] + public static void OpenLocalizationEditor() + { + EditorWindow.GetWindow(false, "Localization", true); + }*/ + + #endregion + + #region GUI + + void InitializeStyles() + { + Style_ToolBar_Big = new GUIStyle(EditorStyles.toolbar); + Style_ToolBar_Big.fixedHeight = Style_ToolBar_Big.fixedHeight*1.5f; + + Style_ToolBarButton_Big = new GUIStyle(EditorStyles.toolbarButton); + Style_ToolBarButton_Big.fixedHeight = Style_ToolBarButton_Big.fixedHeight*1.5f; + } + + + void OnGUI_Main() + { + OnGUI_Warning_SourceInScene(); + OnGUI_Warning_SourceInsidePluginsFolder(); + OnGUI_Warning_SourceNotUpToDate(); + + var prevViewMode = mCurrentViewMode; + + GUILayout.BeginHorizontal(); + //OnGUI_ToggleEnumBig( "Spreadsheets", ref mCurrentViewMode, eViewMode.ImportExport, GUI.skin.GetStyle("CN EntryWarn").normal.background, "External Spreadsheet File or Service" ); + OnGUI_ToggleEnumBig( "Spreadsheets", ref mCurrentViewMode, eViewMode.ImportExport, null, "External Spreadsheet File or Service" ); + OnGUI_ToggleEnumBig( "Terms", ref mCurrentViewMode, eViewMode.Keys, null, null ); + OnGUI_ToggleEnumBig( "Languages", ref mCurrentViewMode, eViewMode.Languages, null, null ); + OnGUI_ToggleEnumBig( "Tools", ref mCurrentViewMode, eViewMode.Tools, null, null ); + OnGUI_ToggleEnumBig( "Assets", ref mCurrentViewMode, eViewMode.References, null, null ); + GUILayout.EndHorizontal(); + //GUILayout.Space(10); + + switch (mCurrentViewMode) + { + case eViewMode.ImportExport : OnGUI_ImportExport(); break; + case eViewMode.Keys : OnGUI_KeysList(); break; + case eViewMode.Languages : OnGUI_Languages(); break; + case eViewMode.Tools : OnGUI_Tools(prevViewMode != mCurrentViewMode); break; + case eViewMode.References : OnGUI_References(); break; + } + } + + void OnGUI_ImportExport() + { + eSpreadsheetMode OldMode = mSpreadsheetMode; + mSpreadsheetMode = (eSpreadsheetMode)GUITools.DrawShadowedTabs ((int)mSpreadsheetMode, new[]{"Local", "Google"}); + if (mSpreadsheetMode != OldMode) + ClearErrors(); + + GUITools.BeginContents(); + switch (mSpreadsheetMode) + { + case eSpreadsheetMode.Local : OnGUI_Spreadsheet_Local(); break; + case eSpreadsheetMode.Google : OnGUI_Spreadsheet_Google(); break; + } + GUITools.EndContents(false); + } + + void OnGUI_References() + { + EditorGUILayout.HelpBox("These are the assets that are referenced by the Terms and not in the Resources folder", MessageType.Info); + + bool canTest = UnityEngine.Event.current.type == EventType.Repaint; + + var testAddObj = canTest && mTestAction == eTest_ActionType.Button_Assets_Add ? (Object)mTestActionArg : null; + var testReplaceIndx = canTest && mTestAction == eTest_ActionType.Button_Assets_Replace ? (int)mTestActionArg : -1; + var testReplaceObj = canTest && mTestAction == eTest_ActionType.Button_Assets_Replace ? (Object)mTestActionArg2 : null; + var testDeleteIndx = canTest && mTestAction == eTest_ActionType.Button_Assets_Delete ? (int)mTestActionArg : -1; + + bool changed = GUITools.DrawObjectsArray( mProp_Assets, false, false, false, testAddObj, testReplaceObj, testReplaceIndx, testDeleteIndx); + if (changed) + { + serializedObject.ApplyModifiedProperties(); + foreach (var obj in serializedObject.targetObjects) + (obj as LanguageSource).mSource.UpdateAssetDictionary(); + } + } + + #endregion + + #region Misc + + void OnGUI_ToggleEnumBig( string text, ref Enum currentMode, Enum newMode, Texture texture, string tooltip) { OnGUI_ToggleEnum( text, ref currentMode, newMode, texture, tooltip, Style_ToolBarButton_Big); } + void OnGUI_ToggleEnumSmall( string text, ref Enum currentMode, Enum newMode, Texture texture, string tooltip) { OnGUI_ToggleEnum( text, ref currentMode, newMode, texture, tooltip, EditorStyles.toolbarButton); } + void OnGUI_ToggleEnum( string text, ref Enum currentMode, Enum newMode, Texture texture, string tooltip, GUIStyle style) + { + GUI.changed = false; + if (GUILayout.Toggle( currentMode.Equals(newMode), new GUIContent(text, texture, tooltip), style, GUILayout.ExpandWidth(true))) + { + currentMode = newMode; + if (GUI.changed) + ClearErrors(); + } + } + + int OnGUI_FlagToogle( string Text, string tooltip, int flags, int bit ) + { + bool State = (flags & bit)>0; + bool NewState = GUILayout.Toggle(State, new GUIContent(Text, tooltip), "toolbarbutton"); + if (State!=NewState) + { + if (!NewState && flags==bit) + return flags; + + flags = NewState ? flags | bit : flags & ~bit; + } + + return flags; + } + + void OnGUI_SelectableToogleListItem( string Element, ref List Selections, string Style ) + { + bool WasEnabled = Selections.Contains(Element); + bool IsEnabled = GUILayout.Toggle( WasEnabled, "", Style, GUILayout.ExpandWidth(false) ); + + if (IsEnabled && !WasEnabled) + Selections.Add(Element); + else + if (!IsEnabled && WasEnabled) + Selections.Remove(Element); + } + + void OnGUI_SelectableToogleListItem( Rect rect, string Element, ref List Selections, string Style ) + { + bool WasEnabled = Selections.Contains(Element); + bool IsEnabled = GUI.Toggle( rect, WasEnabled, "", Style ); + + if (IsEnabled && !WasEnabled) + Selections.Add(Element); + else + if (!IsEnabled && WasEnabled) + Selections.Remove(Element); + } + + static bool InTestAction( eTest_ActionType testType ) + { + return mTestAction == testType && UnityEngine.Event.current.type == EventType.Repaint; + } + static bool TestButton(eTest_ActionType action, string text, GUIStyle style, params GUILayoutOption[] options) + { + return GUILayout.Button(text, style, options) || mTestAction == action && UnityEngine.Event.current.type == EventType.Repaint; + } + + static bool TestButtonArg(eTest_ActionType action, object arg, string text, GUIStyle style, params GUILayoutOption[] options) + { + return GUILayout.Button(text, style, options) || mTestAction == action && (mTestActionArg==null || mTestActionArg.Equals(arg)) && UnityEngine.Event.current.type == EventType.Repaint; + } + + + static bool TestButton(eTest_ActionType action, GUIContent text, GUIStyle style, params GUILayoutOption[] options) + { + return GUILayout.Button(text, style, options) || mTestAction == action && UnityEngine.Event.current.type == EventType.Repaint; + } + + static bool TestButtonArg(eTest_ActionType action, object arg, GUIContent text, GUIStyle style, params GUILayoutOption[] options) + { + return GUILayout.Button(text, style, options) || mTestAction == action && (mTestActionArg == null || mTestActionArg.Equals(arg)) && UnityEngine.Event.current.type == EventType.Repaint; + } + + #endregion + + #region Error Management + + static void OnGUI_ShowMsg() + { + if (!string.IsNullOrEmpty(mLocalizationMsg)) + { + GUILayout.BeginHorizontal(); + EditorGUILayout.HelpBox(mLocalizationMsg, mLocalizationMessageType); + + GUILayout.Space(-5); + GUILayout.BeginVertical(GUILayout.Width(15), GUILayout.ExpandHeight(false)); + GUILayout.Space(15); + if (GUILayout.Button("X", GUITools.Style_ToolbarSearchCancelButton, GUILayout.ExpandWidth(false))) + ClearErrors(); + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + GUILayout.Space(8); + } + } + + static void ShowError ( string Error, bool ShowInConsole = true ) { ShowMessage ( Error, MessageType.Error, ShowInConsole ); } + static void ShowInfo ( string Msg, bool ShowInConsole = false ) { ShowMessage ( Msg, MessageType.Info, ShowInConsole ); } + static void ShowWarning( string Msg, bool ShowInConsole = true) { ShowMessage ( Msg, MessageType.Warning, ShowInConsole ); } + + static void ShowMessage( string Msg, MessageType msgType, bool ShowInConsole ) + { + if (string.IsNullOrEmpty(Msg)) + Msg = string.Empty; + + mLocalizationMsg = Msg; + mLocalizationMessageType = msgType; + if (ShowInConsole) + { + switch (msgType) + { + case MessageType.Error : Debug.LogError(Msg); break; + case MessageType.Warning : Debug.LogWarning(Msg); break; + default : Debug.Log(Msg); break; + } + } + } + + + public static void ClearErrors() + { + GUI.FocusControl(null); + + mLocalizationMsg = string.Empty; + } + + #endregion + + #region Unity Version branching + + public static string Editor_GetCurrentScene() + { + #if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 + return EditorApplication.currentScene; + #else + return SceneManager.GetActiveScene().path; + #endif + } + + public static void Editor_MarkSceneDirty() + { + #if UNITY_5_3 || UNITY_5_3_OR_NEWER + EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + #else + EditorApplication.MarkSceneDirty(); + #endif + } + + public static void Editor_SaveScene(bool force=false) + { + if (force) + Editor_MarkSceneDirty(); + + #if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 + EditorApplication.SaveScene (); + #else + EditorSceneManager.SaveOpenScenes(); + #endif + } + + public static void Editor_OpenScene( string sceneName ) + { +#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 + if (string.IsNullOrEmpty(sceneName)) + EditorApplication.NewEmptyScene(); + else + EditorApplication.OpenScene(sceneName); +#else + if (string.IsNullOrEmpty(sceneName)) + EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single); + else + EditorSceneManager.OpenScene(sceneName); + #endif + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor.cs.meta new file mode 100644 index 00000000..71ed09b3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ffd53aaaf6936407d8b087583b0626e9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Languages.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Languages.cs new file mode 100644 index 00000000..d43cdd78 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Languages.cs @@ -0,0 +1,477 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + #region Variables + private List mTranslationTerms = new List(); + private Dictionary mTranslationRequests = new Dictionary (); + private bool mAppNameTerm_Expanded; + + private List mLanguageCodePopupList; + + #endregion + + void OnGUI_Languages() + { + //GUILayout.Space(5); + + OnGUI_ShowMsg(); + + OnGUI_LanguageList(); + + OnGUI_StoreIntegration(); + + GUILayout.BeginHorizontal(); + GUILayout.Label(new GUIContent("On Missing Translation:", "What should happen IN-GAME when a term is not yet translated to the current language?"), EditorStyles.boldLabel, GUILayout.Width(200)); + GUILayout.BeginVertical(); + GUILayout.Space(7); + EditorGUILayout.PropertyField(mProp_OnMissingTranslation, GUITools.EmptyContent, GUILayout.Width(165)); + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Label(new GUIContent("Unload Languages At Runtime:", "When playing the game, the plugin will unload all unused languages and only load them when needed"), EditorStyles.boldLabel, GUILayout.Width(200)); + GUILayout.BeginVertical(); + GUILayout.Space(7); + EditorGUILayout.PropertyField(mProp_AllowUnloadingLanguages, GUITools.EmptyContent, GUILayout.Width(165)); + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + + + + + string firstLanguage = ""; + if (mLanguageSource.mLanguages.Count > 0) + firstLanguage = " (" + mLanguageSource.mLanguages [0].Name + ")"; + + GUILayout.BeginHorizontal(); + GUILayout.Label(new GUIContent("Default Language:", "When the game starts this is the language that will be used until the player manually selects a language"), EditorStyles.boldLabel, GUILayout.Width(160)); + GUILayout.BeginVertical(); + GUILayout.Space(7); + + mProp_IgnoreDeviceLanguage.boolValue = EditorGUILayout.Popup(mProp_IgnoreDeviceLanguage.boolValue?1:0, new[]{"Device Language", "First in List"+firstLanguage}, GUILayout.ExpandWidth(true))==1; + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + } + + #region GUI Languages + + void OnGUI_LanguageList() + { + GUILayout.BeginHorizontal(EditorStyles.toolbar); + GUILayout.FlexibleSpace(); + GUILayout.Label ("Languages:", EditorStyles.miniLabel, GUILayout.ExpandWidth(false)); + GUILayout.FlexibleSpace(); + GUILayout.Label ("Code:", EditorStyles.miniLabel); + GUILayout.Space(170); + GUILayout.EndHorizontal(); + + //--[ Language List ]-------------------------- + + int IndexLanguageToDelete = -1; + int LanguageToMoveUp = -1; + int LanguageToMoveDown = -1; + GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f); + mScrollPos_Languages = GUILayout.BeginScrollView( mScrollPos_Languages, LocalizeInspector.GUIStyle_OldTextArea, GUILayout.MinHeight (200), /*GUILayout.MaxHeight(Screen.height),*/ GUILayout.ExpandHeight(false)); + GUI.backgroundColor = Color.white; + + if (mLanguageCodePopupList == null || mLanguageCodePopupList.Count==0) + { + mLanguageCodePopupList = GoogleLanguages.GetLanguagesForDropdown("", ""); + mLanguageCodePopupList.Sort(); + mLanguageCodePopupList.Insert(0, string.Empty); + } + + for (int i=0, imax=mProp_Languages.arraySize; i c.Contains(currentCode))); + EditorGUI.BeginChangeCheck(); + Index = EditorGUILayout.Popup(Index, mLanguageCodePopupList.ToArray(), EditorStyles.toolbarPopup, GUILayout.Width(60)); + if (EditorGUI.EndChangeCheck() && Index >= 0) + { + currentCode = mLanguageCodePopupList[Index]; + int i0 = currentCode.IndexOf("["); + int i1 = currentCode.IndexOf("]"); + if (i0 >= 0 && i1 > i0) + Prop_LangCode.stringValue = currentCode.Substring(i0 + 1, i1 - i0 - 1); + else + Prop_LangCode.stringValue = string.Empty; + } + var rect = GUILayoutUtility.GetLastRect(); + GUI.Label(rect, Prop_LangCode.stringValue, EditorStyles.toolbarPopup); + } + else + { + GUILayout.Label(Prop_LangCode.stringValue, EditorStyles.toolbarPopup, GUILayout.Width(60)); + } + + GUILayout.EndHorizontal(); + + GUI.enabled = i0; + if (GUILayout.Button( "\u25B2", EditorStyles.toolbarButton, GUILayout.Width(18))) LanguageToMoveUp = i; + + GUI.enabled = true; + if (GUILayout.Button( new GUIContent("Show", "Preview all localizations into this language"), EditorStyles.toolbarButton, GUILayout.Width(35))) + { + LocalizationManager.SetLanguageAndCode( LanName, Prop_LangCode.stringValue, false, true); + } + + if (TestButtonArg( eTest_ActionType.Button_Languages_TranslateAll, i, new GUIContent("Translate", "Translate all empty terms"), EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + { + GUITools.DelayedCall( () => TranslateAllToLanguage(LanName)); + } + GUI.enabled = true; + GUI.color = Color.white; + + EditorGUI.BeginChangeCheck(); + isLanguageEnabled = EditorGUILayout.Toggle(isLanguageEnabled, GUILayout.Width(15)); + + var r = GUILayoutUtility.GetLastRect(); + GUI.Label(r, new GUIContent("", "Enable/Disable the language.\nDisabled languages can be used to store data values or to avoid showing Languages that are stil under development")); + + if (EditorGUI.EndChangeCheck()) + { + Prop_Flags.intValue = (Prop_Flags.intValue & ~(int)eLanguageDataFlags.DISABLED) | (isLanguageEnabled ? 0 : (int)eLanguageDataFlags.DISABLED); + } + + GUILayout.EndHorizontal(); + } + + GUILayout.EndScrollView(); + + OnGUI_AddLanguage( mProp_Languages ); + + if (mConnection_WWW!=null || mConnection_Text.Contains("Translating")) + { + // Connection Status Bar + int time = (int)(Time.realtimeSinceStartup % 2 * 2.5); + string Loading = mConnection_Text + ".....".Substring(0, time); + GUI.color = Color.gray; + GUILayout.BeginHorizontal(LocalizeInspector.GUIStyle_OldTextArea); + GUILayout.Label (Loading, EditorStyles.miniLabel); + GUI.color = Color.white; + if (GUILayout.Button("Cancel", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + { + GoogleTranslation.CancelCurrentGoogleTranslations (); + StopConnectionWWW(); + } + GUILayout.EndHorizontal(); + Repaint(); + } + + if (IndexLanguageToDelete>=0) + { + if (EditorUtility.DisplayDialog ("Confirm delete", "Are you sure you want to delete the selected language", "Yes", "Cancel")) + { + mLanguageSource.RemoveLanguage (mLanguageSource.mLanguages [IndexLanguageToDelete].Name); + serializedObject.Update (); + ParseTerms (true, false, false); + } + } + + if (LanguageToMoveUp>=0) SwapLanguages( LanguageToMoveUp, LanguageToMoveUp-1 ); + if (LanguageToMoveDown>=0) SwapLanguages( LanguageToMoveDown, LanguageToMoveDown+1 ); + } + + void SwapLanguages( int iFirst, int iSecond ) + { + serializedObject.ApplyModifiedProperties(); + LanguageSourceData Source = mLanguageSource; + + SwapValues( Source.mLanguages, iFirst, iSecond ); + foreach (TermData termData in Source.mTerms) + { + SwapValues ( termData.Languages, iFirst, iSecond ); + SwapValues ( termData.Flags, iFirst, iSecond ); + } + serializedObject.Update(); + } + + void SwapValues( List mList, int Index1, int Index2 ) + { + LanguageData temp = mList[Index1]; + mList[Index1] = mList[Index2]; + mList[Index2] = temp; + } + void SwapValues( string[] mList, int Index1, int Index2 ) + { + string temp = mList[Index1]; + mList[Index1] = mList[Index2]; + mList[Index2] = temp; + } + void SwapValues( byte[] mList, int Index1, int Index2 ) + { + byte temp = mList[Index1]; + mList[Index1] = mList[Index2]; + mList[Index2] = temp; + } + + + void OnGUI_AddLanguage( SerializedProperty Prop_Languages) + { + //--[ Add Language Upper Toolbar ]----------------- + + GUILayout.BeginVertical(); + GUILayout.BeginHorizontal(); + + GUILayout.BeginHorizontal(EditorStyles.toolbar); + mLanguages_NewLanguage = EditorGUILayout.TextField("", mLanguages_NewLanguage, EditorStyles.toolbarTextField, GUILayout.ExpandWidth(true)); + GUILayout.EndHorizontal(); + + GUI.enabled = !string.IsNullOrEmpty (mLanguages_NewLanguage); + if (TestButton(eTest_ActionType.Button_AddLanguageManual,"Add", EditorStyles.toolbarButton, GUILayout.Width(50))) + { + Prop_Languages.serializedObject.ApplyModifiedProperties(); + mLanguageSource.AddLanguage( mLanguages_NewLanguage, GoogleLanguages.GetLanguageCode(mLanguages_NewLanguage) ); + Prop_Languages.serializedObject.Update(); + mLanguages_NewLanguage = ""; + GUI.FocusControl(string.Empty); + } + GUI.enabled = true; + + GUILayout.EndHorizontal(); + + + //--[ Add Language Bottom Toolbar ]----------------- + + GUILayout.BeginHorizontal(); + + //-- Language Dropdown ----------------- + string CodesToExclude = string.Empty; + foreach (var LanData in mLanguageSource.mLanguages) + CodesToExclude = string.Concat(CodesToExclude, "[", LanData.Code, "]"); + + List Languages = GoogleLanguages.GetLanguagesForDropdown(mLanguages_NewLanguage, CodesToExclude); + + GUI.changed = false; + int index = EditorGUILayout.Popup(0, Languages.ToArray(), EditorStyles.toolbarDropDown); + + if (GUI.changed && index>=0) + { + mLanguages_NewLanguage = GoogleLanguages.GetFormatedLanguageName( Languages[index] ); + } + + + if (TestButton(eTest_ActionType.Button_AddLanguageFromPopup, "Add", EditorStyles.toolbarButton, GUILayout.Width(50)) && index>=0) + { + Prop_Languages.serializedObject.ApplyModifiedProperties(); + mLanguages_NewLanguage = GoogleLanguages.GetFormatedLanguageName(Languages[index]); + + if (!string.IsNullOrEmpty(mLanguages_NewLanguage)) + mLanguageSource.AddLanguage(mLanguages_NewLanguage, GoogleLanguages.GetLanguageCode(mLanguages_NewLanguage)); + Prop_Languages.serializedObject.Update(); + + mLanguages_NewLanguage = ""; + GUI.FocusControl(string.Empty); + } + + GUILayout.EndHorizontal(); + GUILayout.EndVertical(); + GUI.color = Color.white; + } + + + void TranslateAllToLanguage (string lanName) + { + if (!GoogleTranslation.CanTranslate ()) + { + ShowError ("WebService is not set correctly or needs to be reinstalled"); + return; + } + ClearErrors(); + int LanIndex = mLanguageSource.GetLanguageIndex (lanName); + string code = mLanguageSource.mLanguages [LanIndex].Code; + string googleCode = GoogleLanguages.GetGoogleLanguageCode(code); + if (string.IsNullOrEmpty(googleCode)) + { + ShowError("Language '" + code + "' is not supported by google translate"); + return; + } + googleCode = code; + + mTranslationTerms.Clear (); + mTranslationRequests.Clear (); + foreach (var termData in mLanguageSource.mTerms) + { + if (termData.TermType != eTermType.Text) + continue; + + if (!string.IsNullOrEmpty(termData.Languages[LanIndex])) + continue; + + string sourceCode, sourceText; + FindTranslationSource( LanguageSourceData.GetKeyFromFullTerm(termData.Term), termData, code, null, out sourceText, out sourceCode ); + + mTranslationTerms.Add (termData.Term); + + GoogleTranslation.CreateQueries(sourceText, sourceCode, googleCode, mTranslationRequests); // can split plurals into several queries + } + + if (mTranslationRequests.Count == 0) + { + StopConnectionWWW (); + return; + } + + mConnection_WWW = null; + mConnection_Text = "Translating"; if (mTranslationRequests.Count > 1) mConnection_Text += " (" + mTranslationRequests.Count + ")"; + mConnection_Callback = null; + //EditorApplication.update += CheckForConnection; + + GoogleTranslation.Translate (mTranslationRequests, OnLanguageTranslated); + } + + void OnLanguageTranslated( Dictionary requests, string Error ) + { + //Debug.Log (Result); + + //if (Result.Contains("Service invoked too many times")) + //{ + // TimeStartTranslation = EditorApplication.timeSinceStartup + 1; + // EditorApplication.update += DelayedStartTranslation; + // mConnection_Text = "Translating (" + mTranslationRequests.Count + ")"; + // return; + //} + + //if (!string.IsNullOrEmpty(Error))/* || !Result.Contains("")*/ + //{ + // Debug.LogError("WEB ERROR: " + Error); + // ShowError ("Unable to access Google or not valid request"); + // return; + //} + + ClearErrors(); + StopConnectionWWW(); + + if (!string.IsNullOrEmpty(Error)) + { + ShowError (Error); + return; + } + + if (requests.Values.Count == 0) + return; + + var langCode = requests.Values.First().TargetLanguagesCode [0]; + //langCode = GoogleLanguages.GetGoogleLanguageCode(langCode); + int langIndex = mLanguageSource.GetLanguageIndexFromCode (langCode, false); + //if (langIndex >= 0) + { + foreach (var term in mTranslationTerms) + { + var termData = mLanguageSource.GetTermData(term); + if (termData == null) + continue; + if (termData.TermType != eTermType.Text) + continue; + //if (termData.Languages.Length <= langIndex) + // continue; + + string sourceCode, sourceText; + FindTranslationSource(LanguageSourceData.GetKeyFromFullTerm(termData.Term), termData, langCode, null, out sourceText, out sourceCode); + + string result = GoogleTranslation.RebuildTranslation(sourceText, mTranslationRequests, langCode); // gets the result from google and rebuilds the text from multiple queries if its is plurals + + termData.Languages[langIndex] = result; + } + } + + mTranslationTerms.Clear (); + mTranslationRequests.Clear (); + StopConnectionWWW (); + } + + #endregion + + #region Store Integration + + void OnGUI_StoreIntegration() + { + GUIStyle lstyle = new GUIStyle (EditorStyles.label); + lstyle.richText = true; + + GUILayout.BeginHorizontal (); + GUILayout.Label (new GUIContent("Store Integration:", "Setups the stores to detect that the game has localization, Android adds strings.xml for each language. IOS modifies the Info.plist"), EditorStyles.boldLabel, GUILayout.Width(160)); + GUILayout.FlexibleSpace(); + + GUILayout.Label( new GUIContent( "\u2713 IOS", "Setups the stores to show in iTunes and the Appstore all the languages that this app supports, also localizes the app name if available" ), lstyle, GUILayout.Width( 90 ) ); + GUILayout.Label( new GUIContent( "\u2713 Android", "Setups the stores to show in GooglePlay all the languages this app supports, also localizes the app name if available" ), lstyle, GUILayout.Width( 90 ) ); + GUILayout.EndHorizontal (); + + GUILayout.BeginHorizontal(); + mAppNameTerm_Expanded = GUILayout.Toggle(mAppNameTerm_Expanded, new GUIContent( "App Name translations:", "How should the game be named in the devices based on their language" ), EditorStyles.foldout, GUILayout.Width( 160 ) ); + + GUILayout.Label("", GUILayout.ExpandWidth(true)); + var rect = GUILayoutUtility.GetLastRect(); + TermsPopup_Drawer.ShowGUI( rect, mProp_AppNameTerm, GUITools.EmptyContent, mLanguageSource); + + if (GUILayout.Button("New Term", EditorStyles.miniButton, GUILayout.ExpandWidth(false))) + { + AddLocalTerm("App_Name"); + mProp_AppNameTerm.stringValue = "App_Name"; + mAppNameTerm_Expanded = true; + } + GUILayout.EndHorizontal(); + + if (mAppNameTerm_Expanded) + { + GUILayout.BeginHorizontal(); + GUILayout.Space(10); + + GUILayout.BeginVertical("Box"); + var termName = mProp_AppNameTerm.stringValue; + if (!string.IsNullOrEmpty(termName)) + { + var termData = LocalizationManager.GetTermData(termName); + if (termData != null) + OnGUI_Keys_Languages(mProp_AppNameTerm.stringValue, ref termData, null, true, mLanguageSource); + } + GUILayout.Space(10); + + GUILayout.BeginHorizontal(); + GUILayout.Label("Default App Name:", lstyle, GUITools.DontExpandWidth); + GUILayout.Label(Application.productName); + GUILayout.EndHorizontal(); + GUILayout.EndVertical(); + + GUILayout.EndHorizontal(); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Languages.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Languages.cs.meta new file mode 100644 index 00000000..375ebe73 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Languages.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 304783c1e95d94a598aecd17728c8556 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Google.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Google.cs new file mode 100644 index 00000000..221d3b42 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Google.cs @@ -0,0 +1,727 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UnityEditor; +using UnityEngine; +using UnityEngine.Networking; +using TEngine.Localization.SimpleJSON; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + #region Variables + + public static Dictionary mGoogleSpreadsheets = new Dictionary(StringComparer.Ordinal); + + public UnityWebRequest mConnection_WWW; + + delegate void fnConnectionCallback(string Result, string Error); + event fnConnectionCallback mConnection_Callback; + //float mConnection_TimeOut; + + string mConnection_Text = string.Empty; + + string mWebService_Status; + + #endregion + + #region GUI + + void OnGUI_Spreadsheet_Google() + { + GUILayout.Space(20); + +#if UNITY_WEBPLAYER + mConnection_Text = string.Empty; + EditorGUILayout.HelpBox("Google Synchronization is not supported when in WebPlayer mode." + mConnection_Text, MessageType.Info); + + mProp_GoogleUpdateFrequency.enumValueIndex = mProp_GoogleUpdateFrequency.enumValueIndex; // to avoid the warning "unused" + mProp_GoogleUpdateSynchronization.enumValueIndex = mProp_GoogleUpdateSynchronization.enumValueIndex; +#else + + OnGUI_GoogleCredentials(); + + OnGUI_ShowMsg(); + + if (string.IsNullOrEmpty(mProp_Google_WebServiceURL.stringValue)) + return; + + if (mWebService_Status == "Offline") + return; + + GUILayout.Space(20); + + GUI.backgroundColor = Color.Lerp(Color.gray, Color.white, 0.5f); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height (1)); + GUI.backgroundColor = Color.white; + GUILayout.Space(10); + + GUILayout.BeginHorizontal(); + GUILayout.Label(new GUIContent(" Password", "This should match the value of the LocalizationPassword variable in the WebService Script in your Google Drive"), GUILayout.Width(108)); + mProp_Google_Password.stringValue = EditorGUILayout.TextField(mProp_Google_Password.stringValue, GUILayout.ExpandWidth(true)); + GUILayout.EndHorizontal(); + + OnGUI_GoogleSpreadsheetsInGDrive(); + GUILayout.EndVertical(); + + if (mConnection_WWW!=null) + { + // Connection Status Bar + int time = (int)(Time.realtimeSinceStartup % 2 * 2.5); + string Loading = mConnection_Text + ".....".Substring(0, time); + GUI.color = Color.gray; + GUILayout.BeginHorizontal(LocalizeInspector.GUIStyle_OldTextArea); + GUILayout.Label (Loading, EditorStyles.miniLabel); + GUI.color = Color.white; + if (GUILayout.Button("Cancel", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + StopConnectionWWW(); + GUILayout.EndHorizontal(); + Repaint(); + } + //else + // GUILayout.Space(10); + + + EditorGUI.BeginChangeCheck(); + GUILayout.Space(5); + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + LanguageSourceData.eGoogleUpdateFrequency GoogleUpdateFrequency = (LanguageSourceData.eGoogleUpdateFrequency)mProp_GoogleUpdateFrequency.enumValueIndex; + GoogleUpdateFrequency = (LanguageSourceData.eGoogleUpdateFrequency)EditorGUILayout.EnumPopup("Auto Update Frequency", GoogleUpdateFrequency, GUILayout.ExpandWidth(true)); + if (EditorGUI.EndChangeCheck()) + { + mProp_GoogleUpdateFrequency.enumValueIndex = (int)GoogleUpdateFrequency; + } + + GUILayout.Space(10); + GUILayout.Label("Delay:"); + mProp_GoogleUpdateDelay.floatValue = EditorGUILayout.FloatField(mProp_GoogleUpdateDelay.floatValue, GUILayout.Width(30)); + GUILayout.Label("secs"); + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + var GoogleInEditorCheckFrequency = (LanguageSourceData.eGoogleUpdateFrequency)mProp_GoogleInEditorCheckFrequency.enumValueIndex; + EditorGUI.BeginChangeCheck(); + GoogleInEditorCheckFrequency = (LanguageSourceData.eGoogleUpdateFrequency)EditorGUILayout.EnumPopup(new GUIContent("In-Editor Check Frequency", "How often the editor will verify that the Spreadsheet is up-to-date with the LanguageSource. Having un-synchronized Spreadsheets can lead to issues when playing in the device as the download data will override the one in the build"), GoogleInEditorCheckFrequency, GUILayout.ExpandWidth(false)); + if (EditorGUI.EndChangeCheck()) + { + mProp_GoogleInEditorCheckFrequency.enumValueIndex = (int)GoogleInEditorCheckFrequency; + } + GUILayout.Space(122); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Label("Update Synchronization", GUILayout.Width(180)); + EditorGUI.BeginChangeCheck(); + LanguageSourceData.eGoogleUpdateSynchronization GoogleUpdateSynchronization = (LanguageSourceData.eGoogleUpdateSynchronization)mProp_GoogleUpdateSynchronization.enumValueIndex; + GoogleUpdateSynchronization = (LanguageSourceData.eGoogleUpdateSynchronization)EditorGUILayout.EnumPopup(GoogleUpdateSynchronization, GUILayout.Width(178)); + if (EditorGUI.EndChangeCheck()) + { + mProp_GoogleUpdateSynchronization.enumValueIndex = (int)GoogleUpdateSynchronization; + } + GUILayout.EndHorizontal(); + + GUILayout.Space(5); + + GUI.changed = false; + bool OpenDataSourceAfterExport = EditorPrefs.GetBool("I2Loc OpenDataSourceAfterExport", true); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + OpenDataSourceAfterExport = GUILayout.Toggle(OpenDataSourceAfterExport, "Open Spreadsheet after Export"); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + if (GUI.changed) + { + GUI.changed = false; + EditorPrefs.SetBool("I2Loc OpenDataSourceAfterExport", OpenDataSourceAfterExport); + } + +#endif + + GUILayout.Space(5); + } + + void OnGUI_GoogleCredentials() + { + GUI.enabled = mConnection_WWW==null; + + GUI.changed = false; + + string WebServiceHelp = "The web service is a script running on the google drive where the spreadsheet you want to use is located.\nThat script allows the game to synchronize the localization even after the game is published."; + + GUILayout.BeginHorizontal(); + GUILayout.Label (new GUIContent("Web Service URL:", WebServiceHelp), GUILayout.Width(110)); + + GUI.SetNextControlName ("WebServiceURL"); + mProp_Google_WebServiceURL.stringValue = EditorGUILayout.TextField(mProp_Google_WebServiceURL.stringValue); + + if (!string.IsNullOrEmpty(mWebService_Status)) + { + if (mWebService_Status=="Online") + { + GUI.color = Color.green; + GUILayout.Label( "", GUILayout.Width(17)); + Rect r = GUILayoutUtility.GetLastRect(); r.xMin += 3; r.yMin-= 3; r.xMax+= 2; r.yMax+=2; + GUI.Label( r, new GUIContent("\u2713", "Online"), EditorStyles.whiteLargeLabel); + GUI.color = Color.white; + } + else + if (mWebService_Status=="Offline") + { + GUI.color = Color.red; + GUILayout.Label( "", GUILayout.Width(17)); + Rect r = GUILayoutUtility.GetLastRect(); r.xMin += 3; r.yMin-= 3; r.xMax+= 2; r.yMax+=2; + GUI.Label( r, new GUIContent("\u2717", mWebService_Status), EditorStyles.whiteLargeLabel); + GUI.color = Color.white; + } + else + if (mWebService_Status=="UnsupportedVersion") + { + Rect rect = GUILayoutUtility.GetLastRect(); + float Width = 15; + rect.xMin = rect.xMax+1; + rect.xMax = rect.xMin + rect.height; + GUITools.DrawSkinIcon(rect, "CN EntryWarnIcon", "CN EntryWarn"); + GUI.Label(rect, new GUIContent("\u2717", "The current Google WebService is not supported.\nPlease, delete the WebService from the Google Drive and Install the latest version.")); + GUILayout.Space (Width); + } + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Space (118); + if (GUILayout.Button(new GUIContent("Install", "This opens the Web Service Script and shows you steps to install and authorize it on your Google Drive"), EditorStyles.toolbarButton)) + { + ClearErrors(); + Application.OpenURL("https://script.google.com/d/1zcsLSmq3Oddd8AsLuoKNDG1Y0eYBOHzyvGT7v94u1oN6igmsZb_PJzEm/newcopy"); // V5 + //Application.OpenURL("https://goo.gl/RBCO0o"); // V4:https://script.google.com/d/1T7e5_40NcgRyind-yeg4PAkHz9TNZJ22F4RcbOvCpAs03JNf1vKNNTZB/newcopy + //Application.OpenURL("https://goo.gl/wFSbv2");// V3:https://script.google.com/d/1CxQDSXflsXRaH3M7xGfrIDrFwOIHWPsYTWi4mRZ_k77nyIInTgIk63Kd/newcopy"); + } + if (GUILayout.Button("Verify", EditorStyles.toolbarButton)) + { + ClearErrors(); + VerifyGoogleService(mProp_Google_WebServiceURL.stringValue); + GUI.changed = false; + } + GUILayout.EndHorizontal(); + + + if (string.IsNullOrEmpty(mProp_Google_WebServiceURL.stringValue)) + { + EditorGUILayout.HelpBox(WebServiceHelp, MessageType.Info); + } + + if (GUI.changed) + { + if (string.IsNullOrEmpty(mProp_Google_WebServiceURL.stringValue)) + { + mProp_Google_SpreadsheetKey.stringValue = string.Empty; + mProp_Google_SpreadsheetName.stringValue = string.Empty; + } + + + // If the web service changed then clear the cached spreadsheet keys + mGoogleSpreadsheets.Clear(); + + GUI.changed = false; + ClearErrors(); + } + GUI.enabled = true; + } + + void OnGUI_GoogleSpreadsheetsInGDrive() + { + GUI.enabled = mConnection_WWW==null; + + string[] Spreadsheets; + string[] SpreadsheetsKey; + if (mGoogleSpreadsheets.Count>0 || string.IsNullOrEmpty(mProp_Google_SpreadsheetKey.stringValue)) + { + Spreadsheets = new List(mGoogleSpreadsheets.Keys).ToArray(); + SpreadsheetsKey = new List(mGoogleSpreadsheets.Values).ToArray(); + } + else + { + Spreadsheets = new[]{mProp_Google_SpreadsheetName.stringValue ?? string.Empty}; + SpreadsheetsKey = new[]{mProp_Google_SpreadsheetKey.stringValue ?? string.Empty}; + } + int mSpreadsheetIndex = Array.IndexOf(SpreadsheetsKey, mProp_Google_SpreadsheetKey.stringValue); + + //--[ Spreadsheets ]------------------ + GUILayout.BeginHorizontal(); + GUILayout.Space(10); + GUILayout.Label ("In Google Drive:", GUILayout.Width(100)); + + GUI.changed = false; + GUI.enabled = Spreadsheets != null && Spreadsheets.Length>0; + mSpreadsheetIndex = EditorGUILayout.Popup(mSpreadsheetIndex, Spreadsheets, EditorStyles.toolbarPopup); + if (GUI.changed && mSpreadsheetIndex >= 0) + { + mProp_Google_SpreadsheetKey.stringValue = SpreadsheetsKey[mSpreadsheetIndex]; + mProp_Google_SpreadsheetName.stringValue = Spreadsheets[mSpreadsheetIndex]; + GUI.changed = false; + } + GUI.enabled = true; + + GUI.enabled = !string.IsNullOrEmpty(mProp_Google_SpreadsheetKey.stringValue) && mConnection_WWW==null; + if (GUILayout.Button("X", EditorStyles.toolbarButton,GUILayout.ExpandWidth(false))) + mProp_Google_SpreadsheetKey.stringValue = string.Empty; + GUI.enabled = true; + GUILayout.Space(10); + GUILayout.EndHorizontal(); + + GUILayout.Space(2); + + //--[ Spreadsheets Operations ]------------------ + GUILayout.BeginHorizontal(); + GUILayout.Space(114); + if (GUILayout.Button("New", EditorStyles.toolbarButton,GUILayout.ExpandWidth(true))) + Google_NewSpreadsheet(); + + GUI.enabled = !string.IsNullOrEmpty(mProp_Google_SpreadsheetKey.stringValue) && mConnection_WWW==null; + if (GUILayout.Button("Open", EditorStyles.toolbarButton,GUILayout.ExpandWidth(true))) + OpenGoogleSpreadsheet(mProp_Google_SpreadsheetKey.stringValue); + GUI.enabled = mConnection_WWW==null; + + GUILayout.Space(5); + + if (TestButton(eTest_ActionType.Button_GoogleSpreadsheet_RefreshList, "Refresh", EditorStyles.toolbarButton,GUILayout.ExpandWidth(true))) + EditorApplication.update+=Google_FindSpreadsheets; + + GUILayout.Space(10); + GUILayout.EndHorizontal(); + + GUILayout.Space(15); + + if (!string.IsNullOrEmpty(mProp_Google_SpreadsheetKey.stringValue)) + OnGUI_GoogleButtons_ImportExport( mProp_Google_SpreadsheetKey.stringValue ); + + GUI.enabled = true; + } + + + private void OnGUI_ImportButtons() + { + eSpreadsheetUpdateMode Mode = SynchronizationButtons("Import"); + if (Mode != eSpreadsheetUpdateMode.None || InTestAction(eTest_ActionType.Button_GoogleSpreadsheet_Import)) + { + if (mTestAction == eTest_ActionType.Button_GoogleSpreadsheet_Import) + Mode = (eSpreadsheetUpdateMode)mTestActionArg; + + serializedObject.ApplyModifiedProperties(); + + var modeCopy = Mode; + GUITools.DelayedCall(() => Import_Google(modeCopy)); + } + } + + private void OnGUI_ExportButtons() + { + eSpreadsheetUpdateMode Mode = SynchronizationButtons("Export"); + if (Mode != eSpreadsheetUpdateMode.None || InTestAction(eTest_ActionType.Button_GoogleSpreadsheet_Export)) + { + if (mTestAction == eTest_ActionType.Button_GoogleSpreadsheet_Export) + Mode = (eSpreadsheetUpdateMode)mTestActionArg; + + serializedObject.ApplyModifiedProperties(); + + var modeCopy = Mode; + GUITools.DelayedCall(() => Export_Google(modeCopy)); + } + } + + void OnGUI_GoogleButtons_ImportExport( string SpreadsheetKey ) + { + GUI.enabled = !string.IsNullOrEmpty(SpreadsheetKey) && mConnection_WWW==null; + + bool vertical = EditorGUIUtility.currentViewWidth < 450; + + if (vertical) + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + OnGUI_ImportButtons(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + OnGUI_ExportButtons(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + else + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + OnGUI_ImportButtons(); + GUILayout.FlexibleSpace(); + OnGUI_ExportButtons(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.BeginVertical(); + EditorGUIUtility.labelWidth += 10; + EditorGUILayout.PropertyField(mProp_Spreadsheet_SpecializationAsRows, new GUIContent("Show Specializations as Rows", "true: Make each specialization a separate row (e.g. Term[VR]..., Term[Touch]....\nfalse: Merge specializations into same cell separated by [i2s_XXX]")); + EditorGUILayout.PropertyField(mProp_Spreadsheet_SortRows, new GUIContent("Sort Rows", "true: Sort each term by its name....\nfalse: Keep the terms order")); + EditorGUIUtility.labelWidth -= 10; + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + GUILayout.Space(10); + + + GUI.enabled = true; + } + + eSpreadsheetUpdateMode SynchronizationButtons( string Operation, bool ForceReplace = false ) + { + eSpreadsheetUpdateMode Result = eSpreadsheetUpdateMode.None; + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Width (1)); + GUI.backgroundColor = Color.white; + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Label(Operation, EditorStyles.miniLabel); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + if (GUILayout.Button( "Replace", EditorStyles.toolbarButton, GUILayout.Width(60))) + Result = eSpreadsheetUpdateMode.Replace; + + if (ForceReplace) GUI.enabled = false; + if (GUILayout.Button( "Merge", EditorStyles.toolbarButton, GUILayout.Width(60))) + Result = eSpreadsheetUpdateMode.Merge; + + if (GUILayout.Button( "Add New", EditorStyles.toolbarButton, GUILayout.Width(60))) + Result = eSpreadsheetUpdateMode.AddNewTerms; + GUI.enabled = mConnection_WWW==null; + GUILayout.Space(1); + GUILayout.EndHorizontal(); + + GUILayout.Space(2); + GUILayout.EndVertical(); + + if (Result != eSpreadsheetUpdateMode.None) + ClearErrors(); + + return Result; + } + #endregion + + void VerifyGoogleService( string WebServiceURL ) + { + #if UNITY_WEBPLAYER + ShowError ("Contacting google translation is not yet supported on WebPlayer" ); + #else + StopConnectionWWW(); + mWebService_Status = null; + mConnection_WWW = UnityWebRequest.Get(WebServiceURL + "?action=Ping"); + I2Utils.SendWebRequest(mConnection_WWW); + mConnection_Callback = OnVerifyGoogleService; + EditorApplication.update += CheckForConnection; + mConnection_Text = "Verifying Web Service"; + //mConnection_TimeOut = Time.realtimeSinceStartup + 10; + #endif + } + + void OnVerifyGoogleService( string Result, string Error ) + { + if (Result.Contains("Authorization is required to perform that action")) + { + ShowWarning("You need to authorize the webservice before using it. Check the steps 4 and 5 in the WebService Script"); + mWebService_Status = "Offline"; + return; + } + + try + { + var data = JSON.Parse(Result).AsObject; + int version = 0; + if (!int.TryParse(data["script_version"], out version)) + version = 0; + int requiredVersion = LocalizationManager.GetRequiredWebServiceVersion(); + + if (requiredVersion == version) + { + mWebService_Status = "Online"; + ClearErrors(); + } + else + { + mWebService_Status = "UnsupportedVersion"; + ShowError("The current Google WebService is not supported.\nPlease, delete the WebService from the Google Drive and Install the latest version."); + } + } + catch (Exception) + { + ShowError("Unable to access the WebService"); + mWebService_Status = "Offline"; + } + } + + + void Export_Google( eSpreadsheetUpdateMode UpdateMode ) + { + StopConnectionWWW(); + LanguageSourceData source = GetSourceData(); + mConnection_WWW = source.Export_Google_CreateWWWcall( UpdateMode ); + if (mConnection_WWW==null) + { + OnExported_Google(string.Empty, "WebPlayer can't contact Google"); + } + else + { + mConnection_Callback = OnExported_Google; + EditorApplication.update += CheckForConnection; + mConnection_Text = "Uploading spreadsheet"; + //mConnection_TimeOut = Time.realtimeSinceStartup + 10; + } + } + + void OnExported_Google( string Result, string Error ) + { + // Checkf or error, but discard the "necessary data rewind wasn't possible" as thats not a real error, just a bug in Unity with POST redirects + if (!string.IsNullOrEmpty(Error) && !Error.Contains("rewind")) + { + Debug.Log (Error); + ShowError("Unable to access google"); + return; + } + + if (EditorPrefs.GetBool("I2Loc OpenDataSourceAfterExport", true) && !string.IsNullOrEmpty(GetSourceData().Google_SpreadsheetName)) + OpenGoogleSpreadsheet(GetSourceData().Google_SpreadsheetKey ); + mProp_GoogleLiveSyncIsUptoDate.boolValue = true; + } + + static void OpenGoogleSpreadsheet( string SpreadsheetKey ) + { + ClearErrors(); + string SpreadsheetUrl = "https://docs.google.com/spreadsheet/ccc?key=" + SpreadsheetKey; + Application.OpenURL(SpreadsheetUrl); + } + + public abstract LanguageSourceData GetSourceData(); + + + void Import_Google( eSpreadsheetUpdateMode UpdateMode ) + { + StopConnectionWWW(); + LanguageSourceData source = GetSourceData(); + mConnection_WWW = source.Import_Google_CreateWWWcall(true, false); + if (mConnection_WWW==null) + { + OnImported_Google(string.Empty, "Unable to import from google", eSpreadsheetUpdateMode.Replace); + } + else + { + mConnection_Callback=null; + switch (UpdateMode) + { + case eSpreadsheetUpdateMode.Replace : mConnection_Callback += OnImported_Google_Replace; break; + case eSpreadsheetUpdateMode.Merge : mConnection_Callback += OnImported_Google_Merge; break; + case eSpreadsheetUpdateMode.AddNewTerms : mConnection_Callback += OnImported_Google_AddNewTerms; break; + } + EditorApplication.update += CheckForConnection; + mConnection_Text = "Downloading spreadsheet"; + //mConnection_TimeOut = Time.realtimeSinceStartup + 10; + } + } + + void OnImported_Google_Replace( string Result, string Error ) { OnImported_Google(Result, Error, eSpreadsheetUpdateMode.Replace); } + void OnImported_Google_Merge( string Result, string Error ) { OnImported_Google(Result, Error, eSpreadsheetUpdateMode.Merge); } + void OnImported_Google_AddNewTerms( string Result, string Error ) { OnImported_Google(Result, Error, eSpreadsheetUpdateMode.AddNewTerms); } + + void OnImported_Google( string Result, string Error, eSpreadsheetUpdateMode UpdateMode ) + { + if (!string.IsNullOrEmpty(Error)) + { + Debug.Log(Error); + ShowError("Unable to access google"); + return; + } + LanguageSourceData source = GetSourceData(); + string ErrorMsg = source.Import_Google_Result(Result, UpdateMode); + bool HasErrors = !string.IsNullOrEmpty(ErrorMsg); + if (HasErrors) + ShowError(ErrorMsg); + + serializedObject.Update(); + ParseTerms(true, false, !HasErrors); + mSelectedKeys.Clear (); + mSelectedCategories.Clear(); + ScheduleUpdateTermsToShowInList(); + mLanguageSource.GetCategories(false, mSelectedCategories); + + EditorUtility.SetDirty (target); + AssetDatabase.SaveAssets(); + } + + void CheckForConnection() + { + if (mConnection_WWW!=null && mConnection_WWW.isDone) + { + fnConnectionCallback callback = mConnection_Callback; + string Result = string.Empty; + string Error = mConnection_WWW.error; + + if (string.IsNullOrEmpty(Error)) + { + // Try first converting with the right encoding + var bytes = mConnection_WWW.downloadHandler.data; + if (bytes!=null) + Result = Encoding.UTF8.GetString(bytes); //mConnection_WWW.text; + + // Fallback to use the default encoding + else + Result = mConnection_WWW.downloadHandler.text; + } + + StopConnectionWWW(); + if (callback!=null) + callback(Result, Error); + } + /*else + if (Time.realtimeSinceStartup > mConnection_TimeOut+30) + { + fnConnectionCallback callback = mConnection_Callback; + StopConnectionWWW(); + if (callback!=null) + callback(string.Empty, "Time Out"); + }*/ + } + + void StopConnectionWWW() + { + EditorApplication.update -= CheckForConnection; + mConnection_WWW = null; + mConnection_Callback = null; + mConnection_Text = string.Empty; + } + + #region New Spreadsheet + + void Google_NewSpreadsheet() + { + #if UNITY_WEBPLAYER + ShowError ("Contacting google translation is not yet supported on WebPlayer" ); + #else + + ClearErrors(); + string SpreadsheetName; + + LanguageSourceData source = GetSourceData(); + if (source.IsGlobalSource()) + SpreadsheetName = string.Format("{0} Localization", PlayerSettings.productName); + else + SpreadsheetName = string.Format("{0} {1} {2}", PlayerSettings.productName, Editor_GetCurrentScene(), source.ownerObject.name); + + string query = mProp_Google_WebServiceURL.stringValue + "?action=NewSpreadsheet&name=" + Uri.EscapeDataString(SpreadsheetName) + "&password="+ Uri.EscapeDataString(mProp_Google_Password.stringValue); + + mConnection_WWW = UnityWebRequest.Get(query); + I2Utils.SendWebRequest(mConnection_WWW); + mConnection_Callback = Google_OnNewSpreadsheet; + EditorApplication.update += CheckForConnection; + mConnection_Text = "Creating Spreadsheet"; + //mConnection_TimeOut = Time.realtimeSinceStartup + 10; + #endif + } + + void Google_OnNewSpreadsheet( string Result, string Error ) + { + if (!string.IsNullOrEmpty(Error)) + { + ShowError("Unable to access google"); + return; + } + if (Result=="Wrong Password") + { + ShowError(Result); + return; + } + + try + { + var data = JSON.Parse(Result).AsObject; + + string name = data["name"]; + string key = data["id"]; + + serializedObject.Update(); + mProp_Google_SpreadsheetKey.stringValue = key; + mProp_Google_SpreadsheetName.stringValue = name; + serializedObject.ApplyModifiedProperties(); + mGoogleSpreadsheets[name] = key; + + LanguageSourceData source = GetSourceData(); + if (source.mTerms.Count>0 || source.mLanguages.Count>0) + Export_Google( eSpreadsheetUpdateMode.Replace ); + else + if (EditorPrefs.GetBool("I2Loc OpenDataSourceAfterExport", true)) + OpenGoogleSpreadsheet( key ); + + } + catch(Exception e) + { + ShowError (e.Message); + } + } + + #endregion + + #region FindSpreadsheets + + void Google_FindSpreadsheets() + { + ClearErrors(); + EditorApplication.update -= Google_FindSpreadsheets; + string query = mProp_Google_WebServiceURL.stringValue + "?action=GetSpreadsheetList&password="+ Uri.EscapeDataString(mProp_Google_Password.stringValue); + mConnection_WWW = UnityWebRequest.Get(query); + I2Utils.SendWebRequest(mConnection_WWW); + mConnection_Callback = Google_OnFindSpreadsheets; + EditorApplication.update += CheckForConnection; + mConnection_Text = "Accessing google"; + //mConnection_TimeOut = Time.realtimeSinceStartup + 10; + } + + void Google_OnFindSpreadsheets( string Result, string Error) + { + if (!string.IsNullOrEmpty(Error)) + { + ShowError("Unable to access google"); + return; + } + + if (Result=="Wrong Password") + { + ShowError(Result); + return; + } + + try + { + mGoogleSpreadsheets.Clear(); + var data = JSON.Parse(Result).AsObject; + foreach (KeyValuePair element in data) + mGoogleSpreadsheets[element.Key] = element.Value; + } + catch(Exception e) + { + ShowError (e.Message); + } + + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Google.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Google.cs.meta new file mode 100644 index 00000000..77261f67 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Google.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 800caf7e364ec2947be099b4f9ed976d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Local.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Local.cs new file mode 100644 index 00000000..ade61d17 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Local.cs @@ -0,0 +1,339 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + enum eLocalSpreadsheeet { CSV, XLS, XLSX, NONE } + + void OnGUI_Spreadsheet_Local() + { + GUILayout.Space(10); + GUILayout.BeginVertical(); + + GUILayout.BeginHorizontal(); + GUILayout.Label ("File:", GUILayout.ExpandWidth(false)); + + mProp_Spreadsheet_LocalFileName.stringValue = EditorGUILayout.TextField(mProp_Spreadsheet_LocalFileName.stringValue); + /*if (GUILayout.Button("...", "toolbarbutton", GUILayout.ExpandWidth(false))) + { + string sFileName = mProp_Spreadsheet_LocalFileName.stringValue; + + string sPath = string.Empty; + try { + sPath = System.IO.Path.GetDirectoryName(sFileName); + } + catch( System.Exception e){} + + if (string.IsNullOrEmpty(sPath)) + sPath = Application.dataPath + "/"; + + sFileName = System.IO.Path.GetFileName(sFileName); + if (string.IsNullOrEmpty(sFileName)) + sFileName = "Localization.csv"; + + string FullFileName = EditorUtility.SaveFilePanel("Select CSV File", sPath, sFileName, "csv"); + //string FullFileName = EditorUtility.OpenFilePanel("Select CSV, XLS or XLSX File", sFileName, "csv;*.xls;*.xlsx"); + + if (!string.IsNullOrEmpty(FullFileName)) + { + Prop_LocalFileName.stringValue = TryMakingPathRelativeToProject(FullFileName); + } + }*/ + GUILayout.EndHorizontal(); + + //--[ Find current extension ]--------------- + eLocalSpreadsheeet CurrentExtension = eLocalSpreadsheeet.NONE; + //string FileNameLower = Prop_LocalFileName.stringValue.ToLower(); + /*if (FileNameLower.EndsWith(".csv")) */CurrentExtension = eLocalSpreadsheeet.CSV; + /*if (FileNameLower.EndsWith(".xls")) CurrentExtension = eLocalSpreadsheeet.XLS; + if (FileNameLower.EndsWith(".xlsx")) CurrentExtension = eLocalSpreadsheeet.XLSX;*/ + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + switch (CurrentExtension) + { + case eLocalSpreadsheeet.NONE : + case eLocalSpreadsheeet.CSV : + { + string FileTypesDesc = "Select or Drag any file of the following types:\n\n"; + FileTypesDesc+= "*.csv (Comma Separated Values)\n"; + FileTypesDesc+= "*.txt (CSV file renamed as txt)\n"; + //FileTypesDesc+= "\n*.xls (Excel 97-2003)"; + //FileTypesDesc+= "\n*.xlsx (Excel Open XML format)"; + EditorGUILayout.HelpBox(FileTypesDesc, MessageType.None); + } + break; + case eLocalSpreadsheeet.XLS : EditorGUILayout.HelpBox("Excel 97-2003", MessageType.None); break; + case eLocalSpreadsheeet.XLSX : EditorGUILayout.HelpBox("Excel Open XML format", MessageType.None); break; + } + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUILayout.EndVertical(); + + //--[ Allow Dragging files ]----------------- + if (GUILayoutUtility.GetLastRect().Contains (UnityEngine.Event.current.mousePosition) && IsValidDraggedLoadSpreadsheet()) + { + if (UnityEngine.Event.current.type == EventType.DragUpdated) + DragAndDrop.visualMode = DragAndDropVisualMode.Link; + + if (UnityEngine.Event.current.type == EventType.DragPerform) + { + mProp_Spreadsheet_LocalFileName.stringValue = TryMakingPathRelativeToProject( DragAndDrop.paths[0] ); + DragAndDrop.AcceptDrag(); + UnityEngine.Event.current.Use(); + } + } + + GUILayout.Space(10); + + OnGUI_Spreadsheet_Local_ImportExport( CurrentExtension, mProp_Spreadsheet_LocalFileName.stringValue ); + + //if (Application.platform == RuntimePlatform.OSXEditor) + + //-- CSV Separator ---------------- + GUI.changed = false; + var CSV_Separator = mProp_Spreadsheet_LocalCSVSeparator.stringValue; + if (string.IsNullOrEmpty (CSV_Separator)) + CSV_Separator = ","; + + GUILayout.Space(10); + GUILayout.BeginVertical("Box"); + GUILayout.BeginHorizontal(); + GUILayout.Label("Separator:"); + GUILayout.FlexibleSpace(); + + if (GUILayout.Toggle(CSV_Separator==",", "Comma(,)") && CSV_Separator!=",") + CSV_Separator = ","; + + GUILayout.FlexibleSpace(); + + if (GUILayout.Toggle(CSV_Separator==";", "Semicolon(;)") && CSV_Separator!=";") + CSV_Separator = ";"; + + GUILayout.FlexibleSpace(); + + if (GUILayout.Toggle(CSV_Separator=="\t", "TAB(\\t)") && CSV_Separator!="\t") + CSV_Separator = "\t"; + + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + //--[ Encoding ]--------------- + var encodings = Encoding.GetEncodings ().OrderBy(e=>e.Name).ToArray(); + var encodingNames = encodings.Select(e=>e.Name).ToArray(); + + int idx = Array.IndexOf (encodingNames, mProp_Spreadsheet_LocalCSVEncoding.stringValue); + if (idx == -1) + idx = Array.IndexOf (encodingNames, "utf-8"); + EditorGUIUtility.labelWidth = 80; + + idx = EditorGUILayout.Popup ("Encoding:", idx, encodingNames); + if (GUILayout.Button("Default", GUILayout.ExpandWidth(false))) + idx = Array.IndexOf (encodingNames, "utf-8"); + + if (idx>=0 && mProp_Spreadsheet_LocalCSVEncoding.stringValue != encodings [idx].Name) + mProp_Spreadsheet_LocalCSVEncoding.stringValue = encodings [idx].Name; + GUILayout.EndHorizontal(); + + GUILayout.EndVertical(); + + if (GUI.changed) + { + mProp_Spreadsheet_LocalCSVSeparator.stringValue = CSV_Separator; + } + + GUILayout.Space(10); + EditorGUILayout.HelpBox("On some Mac OS, there is a Unity Bug that makes the IDE crash when selecting a CSV file in the Open/Save File Dialog.\nJust by clicking the file, unity tries to preview the content and crashes.\n\nIf any of your the team members use Mac, its adviced to import/export the CSV Files with TXT extension.", MessageType.Warning); + GUILayout.Space(10); + + OnGUI_ShowMsg(); + } + + bool IsValidDraggedLoadSpreadsheet() + { + if (DragAndDrop.paths==null || DragAndDrop.paths.Length!=1) + return false; + + string sPath = DragAndDrop.paths[0].ToLower(); + if (sPath.EndsWith(".csv")) return true; + if (sPath.EndsWith(".txt")) return true; + //if (sPath.EndsWith(".xls")) return true; + //if (sPath.EndsWith(".xlsx")) return true; + + /*int iChar = sPath.LastIndexOfAny( "/\\.".ToCharArray() ); + if (iChar<0 || sPath[iChar]!='.') + return true; + return false;*/ + return false; + } + + string TryMakingPathRelativeToProject( string FileName ) + { + string ProjectPath = Application.dataPath.ToLower(); + string FileNameLower = FileName.ToLower(); + + if (FileNameLower.StartsWith(ProjectPath)) + FileName = FileName.Substring(ProjectPath.Length+1); + else + if (FileNameLower.StartsWith("assets/")) + FileName = FileName.Substring("assets/".Length); + return FileName; + } + + void OnGUI_Spreadsheet_Local_ImportExport( eLocalSpreadsheeet CurrentExtension, string File ) + { + GUI.enabled = CurrentExtension!=eLocalSpreadsheeet.NONE; + + GUILayout.BeginHorizontal(); + GUILayout.Space(10); + + GUI.backgroundColor = Color.Lerp(Color.gray, Color.white, 0.5f); + eSpreadsheetUpdateMode Mode = SynchronizationButtons("Import"); + if ( Mode!= eSpreadsheetUpdateMode.None) + Import_Local(File, CurrentExtension, Mode); + + GUILayout.FlexibleSpace(); + + GUI.backgroundColor = Color.Lerp(Color.gray, Color.white, 0.5f); + Mode = SynchronizationButtons("Export", true); + if ( Mode != eSpreadsheetUpdateMode.None) + Export_Local(File, CurrentExtension, Mode); + + GUILayout.Space(10); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + GUILayout.BeginVertical(); + EditorGUIUtility.labelWidth += 10; + EditorGUILayout.PropertyField(mProp_Spreadsheet_SpecializationAsRows, new GUIContent("Show Specializations as Rows", "true: Make each specialization a separate row (e.g. Term[VR]..., Term[Touch]....\nfalse: Merge specializations into same cell separated by [i2s_XXX]")); + EditorGUILayout.PropertyField(mProp_Spreadsheet_SortRows, new GUIContent("Sort Rows", "true: Sort each term by its name....\nfalse: Keep the terms order")); + EditorGUIUtility.labelWidth -= 10; + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + + + GUI.enabled = true; + } + + void Import_Local( string File, eLocalSpreadsheeet CurrentExtension, eSpreadsheetUpdateMode UpdateMode ) + { + try + { + serializedObject.ApplyModifiedProperties(); + serializedObject.Update(); + ClearErrors(); + + if (string.IsNullOrEmpty(File)) + File = Application.dataPath + "/Localization.csv"; + else + if (!Path.IsPathRooted(File)) + File = string.Concat(Application.dataPath, "/", File); + + // On Mac there is an issue with previewing CSV files, so its forced to only TXT + if (Application.platform == RuntimePlatform.OSXEditor) + File = EditorUtility.OpenFilePanel("Select a CSV file renamed as TXT", File, "txt"); + else + File = EditorUtility.OpenFilePanel("Select a CSV file or a CSV file renamed as TXT", File, "csv;*.txt"); + //File = EditorUtility.OpenFilePanel("Select CSV, XLS or XLSX File", File, "csv;*.xls;*.xlsx"); + if (!string.IsNullOrEmpty(File)) + { + mLanguageSource.Spreadsheet_LocalFileName = TryMakingPathRelativeToProject(File); + switch (CurrentExtension) + { + case eLocalSpreadsheeet.CSV : Import_CSV(File, UpdateMode); break; + } + ParseTerms(true, false, true); + EditorUtility.SetDirty (target); + AssetDatabase.SaveAssets(); + } + } + catch (Exception ex) + { + ShowError("Unable to import file"); + Debug.LogError(ex.Message); + } + } + + void Import_CSV( string FileName, eSpreadsheetUpdateMode UpdateMode ) + { + LanguageSourceData source = GetSourceData(); + var encoding = Encoding.GetEncoding (mProp_Spreadsheet_LocalCSVEncoding.stringValue); + if (encoding == null) + encoding = Encoding.UTF8; + string CSVstring = LocalizationReader.ReadCSVfile (FileName, encoding); + + char Separator = mProp_Spreadsheet_LocalCSVSeparator.stringValue.Length>0 ? mProp_Spreadsheet_LocalCSVSeparator.stringValue[0] : ','; + string sError = source.Import_CSV( string.Empty, CSVstring, UpdateMode, Separator); + if (!string.IsNullOrEmpty(sError)) + ShowError(sError); + + mSelectedCategories = source.GetCategories(); + } + + void Export_Local( string File, eLocalSpreadsheeet CurrentExtension, eSpreadsheetUpdateMode UpdateMode ) + { + try + { + serializedObject.ApplyModifiedProperties(); + serializedObject.Update(); + ClearErrors(); + + string sPath = string.Empty; + if (!Path.IsPathRooted(File)) + File = string.Concat(Application.dataPath, "/", File); + + try { + sPath = Path.GetDirectoryName(File); + } + catch( Exception){} + + if (string.IsNullOrEmpty(sPath)) + sPath = Application.dataPath + "/"; + + File = Path.GetFileName(File); + if (string.IsNullOrEmpty(File)) + File = "Localization.csv"; + + if (Application.platform == RuntimePlatform.OSXEditor) + File = EditorUtility.SaveFilePanel("Select a CSV file renamed as TXT", sPath, File, "txt"); + else + File = EditorUtility.SaveFilePanel("Select a CSV or TXT file", sPath, File, "csv;*.txt"); + if (!string.IsNullOrEmpty(File)) + { + mLanguageSource.Spreadsheet_LocalFileName = TryMakingPathRelativeToProject(File); + + char Separator = mProp_Spreadsheet_LocalCSVSeparator.stringValue.Length>0 ? mProp_Spreadsheet_LocalCSVSeparator.stringValue[0] : ','; + var encoding = Encoding.GetEncoding (mProp_Spreadsheet_LocalCSVEncoding.stringValue); + if (encoding == null) + encoding = Encoding.UTF8; + + switch (CurrentExtension) + { + case eLocalSpreadsheeet.CSV : Export_CSV(File, UpdateMode, Separator, encoding); break; + } + } + } + catch (Exception) + { + ShowError("Unable to export file\nCheck it is not READ-ONLY and that\nits not opened in an external viewer"); + } + } + + public void Export_CSV( string FileName, eSpreadsheetUpdateMode UpdateMode, char Separator, Encoding encoding ) + { + LanguageSourceData source = GetSourceData(); + + string CSVstring = source.Export_CSV(null, Separator, mProp_Spreadsheet_SpecializationAsRows.boolValue, mProp_Spreadsheet_SortRows.boolValue); + File.WriteAllText (FileName, CSVstring, encoding); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Local.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Local.cs.meta new file mode 100644 index 00000000..dd66d4c6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Spreadsheet_Local.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: fdca66efafe784661b464934cacff065 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms.cs new file mode 100644 index 00000000..8063255e --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms.cs @@ -0,0 +1,840 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + #region Variables + + Vector2 mScrollPos_Keys = Vector2.zero; + + public static string mKeyToExplore; // Key that should show all the language details + static string KeyList_Filter = ""; + float mRowSize=-1; + float ScrollHeight; + float mTermList_MaxWidth = -1; + + public static List mSelectedKeys = new List(); // Selected Keys in the list of mParsedKeys + public static List mSelectedCategories = new List(); + + + public enum eFlagsViewKeys + { + Used = 1<<1, + Missing = 1<<2, + NotUsed = 1<<3, + Untranslated = 1<<4, + } + public static int mFlagsViewKeys = (int)eFlagsViewKeys.Used | (int)eFlagsViewKeys.NotUsed; + + public static string mTermsList_NewTerm; + Rect mKeyListFilterRect; + + #endregion + + #region GUI Key List + + float ExpandedViewHeight; + float TermsListHeight; + + void OnGUI_KeysList(bool AllowExpandKey = true, float Height = 300.0f, bool ShowTools=true) + { + ///if (mTermList_MaxWidth<=0) + CalculateTermsListMaxWidth(); + + //--[ List Filters ]-------------------------------------- + + // The ID of this control is registered here to avoid losing focus when the terms list grows in the scrollbox + // This control is drawn later on + int KeyListFilterID = GUIUtility.GetControlID( FocusType.Keyboard ); + + OnGUI_ShowMsg(); + + GUILayout.BeginHorizontal(); + GUIStyle bstyle = new GUIStyle ("toolbarbutton"); + bstyle.fontSize = 15; + if (GUILayout.Button (new GUIContent("\u21bb", "Parse Scene and update terms list with missing and unused terms"), bstyle, GUILayout.Width(25))) + EditorApplication.update += DoParseTermsInCurrentSceneAndScripts; + if (GUILayout.Button(new GUIContent("\u21ea", "Refresh the translation of all Localize objects"), bstyle, GUILayout.Width(25))) + CallLocalizeAll(); + + GUILayout.Space (1); + + var oldFlags = mFlagsViewKeys; + mFlagsViewKeys = OnGUI_FlagToogle("Used","Shows All Terms referenced in the parsed scenes", mFlagsViewKeys, (int)eFlagsViewKeys.Used); + mFlagsViewKeys = OnGUI_FlagToogle("Not Used", "Shows all Terms from the Source that are not been used", mFlagsViewKeys, (int)eFlagsViewKeys.NotUsed); + mFlagsViewKeys = OnGUI_FlagToogle("Missing","Shows all Terms Used but not defined in the Source", mFlagsViewKeys, (int)eFlagsViewKeys.Missing); + + mFlagsViewKeys = OnGUI_FlagToogle("Untranslated", "Shows all Terms that were not translated to any language", mFlagsViewKeys, (int)eFlagsViewKeys.Untranslated); + + if (oldFlags!=mFlagsViewKeys) + ScheduleUpdateTermsToShowInList(); + + OnGUI_SelectedCategories(); + + GUILayout.EndHorizontal(); + + /*//if (UnityEngine.Event.current.type == EventType.Repaint) + TermsListHeight = Screen.height - 400; + Debug.Log(UnityEngine.Event.current.type + " " + TermsListHeight + " " + Screen.height + " " + GUILayoutUtility.GetLastRect().yMax); + + //TermsListHeight = Mathf.Min(Screen.height*0.5f, TermsListHeight); + mScrollPos_Keys = GUILayout.BeginScrollView(mScrollPos_Keys, false, false, "horizontalScrollbar", "verticalScrollbar", LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(TermsListHeight)); + for (int i = 0; i < 1000; ++i) + GUILayout.Label("ahhh" + i); + GUILayout.EndScrollView(); + + return;*/ + TermsListHeight = Mathf.Min(Screen.height*0.5f, TermsListHeight); + + //--[ Keys List ]----------------------------------------- + GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f); + mScrollPos_Keys = GUILayout.BeginScrollView( mScrollPos_Keys, false, false, "horizontalScrollbar", "verticalScrollbar", LocalizeInspector.GUIStyle_OldTextArea ,GUILayout.Height(TermsListHeight)/*GUILayout.MinHeight(Height), GUILayout.MaxHeight(Screen.height), GUILayout.ExpandHeight(true)*/); + GUI.backgroundColor = Color.white; + + bool bAnyValidUsage = false; + + mRowSize = EditorStyles.toolbar.fixedHeight; + if (UnityEngine.Event.current!=null && UnityEngine.Event.current.type == EventType.Layout) + ScrollHeight = mScrollPos_Keys.y; + + float YPosMin = -ScrollHeight; + int nSkip = 0; + int nDraw = 0; + + if (mShowableTerms.Count == 0 && UnityEngine.Event.current.type == EventType.Layout) + UpdateTermsToShownInList (); + + float SkipSize = 0; + foreach (var parsedTerm in mShowableTerms) + { + string sKey = parsedTerm.Term; + string sCategory = parsedTerm.Category; + string FullKey = parsedTerm.FullTerm; + + int nUses = parsedTerm.Usage; + bAnyValidUsage = bAnyValidUsage | (nUses>=0); + + ShowTerm_termData = parsedTerm.termData; + + // Skip lines outside the view ----------------------- + YPosMin += mRowSize; + SkipSize += mRowSize; + float YPosMax = YPosMin + mRowSize; + bool isExpanded = AllowExpandKey && mKeyToExplore==FullKey; + if (!isExpanded && (YPosMax<-2*mRowSize || YPosMin>/*Screen.height*/TermsListHeight+mRowSize)) + { + if (YPosMin>TermsListHeight+mRowSize) + break; + + nSkip++; + continue; + } + nDraw++; + + //------------------------------------------------------ + + OnGUI_KeyHeader (sKey, sCategory, FullKey, nUses, YPosMin-mRowSize+mScrollPos_Keys.y); + + //--[ Key Details ]------------------------------- + + if (isExpanded) + { + GUILayout.Space(SkipSize); + SkipSize = 0; + OnGUI_KeyList_ShowKeyDetails(); + Rect rect = GUILayoutUtility.GetLastRect(); + if (rect.height>5) + ExpandedViewHeight = rect.height; + YPosMin += ExpandedViewHeight; + } + } + SkipSize += (mShowableTerms.Count - nDraw-nSkip) * mRowSize; + GUILayout.Space(SkipSize+2); + if (mSelectedCategories.Count < mParsedCategories.Count) + { + SkipSize += 25; + if (GUILayout.Button ("...", EditorStyles.label)) + { + mSelectedCategories.Clear (); + mSelectedCategories.AddRange (mParsedCategories); + } + } + OnGUI_KeysList_AddKey(); + + GUILayout.Label("", GUILayout.Width(mTermList_MaxWidth+10+30), GUILayout.Height(1)); + + GUILayout.EndScrollView(); + + TermsListHeight = YPosMin + mRowSize + 25;//SkipSize+25; + + //Rect ListRect = GUILayoutUtility.GetLastRect(); + //if (ListRect.height>5) + // TermsListHeight = ListRect.height; + //Debug.Log(nDraw + " " + nSkip + " " + Screen.height + " " + TermsListHeight); + + OnGUI_Keys_ListSelection( KeyListFilterID ); // Selection Buttons + +// if (!bAnyValidUsage) +// EditorGUILayout.HelpBox("Use (Tools\\Parse Terms) to find how many times each of the Terms are used", UnityEditor.MessageType.Info); + + if (ShowTools) + { + GUILayout.BeginHorizontal(); + GUI.enabled = mSelectedKeys.Count>0 || !string.IsNullOrEmpty(mKeyToExplore); + if (TestButton (eTest_ActionType.Button_AddSelectedTerms, new GUIContent("Add Terms", "Add terms to Source"), "Button", GUITools.DontExpandWidth)) AddTermsToSource(); + if (TestButton (eTest_ActionType.Button_RemoveSelectedTerms, new GUIContent("Remove Terms", "Remove Terms from Source"), "Button", GUITools.DontExpandWidth)) RemoveTermsFromSource(); + + GUILayout.FlexibleSpace (); + + if (GUILayout.Button ("Change Category")) OpenTool_ChangeCategoryOfSelectedTerms(); + GUI.enabled = true; + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace (); + bool newBool = GUILayout.Toggle(mLanguageSource.CaseInsensitiveTerms, "Case Insensitive Terms"); + if (newBool != mLanguageSource.CaseInsensitiveTerms) + { + mProp_CaseInsensitiveTerms.boolValue = newBool; + } + GUILayout.FlexibleSpace (); + GUILayout.EndHorizontal(); + } + //Debug.Log ("Draw: " + nDraw + " Skip: " + nSkip); + } + + static void ScheduleUpdateTermsToShowInList() + { + if (!mUpdateShowTermIsScheduled) + { + EditorApplication.update += UpdateTermsToShownInList; + mUpdateShowTermIsScheduled = true; + } + } + static bool mUpdateShowTermIsScheduled; + static void UpdateTermsToShownInList() + { + EditorApplication.update -= UpdateTermsToShownInList; + mUpdateShowTermIsScheduled = false; + + mShowableTerms.Clear (); + mSelectedCategories.Sort(); + foreach (KeyValuePair kvp in mParsedTerms) + { + ParsedTerm parsedTerm = kvp.Value; + if (ShouldShowTerm (parsedTerm.Term, parsedTerm.Category, parsedTerm.Usage, parsedTerm)) + mShowableTerms.Add(parsedTerm); + } + GUITools.RepaintInspectors(); + GUITools.ScheduleRepaintInspectors(); + } + + void OnGUI_KeyHeader (string sKey, string sCategory, string FullKey, int nUses, float YPosMin) + { + //--[ Toggle ]--------------------- + GUI.Box(new Rect(2, YPosMin+2, 18, mRowSize), "", "Toolbar"); + OnGUI_SelectableToogleListItem (new Rect(2, YPosMin+3, 15, mRowSize), FullKey, ref mSelectedKeys, "OL Toggle"); + + bool bEnabled = mSelectedKeys.Contains (FullKey); + //--[ Number of Objects using this key ]--------------------- + if (nUses >= 0) + { + if (nUses == 0) + { + GUI.color = Color.Lerp (Color.gray, Color.white, 0.5f); + GUI.Label (new Rect(20, YPosMin+2, 30, mRowSize), nUses.ToString (), "toolbarbutton"); + } + else + { + if (GUI.Button(new Rect(20, YPosMin + 2, 30, mRowSize), nUses.ToString(), "toolbarbutton")) + { + List selection = new List(mSelectedKeys); + if (!selection.Contains(FullKey)) + selection.Add(FullKey); + + List selGOs = new List(); + for (int i=0; i 0) + Selection.objects = selGOs.ToArray(); + else + ShowWarning("The selected Terms are not used in this Scene. Try opening other scenes"); + } + } + } + else + { + GUI.color = Color.Lerp (Color.red, Color.white, 0.6f); + if (GUI.Button (new Rect(20, YPosMin+2, 30, mRowSize), "", "toolbarbutton")) + { + mCurrentToolsMode = eToolsMode.Parse; + mCurrentViewMode = eViewMode.Tools; + } + } + GUI.color = Color.white; + + TermData termData = ShowTerm_termData!=null ? ShowTerm_termData : mLanguageSource.GetTermData (FullKey); + bool bKeyIsMissing = termData == null; + float MinX = 50; + if (bKeyIsMissing) + { + Rect rect = new Rect(50, YPosMin+2, mRowSize, mRowSize+2); + GUITools.DrawSkinIcon(rect, "CN EntryWarnIcon", "CN EntryWarn"); + GUI.Label (rect, new GUIContent ("", "This term is used in the scene, but its not localized in the Language Source")); + MinX += rect.width; + } + else MinX += 3; + + float listWidth = Mathf.Max(EditorGUIUtility.currentViewWidth / EditorGUIUtility.pixelsPerPoint, mTermList_MaxWidth); + Rect rectKey = new Rect(MinX, YPosMin+2, listWidth-MinX, mRowSize); + if (sCategory != LanguageSourceData.EmptyCategory) + rectKey.width -= 130; + if (mKeyToExplore == FullKey) + { + GUI.backgroundColor = Color.Lerp (Color.blue, Color.white, 0.8f); + if (GUI.Button (rectKey, new GUIContent (sKey, EditorStyles.foldout.onNormal.background), LocalizeInspector.GUIStyle_OldTextArea)) + { + mKeyToExplore = string.Empty; + ScheduleUpdateTermsToShowInList(); + ClearErrors (); + } + GUI.backgroundColor = Color.white; + } + else + { + GUIStyle LabelStyle = EditorStyles.label; + if (!bKeyIsMissing && !TermHasAllTranslations (mLanguageSource, termData)) + { + LabelStyle = new GUIStyle (EditorStyles.label); + LabelStyle.fontStyle = FontStyle.Italic; + GUI.color = Color.Lerp (Color.white, Color.yellow, 0.5f); + } + if (!bEnabled) + GUI.contentColor = Color.Lerp (Color.gray, Color.white, 0.3f); + if (GUI.Button (rectKey, sKey, LabelStyle)) + { + SelectTerm (FullKey); + ClearErrors (); + } + if (!bEnabled) + GUI.contentColor = Color.white; + GUI.color = Color.white; + } + //--[ Category ]-------------------------- + if (sCategory != LanguageSourceData.EmptyCategory) + { + if (mKeyToExplore == FullKey) + { + rectKey.x = listWidth - 100-38-20; + rectKey.width = 130; + if (GUI.Button (rectKey, sCategory, EditorStyles.toolbarButton)) + OpenTool_ChangeCategoryOfSelectedTerms (); + } + else + { + GUIStyle stl = new GUIStyle(EditorStyles.miniLabel); + stl.alignment = TextAnchor.MiddleRight; + rectKey.width = 130;//EditorStyles.miniLabel.CalcSize(new GUIContent(sCategory)).x; + rectKey.x = listWidth - rectKey.width - 38-20; + + if (GUI.Button (rectKey, sCategory, stl)) + { + SelectTerm (FullKey); + ClearErrors (); + } + } + } + } + + + void CalculateTermsListMaxWidth() + { + mTermList_MaxWidth = EditorGUIUtility.currentViewWidth / EditorGUIUtility.pixelsPerPoint - 120; + /*float maxWidth = Screen.width / 18; + foreach (KeyValuePair kvp in mParsedTerms) + { + var txt = kvp.Key; + if (txt.Length > 100) + txt = txt.Substring(0, 100); + var size = EditorStyles.label.CalcSize(new GUIContent(txt)); + mTermList_MaxWidth = Mathf.Max (mTermList_MaxWidth, size.x); + }*/ + } + + bool TermHasAllTranslations( LanguageSourceData source, TermData data ) + { + if (source==null) source = LocalizationManager.Sources[0]; + for (int i=0, imax=data.Languages.Length; ii ? source.mLanguages[i].IsEnabled() : true; + if (string.IsNullOrEmpty(data.Languages[i]) && isLangEnabled) + return false; + } + return true; + } + + void OnGUI_KeysList_AddKey() + { + GUILayout.BeginHorizontal(); + GUI.color = Color.Lerp(Color.gray, Color.white, 0.5f); + bool bWasEnabled = mTermsList_NewTerm!=null; + bool bEnabled = !GUILayout.Toggle (!bWasEnabled, "+", EditorStyles.toolbarButton, GUILayout.Width(30)); + GUI.color = Color.white; + + if (bWasEnabled && !bEnabled) mTermsList_NewTerm = null; + if (!bWasEnabled && bEnabled) mTermsList_NewTerm = string.Empty; + + if (bEnabled) + { + GUILayout.BeginHorizontal(EditorStyles.toolbar); + mTermsList_NewTerm = EditorGUILayout.TextField(mTermsList_NewTerm, EditorStyles.toolbarTextField, GUILayout.ExpandWidth(true)); + GUILayout.EndHorizontal(); + + LanguageSourceData.ValidateFullTerm( ref mTermsList_NewTerm ); + if (string.IsNullOrEmpty(mTermsList_NewTerm) || mLanguageSource.ContainsTerm(mTermsList_NewTerm) || mTermsList_NewTerm=="-") + GUI.enabled = false; + + if (TestButton (eTest_ActionType.Button_AddTerm_InTermsList, "Create Key", "toolbarbutton", GUILayout.ExpandWidth(false))) + { + AddLocalTerm(mTermsList_NewTerm); + SelectTerm( mTermsList_NewTerm ); + ClearErrors(); + mTermsList_NewTerm = null; + SetAllTerms_When_InferredTerms_IsInSource (); + } + GUI.enabled = true; + } + GUILayout.EndHorizontal(); + } + + void OpenTool_ChangeCategoryOfSelectedTerms() + { + mCurrentViewMode = eViewMode.Tools; + mCurrentToolsMode = eToolsMode.Categorize; + if (!string.IsNullOrEmpty(mKeyToExplore) && !mSelectedKeys.Contains(mKeyToExplore)) + mSelectedKeys.Add(mKeyToExplore); + mSelectedKeys.Sort(); + } + + void OnGUI_SelectedCategories() + { + if (mParsedCategories.Count == 0) + return; + + string text = "Categories"; + if (mSelectedCategories.Count() == 0) + text = "Nothing"; + else + if (mSelectedCategories.Count() == mParsedCategories.Count) + text = "Everything"; + else + text = mSelectedCategories.Count + " categories"; + + if (GUILayout.Button(new GUIContent(text), "toolbarbutton", GUILayout.Width(100))) + { + var menu = new GenericMenu(); + + menu.AddItem(new GUIContent("Everything"), false, () => + { + mSelectedCategories.Clear(); + mSelectedCategories.AddRange(mParsedCategories); + ScheduleUpdateTermsToShowInList(); + }); + menu.AddItem(new GUIContent("Nothing"), false, () => + { + mSelectedCategories.Clear(); + ScheduleUpdateTermsToShowInList(); + }); + menu.AddSeparator(""); + + var parsedList = mParsedCategories.OrderBy(x=>x).ToList(); + for (int i=0, imax=parsedList.Count; ix.StartsWith(categoryRoot))), () => + { + var CatHeader = category + "/"; + if (mSelectedCategories.Contains(category)) + { + mSelectedCategories.Remove(category); + + if (isHeader) + { + mSelectedCategories.RemoveAll(x => x.StartsWith(CatHeader)); + } + } + else + { + mSelectedCategories.Add(category); + if (isHeader) + { + mSelectedCategories.AddRange( parsedList.Where(x=>x.StartsWith(CatHeader))); + } + } + ScheduleUpdateTermsToShowInList(); + }); + if (isHeader) + { + menu.AddSeparator(category+"/"); + } + } + + menu.ShowAsContext(); + } + } + + void SaveSelectedCategories() + { + if (mSelectedCategories.Count == 0) { + EditorPrefs.DeleteKey ("I2 CategoryFilter"); + } else { + var data = string.Join(",", mSelectedCategories.ToArray()); + EditorPrefs.SetString ("I2 CategoryFilter", data); + } + } + + void LoadSelectedCategories() + { + var data = EditorPrefs.GetString ("I2 CategoryFilter", null); + if (!string.IsNullOrEmpty(data)) + { + mSelectedCategories.Clear (); + mSelectedCategories.AddRange( data.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); + } + } + + + // Bottom part of the Key list (buttons: All, None, Used,... to select the keys) + void OnGUI_Keys_ListSelection ( int KeyListFilterID ) + { + GUILayout.BeginHorizontal( "toolbarbutton" ); + + if (TestButton( eTest_ActionType.Button_SelectTerms_All, new GUIContent( "All", "Selects All Terms in the list" ), "toolbarbutton", GUILayout.ExpandWidth( false ) )) + { + mSelectedKeys.Clear(); + foreach (var kvp in mParsedTerms) + if (ShouldShowTerm( kvp.Value.Term, kvp.Value.Category, kvp.Value.Usage )) + mSelectedKeys.Add( kvp.Key ); + } + if (GUILayout.Button( new GUIContent( "None", "Clears the selection" ), "toolbarbutton", GUILayout.ExpandWidth( false ) )) { mSelectedKeys.Clear(); } + GUILayout.Space( 5 ); + + GUI.enabled = (mFlagsViewKeys & (int)eFlagsViewKeys.Used)>1; + if (TestButton(eTest_ActionType.Button_SelectTerms_Used, new GUIContent( "Used", "Selects All Terms referenced in the parsed scenes" ), "toolbarbutton", GUILayout.ExpandWidth( false ) )) + { + mSelectedKeys.Clear(); + foreach (var kvp in mParsedTerms) + if (kvp.Value.Usage > 0 && ShouldShowTerm( kvp.Value.Term, kvp.Value.Category, kvp.Value.Usage )) + mSelectedKeys.Add( kvp.Key ); + } + GUI.enabled = (mFlagsViewKeys & (int)eFlagsViewKeys.NotUsed)>1; + if (GUILayout.Button( new GUIContent( "Not Used", "Selects all Terms from the Source that are not been used" ), "toolbarbutton", GUILayout.ExpandWidth( false ) )) + { + mSelectedKeys.Clear(); + foreach (var kvp in mParsedTerms) + if (kvp.Value.Usage == 0 && ShouldShowTerm( kvp.Value.Term, kvp.Value.Category, kvp.Value.Usage )) + mSelectedKeys.Add( kvp.Key ); + } + + GUI.enabled = (mFlagsViewKeys & (int)eFlagsViewKeys.Missing)>1; + if (TestButton(eTest_ActionType.Button_SelectTerms_Missing, new GUIContent( "Missing", "Selects all Terms Used but not defined in the Source" ), "toolbarbutton", GUILayout.ExpandWidth( false ) )) + { + mSelectedKeys.Clear(); + foreach (var kvp in mParsedTerms) + if (!mLanguageSource.ContainsTerm( kvp.Key ) && ShouldShowTerm( kvp.Value.Term, kvp.Value.Category, kvp.Value.Usage )) + mSelectedKeys.Add( kvp.Key ); + } + + GUI.enabled = ((mFlagsViewKeys & (int)eFlagsViewKeys.Untranslated) > 1); + if (GUILayout.Button(new GUIContent("Untranslated", "Selects all Terms from the Source that are not translated to any language"), "toolbarbutton", GUILayout.ExpandWidth(false))) + { + mSelectedKeys.Clear(); + foreach (var kvp in mParsedTerms) + if (kvp.Value.termData.Languages.All(o => string.IsNullOrEmpty(o)) && ShouldShowTerm(kvp.Value.Term, kvp.Value.Category, kvp.Value.Usage)) + mSelectedKeys.Add(kvp.Key); + } + + GUI.enabled = true; + EditorGUI.BeginChangeCheck(); + + // Terms Filter + { + //KeyList_Filter = EditorGUILayout.TextField(KeyList_Filter, GUI.skin.GetStyle(GUITools.Style_ToolbarSearchTextField), GUILayout.ExpandWidth(true)); + GUILayout.Label( "", GUILayout.ExpandWidth( true ) ); + mKeyListFilterRect = GUILayoutUtility.GetLastRect(); + mKeyListFilterRect.xMax += 4; + + KeyList_Filter = GUITools.TextField( mKeyListFilterRect, KeyList_Filter, 255, GUI.skin.GetStyle( GUITools.Style_ToolbarSearchTextField ), KeyListFilterID ); + } + + + + if (GUILayout.Button( string.Empty, string.IsNullOrEmpty( KeyList_Filter ) ? GUITools.Style_ToolbarSearchCancelButtonEmpty : GUITools.Style_ToolbarSearchCancelButton, GUILayout.ExpandWidth( false ) )) + { + KeyList_Filter = string.Empty; + EditorApplication.update += RepaintScene; + GUI.FocusControl( "" ); + } + + string filterHelp = "Fiter Options:\ntext - shows all key/categories matching text\nc text - shows all terms of the text category\nf text - show terms having 'text' in their translations"; + GUILayout.Space(-5); + GUI.contentColor = new Color(1, 1, 1, 0.5f); + GUILayout.Label(new GUIContent(GUITools.Icon_Help.image, filterHelp), GUITools.DontExpandWidth); + GUI.contentColor = GUITools.White; + GUILayout.Space(-5); + + + + + if (EditorGUI.EndChangeCheck()) + { + mShowableTerms.Clear(); + GUI.changed = false; + } + + GUILayout.EndHorizontal(); + } + + + #endregion + + #region Filtering + + public bool ShouldShowTerm (string FullTerm) + { + ParsedTerm termData; + if (!mParsedTerms.TryGetValue(FullTerm, out termData)) + return false; + + return ShouldShowTerm (termData.Term, termData.Category, termData.Usage, termData); + } + + private static TermData ShowTerm_termData; + public static bool ShouldShowTerm (string Term, string Category, int nUses, ParsedTerm parsedTerm=null ) + { + if (!string.IsNullOrEmpty(Category) && !mSelectedCategories.Contains(Category)) + return false; + if (Term == "-") + return false; + + + var fullTerm = Term; + if (!string.IsNullOrEmpty(Category) && Category != LanguageSourceData.EmptyCategory) + fullTerm = Category + "/" + Term; + + if (parsedTerm != null && parsedTerm.termData != null) + ShowTerm_termData = parsedTerm.termData; + else + { + ShowTerm_termData = mLanguageSource.GetTermData (fullTerm); + if (parsedTerm!=null) + parsedTerm.termData = ShowTerm_termData; + } + + var filter = KeyList_Filter.Trim(); + bool useTranslation = filter.StartsWith("f ", StringComparison.OrdinalIgnoreCase); + if (useTranslation) + { + if (ShowTerm_termData == null) + return false; + + filter = filter.Substring(2).Trim(); + if (!string.IsNullOrEmpty(filter)) + { + bool hasFilter = false; + for (int i = 0; i < ShowTerm_termData.Languages.Length; ++i) + { + if (!string.IsNullOrEmpty(ShowTerm_termData.Languages[i]) + && StringContainsFilter(ShowTerm_termData.Languages[i], filter)) + { + hasFilter = true; + break; + } + + } + if (!hasFilter) + return false; + } + } + else + { + bool onlyCategory = filter.StartsWith("c ", StringComparison.OrdinalIgnoreCase); + if (onlyCategory) + filter = filter.Substring(2).Trim(); + + if (!string.IsNullOrEmpty(filter)) + { + bool matchesCategory = StringContainsFilter(Category, filter); + bool matchesName = !onlyCategory && StringContainsFilter(Term, filter); + + if (!matchesCategory && !matchesName) + return false; + } + } + + + bool bIsMissing = ShowTerm_termData == null; + bool hasTranslation = !bIsMissing && ShowTerm_termData.Languages.Any(o => !string.IsNullOrEmpty(o)); + + if ((mFlagsViewKeys & (int)eFlagsViewKeys.Untranslated) > 0) return !hasTranslation; + + if (nUses<0) return true; + + + if ((mFlagsViewKeys & (int)eFlagsViewKeys.Missing)>0 && bIsMissing) return true; + if ((mFlagsViewKeys & (int)eFlagsViewKeys.Missing)==0 && bIsMissing) return false; + + if ((mFlagsViewKeys & (int)eFlagsViewKeys.Used)>0 && nUses>0) return true; + if ((mFlagsViewKeys & (int)eFlagsViewKeys.NotUsed)>0 && nUses==0) return true; + + return false; + } + + static bool StringContainsFilter( string Term, string Filter ) + { + if (string.IsNullOrEmpty(Filter) || string.IsNullOrEmpty(Term)) + return true; + if (Term == "-") + return false; + Term = Term.ToLower(); + string[] Filters = Filter.ToLower().Split(";, ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + for (int i = 0, imax = Filters.Length; i < imax; ++i) + if (Term.Contains(Filters[i])) + return true; + + return false; + } + + #endregion + + #region Add/Remove Keys to DB + + void AddTermsToSource() + { + if (!string.IsNullOrEmpty (mKeyToExplore) && !mSelectedKeys.Contains(mKeyToExplore)) + mSelectedKeys.Add (mKeyToExplore); + + for (int i=mSelectedKeys.Count-1; i>=0; --i) + { + string key = mSelectedKeys[i]; + + if (!ShouldShowTerm(key)) + continue; + + AddLocalTerm(key); + mSelectedKeys.RemoveAt(i); + } + SetAllTerms_When_InferredTerms_IsInSource (); + } + + void RemoveTermsFromSource() + { + if (mTestAction==eTest_ActionType.None && !EditorUtility.DisplayDialog("Confirm delete", "Are you sure you want to delete the selected terms", "Yes", "Cancel")) + return; + + if (!string.IsNullOrEmpty (mKeyToExplore) && !mSelectedKeys.Contains(mKeyToExplore)) + mSelectedKeys.Add (mKeyToExplore); + + for (int i=mSelectedKeys.Count-1; i>=0; --i) + { + string key = mSelectedKeys[i]; + + if (!ShouldShowTerm(key)) + continue; + + mLanguageSource.RemoveTerm(key); + RemoveParsedTerm(key); + mSelectedKeys.Remove(key); + } + + mKeyToExplore = string.Empty; + mTermList_MaxWidth = -1; + serializedObject.ApplyModifiedProperties(); + mLanguageSource.Editor_SetDirty(); + + EditorApplication.update += DoParseTermsInCurrentScene; + EditorApplication.update += RepaintScene; + } + + #endregion + + #region Select Objects in Current Scene + + + public static void SelectTerm( string Key, bool SwitchToKeysTab=false ) + { + GUI.FocusControl(null); + mKeyToExplore = Key; + mKeysDesc_AllowEdit = false; + if (SwitchToKeysTab) + mCurrentViewMode = eViewMode.Keys; + } + + + void SelectObjectsUsingKey( string Key ) + { + List SelectedObjs = FindObjectsUsingKey(Key); + + if (SelectedObjs.Count>0) + Selection.objects = SelectedObjs.ToArray(); + else + ShowWarning("The selected Terms are not used in this Scene. Try opening other scenes"); + } + + List FindObjectsUsingKey(string Key) + { + List SelectedObjs = new List(); + + Localize[] Locals = (Localize[])Resources.FindObjectsOfTypeAll(typeof(Localize)); + + if (Locals == null) + return SelectedObjs; + + for (int i = 0, imax = Locals.Length; i < imax; ++i) + { + Localize localize = Locals[i]; + if (localize == null || localize.gameObject == null || !GUITools.ObjectExistInScene(localize.gameObject)) + continue; + + string Term, SecondaryTerm; + localize.GetFinalTerms(out Term, out SecondaryTerm); + + if (Key == Term || Key == SecondaryTerm) + SelectedObjs.Add(localize.gameObject); + } + + return SelectedObjs; + } + + + #endregion + + + [MenuItem("Tools/I2 Localization/Refresh Localizations", false, 16)] + public static void CallLocalizeAll() + { + LocalizationManager.LocalizeAll(true); + HandleUtility.Repaint(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms.cs.meta new file mode 100644 index 00000000..9384003c --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9f0230a94fc864d5bb1f2261de16edce +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms_Description.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms_Description.cs new file mode 100644 index 00000000..a9f8f2ac --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Terms_Description.cs @@ -0,0 +1,785 @@ +//#define UGUI +//#define NGUI + +using System; +using TMPro; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + #region Variables + internal static bool mKeysDesc_AllowEdit; + internal static string GUI_SelectedSpecialization + { + get{ + if (string.IsNullOrEmpty(mGUI_SelectedSpecialization)) + mGUI_SelectedSpecialization = EditorPrefs.GetString ("I2Loc Specialization", "Any"); + return mGUI_SelectedSpecialization; + } + set{ + if (value!=mGUI_SelectedSpecialization) + EditorPrefs.SetString ("I2Loc Specialization", value); + mGUI_SelectedSpecialization = value; + } + } + internal static string mGUI_SelectedSpecialization; + + internal static bool GUI_ShowDisabledLanguagesTranslation = true; + + internal static int mShowPlural = -1; + #endregion + + #region Key Description + + void OnGUI_KeyList_ShowKeyDetails() + { + GUI.backgroundColor = Color.Lerp(Color.blue, Color.white, 0.9f); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1)); + OnGUI_Keys_Languages(mKeyToExplore, null); + + GUILayout.BeginHorizontal(); + if (TestButton(eTest_ActionType.Button_DeleteTerm, "Delete", "Button", GUILayout.ExpandWidth(true))) + { + if (mTestAction != eTest_ActionType.None || EditorUtility.DisplayDialog("Confirm delete", "Are you sure you want to delete term '" + mKeyToExplore + "'", "Yes", "Cancel")) + EditorApplication.update += DeleteCurrentKey; + } + + if (GUILayout.Button("Rename")) + { + mCurrentViewMode = eViewMode.Tools; + mCurrentToolsMode = eToolsMode.Merge; + if (!mSelectedKeys.Contains(mKeyToExplore)) + mSelectedKeys.Add(mKeyToExplore); + } + GUILayout.EndHorizontal(); + GUILayout.EndVertical(); + GUI.backgroundColor = Color.white; + } + + void DeleteTerm( string Term, bool updateStructures = true ) + { + mLanguageSource.RemoveTerm (Term); + RemoveParsedTerm(Term); + mSelectedKeys.Remove(Term); + + if (Term==mKeyToExplore) + mKeyToExplore = string.Empty; + + if (updateStructures) + { + UpdateParsedCategories(); + mTermList_MaxWidth = -1; + serializedObject.ApplyModifiedProperties(); + mLanguageSource.Editor_SetDirty(); + ScheduleUpdateTermsToShowInList(); + } + EditorApplication.update += RepaintScene; + } + + void RepaintScene() + { + EditorApplication.update -= RepaintScene; + Repaint(); + } + + void DeleteCurrentKey() + { + EditorApplication.update -= DeleteCurrentKey; + DeleteTerm (mKeyToExplore); + + mKeyToExplore = ""; + EditorApplication.update += DoParseTermsInCurrentScene; + } + + TermData AddLocalTerm( string Term, bool AutoSelect = true ) + { + var data = AddTerm(Term, AutoSelect); + if (data==null) + return null; + + mTermList_MaxWidth = -1; + serializedObject.ApplyModifiedProperties(); + mLanguageSource.Editor_SetDirty(); + return data; + } + + static TermData AddTerm(string Term, bool AutoSelect = true, eTermType termType = eTermType.Text) + { + if (Term == "-" || string.IsNullOrEmpty(Term)) + return null; + + Term = I2Utils.GetValidTermName(Term, true); + + TermData data = mLanguageSource.AddTerm(Term, termType); + GetParsedTerm(Term); + string sCategory = LanguageSourceData.GetCategoryFromFullTerm(Term); + mParsedCategories.Add(sCategory); + + if (AutoSelect) + { + if (!mSelectedKeys.Contains(Term)) + mSelectedKeys.Add(Term); + + if (!mSelectedCategories.Contains(sCategory)) + mSelectedCategories.Add(sCategory); + } + ScheduleUpdateTermsToShowInList(); + mLanguageSource.Editor_SetDirty(); + return data; + } + + // this method shows the key description and the localization to each language + public static TermData OnGUI_Keys_Languages( string Key, Localize localizeCmp, bool IsPrimaryKey=true ) + { + if (Key==null) + Key = string.Empty; + + TermData termdata = null; + + LanguageSourceData source = mLanguageSource; + if (localizeCmp != null && localizeCmp.Source != null) + source = localizeCmp.Source.SourceData; + + if (source==null) + source = LocalizationManager.GetSourceContaining(Key, false); + + if (source==null) + { + if (localizeCmp == null) + source = LocalizationManager.Sources[0]; + else + source = LocalizationManager.GetSourceContaining(IsPrimaryKey ? localizeCmp.SecondaryTerm : localizeCmp.Term); + } + + + if (string.IsNullOrEmpty(Key)) + { + EditorGUILayout.HelpBox( "Select a Term to Localize", MessageType.Info ); + return null; + } + + termdata = source.GetTermData(Key); + if (termdata==null && localizeCmp!=null) + { + var realSource = LocalizationManager.GetSourceContaining(Key, false); + if (realSource != null) + { + termdata = realSource.GetTermData(Key); + source = realSource; + } + } + if (termdata==null) + { + if (Key == "-") + return null; + EditorGUILayout.HelpBox( string.Format("Key '{0}' is not Localized or it is in a different Language Source", Key), MessageType.Error ); + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Add Term to Source")) + { + var termType = eTermType.Text; + if (localizeCmp!=null && localizeCmp.mLocalizeTarget != null) + { + termType = IsPrimaryKey ? localizeCmp.mLocalizeTarget.GetPrimaryTermType(localizeCmp) + : localizeCmp.mLocalizeTarget.GetSecondaryTermType(localizeCmp); + } + + AddTerm(Key, true, termType); + } + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + return null; + } + + //--[ Type ]---------------------------------- + if (localizeCmp==null) + { + GUILayout.BeginHorizontal(); + GUILayout.Label ("Type:", GUILayout.ExpandWidth(false)); + eTermType NewType = (eTermType)EditorGUILayout.EnumPopup(termdata.TermType, GUILayout.ExpandWidth(true)); + if (termdata.TermType != NewType) + termdata.TermType = NewType; + GUILayout.EndHorizontal(); + } + + + //--[ Description ]--------------------------- + + mKeysDesc_AllowEdit = GUILayout.Toggle(mKeysDesc_AllowEdit, "Description", EditorStyles.foldout, GUILayout.ExpandWidth(true)); + + if (mKeysDesc_AllowEdit) + { + string NewDesc = EditorGUILayout.TextArea( termdata.Description, Style_WrapTextField ); + if (NewDesc != termdata.Description) + { + termdata.Description = NewDesc; + source.Editor_SetDirty(); + } + } + else + EditorGUILayout.HelpBox( string.IsNullOrEmpty(termdata.Description) ? "No description" : termdata.Description, MessageType.Info ); + + OnGUI_Keys_Language_SpecializationsBar (termdata, source); + + OnGUI_Keys_Languages(Key, ref termdata, localizeCmp, IsPrimaryKey, source); + return termdata; + } + + static void OnGUI_Keys_Languages( string Key, ref TermData termdata, Localize localizeCmp, bool IsPrimaryKey, LanguageSourceData source ) + { + //--[ Languages ]--------------------------- + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1)); + + OnGUI_Keys_LanguageTranslations(Key, localizeCmp, IsPrimaryKey, ref termdata, source); + + if (termdata.TermType == eTermType.Text) + { + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (TestButton(eTest_ActionType.Button_Term_TranslateAll, "Translate All", "Button", GUILayout.Width(85))) + { + var termData = termdata; + GUITools.DelayedCall(() => TranslateLanguage( Key, termData, localizeCmp, source)); + GUI.FocusControl(string.Empty); + } + GUILayout.EndHorizontal(); + OnGUI_TranslatingMessage(); + } + GUILayout.EndVertical(); + } + + static void TranslateLanguage( string Key, TermData termdata, Localize localizeCmp, LanguageSourceData source) + { + ClearErrors(); + string mainText = localizeCmp == null ? LanguageSourceData.GetKeyFromFullTerm(Key) : localizeCmp.GetMainTargetsText(); + + for (int i = 0; i < source.mLanguages.Count; ++i) + if (source.mLanguages[i].IsEnabled() && string.IsNullOrEmpty(termdata.Languages[i])) + { + var langIdx = i; + var term = termdata; + var i2source = source; + Translate(mainText, ref termdata, source.mLanguages[i].Code, + (translation, error) => + { + if (error != null) + ShowError(error); + else + if (translation != null) + { + term.Languages[langIdx] = translation; //SetTranslation(langIdx, translation); + i2source.Editor_SetDirty(); + } + }, null); + } + } + + static void OnGUI_TranslatingMessage() + { + if (GoogleTranslation.IsTranslating()) + { + // Connection Status Bar + int time = (int)(Time.realtimeSinceStartup % 2 * 2.5); + string Loading = "Translating" + ".....".Substring(0, time); + GUI.color = Color.gray; + GUILayout.BeginHorizontal(LocalizeInspector.GUIStyle_OldTextArea); + GUILayout.Label(Loading, EditorStyles.miniLabel); + GUI.color = Color.white; + if (GUILayout.Button("Cancel", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + { + GoogleTranslation.CancelCurrentGoogleTranslations(); + } + GUILayout.EndHorizontal(); + HandleUtility.Repaint (); + } + } + + static void OnGUI_Keys_Language_SpecializationsBar(TermData termData, LanguageSourceData source) + { + var activeSpecializations = termData.GetAllSpecializations(); + + GUILayout.BeginHorizontal(); + + var TabStyle = new GUIStyle(GUI.skin.FindStyle("dragtab")); + TabStyle.fixedHeight = 0; + + //var ss = GUI.skin.FindStyle("TL tab left"); + var TabOpenStyle = new GUIStyle(GUI.skin.FindStyle("minibuttonmid")); + TabOpenStyle.margin.right = -1; + var TabCloseStyle = new GUIStyle(EditorStyles.label); + //var TabCloseStyle = new GUIStyle(GUI.skin.FindStyle("TL tab right")); + TabCloseStyle.margin.left = -1; + TabCloseStyle.padding.left=4; + + //-- Specialization Tabs ----- + + var prevSpecialization = "Any"; + foreach (var specialization in SpecializationManager.Singleton.mSpecializations) + { + if (!activeSpecializations.Contains(specialization) && specialization != GUI_SelectedSpecialization) + continue; + + bool isActive = specialization == GUI_SelectedSpecialization; + var labelContent = new GUIContent(specialization, "Specialization of the main translation (i.e. variants that show only on specific platforms or devices)\nThis allows using 'tap' instead of 'click' for touch devices."); + + if (isActive && activeSpecializations.Count>1) + { + GUILayout.BeginHorizontal(TabOpenStyle); + GUILayout.Toggle(isActive, labelContent, TabStyle, GUILayout.Height(20), GUILayout.ExpandWidth(false)); + //GUILayout.Label(labelContent, TabOpenStyle); + if (specialization != "Any" && GUILayout.Button("x", TabCloseStyle, GUILayout.Width(15))) + { + termData.RemoveSpecialization(specialization); + GUI_SelectedSpecialization = prevSpecialization; + GUI.FocusControl(null); + } + GUILayout.EndHorizontal(); + } + else + if (GUILayout.Toggle(isActive, labelContent, TabStyle, GUILayout.Height(25), GUILayout.ExpandWidth(false)) && !isActive) + { + GUI_SelectedSpecialization = specialization; + GUI.FocusControl(null); + } + } + + + //-- Add new Specialization ----- + int newIndex = EditorGUILayout.Popup(-1, SpecializationManager.Singleton.mSpecializations, "DropDown", GUILayout.Width(20)); + if (newIndex>=0) + { + string newSpecialization = SpecializationManager.Singleton.mSpecializations[newIndex]; + if (!activeSpecializations.Contains(newSpecialization)) + { + for (int iLang = 0; iLang < source.mLanguages.Count; ++iLang) + { + string Translation = termData.GetTranslation(iLang, GUI_SelectedSpecialization, editMode: true); + termData.SetTranslation(iLang, Translation, GUI_SelectedSpecialization); + } + GUI_SelectedSpecialization = newSpecialization; + } + } + + GUILayout.FlexibleSpace(); + + + GUI_ShowDisabledLanguagesTranslation = GUILayout.Toggle(GUI_ShowDisabledLanguagesTranslation, new GUIContent("L", "Show Disabled Languages"), "Button", GUILayout.ExpandWidth(false)); + GUILayout.EndHorizontal(); + GUILayout.Space(-3); + } + + static void OnGUI_Keys_LanguageTranslations (string Key, Localize localizeCmp, bool IsPrimaryKey, ref TermData termdata, LanguageSourceData source) + { + bool IsSelect = UnityEngine.Event.current.type==EventType.MouseUp; + for (int i=0; i< source.mLanguages.Count; ++ i) + { + bool forcePreview = false; + bool isEnabledLanguage = source.mLanguages[i].IsEnabled(); + + if (!isEnabledLanguage) + { + if (!GUI_ShowDisabledLanguagesTranslation) + continue; + GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.35f); + } + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(source.mLanguages[i].Name, EditorStyles.label, GUILayout.Width(100))) + forcePreview = true; + + + string Translation = termdata.GetTranslation(i, GUI_SelectedSpecialization, editMode:true); + if (Translation == null) Translation = string.Empty; + +// if (termdata.Languages[i] != termdata.Languages_Touch[i] && !string.IsNullOrEmpty(termdata.Languages[i]) && !string.IsNullOrEmpty(termdata.Languages_Touch[i])) +// GUI.contentColor = GUITools.LightYellow; + + if (termdata.TermType == eTermType.Text || termdata.TermType==eTermType.Child) + { + EditorGUI.BeginChangeCheck (); + string CtrName = "TranslatedText"+i; + GUI.SetNextControlName(CtrName); + + EditPluralTranslations (ref Translation, i, source.mLanguages[i].Code); + //Translation = EditorGUILayout.TextArea(Translation, Style_WrapTextField, GUILayout.Width(Screen.width - 260 - (autoTranslated ? 20 : 0))); + if (EditorGUI.EndChangeCheck ()) + { + termdata.SetTranslation(i, Translation, GUI_SelectedSpecialization); + source.Editor_SetDirty(); + forcePreview = true; + } + + if (localizeCmp!=null && + (forcePreview || /*GUI.changed || */GUI.GetNameOfFocusedControl()==CtrName && IsSelect)) + { + if (IsPrimaryKey && string.IsNullOrEmpty(localizeCmp.Term)) + { + localizeCmp.mTerm = Key; + } + + if (!IsPrimaryKey && string.IsNullOrEmpty(localizeCmp.SecondaryTerm)) + { + localizeCmp.mTermSecondary = Key; + } + + string PreviousLanguage = LocalizationManager.CurrentLanguage; + LocalizationManager.PreviewLanguage(source.mLanguages[i].Name); + if (forcePreview || IsSelect) + LocalizationManager.LocalizeAll(); + else + localizeCmp.OnLocalize(true); + LocalizationManager.PreviewLanguage(PreviousLanguage); + EditorUtility.SetDirty(localizeCmp); + } + GUI.contentColor = Color.white; + + //if (autoTranslated) + //{ + // if (GUILayout.Button(new GUIContent("\u2713"/*"A"*/,"Translated by Google Translator\nClick the button to approve the translation"), EditorStyles.toolbarButton, GUILayout.Width(autoTranslated ? 20 : 0))) + // { + // termdata.Flags[i] &= (byte)(byte.MaxValue ^ (byte)(GUI_SelectedSpecialization==0 ? TranslationFlag.AutoTranslated_Normal : TranslationFlag.AutoTranslated_Touch)); + // } + //} + + if (termdata.TermType == eTermType.Text) + { + if (TestButtonArg(eTest_ActionType.Button_Term_Translate, i, new GUIContent("T", "Translate"), EditorStyles.toolbarButton, GUILayout.Width(20))) + { + var termData = termdata; + var indx = i; + var key = Key; + GUITools.DelayedCall(()=>TranslateTerm(key, termData, source, indx)); + GUI.FocusControl(string.Empty); + } + } + } + else + { + string MultiSpriteName = string.Empty; + + if (termdata.TermType==eTermType.Sprite && Translation.EndsWith("]", StringComparison.Ordinal)) // Handle sprites of type (Multiple): "SpritePath[SpriteName]" + { + int idx = Translation.LastIndexOf("[", StringComparison.Ordinal); + int len = Translation.Length-idx-2; + MultiSpriteName = Translation.Substring(idx+1, len); + Translation = Translation.Substring(0, idx); + } + + Object Obj = null; + + // Try getting the asset from the References section + if (localizeCmp!=null) + Obj = localizeCmp.FindTranslatedObject(Translation); + if (Obj==null && source != null) + Obj = source.FindAsset(Translation); + + // If it wasn't in the references, Load it from Resources + if (Obj==null && localizeCmp==null) + Obj = ResourceManager.pInstance.LoadFromResources(Translation); + + Type ObjType = typeof(Object); + switch (termdata.TermType) + { + case eTermType.Font : ObjType = typeof(Font); break; + case eTermType.Texture : ObjType = typeof(Texture); break; + case eTermType.AudioClip : ObjType = typeof(AudioClip); break; + case eTermType.GameObject : ObjType = typeof(GameObject); break; + case eTermType.Sprite : ObjType = typeof(Sprite); break; + case eTermType.Material : ObjType = typeof(Material); break; + case eTermType.Mesh : ObjType = typeof(Mesh); break; +#if NGUI + case eTermType.UIAtlas : ObjType = typeof(UIAtlas); break; + case eTermType.UIFont : ObjType = typeof(UIFont); break; +#endif +#if TK2D + case eTermType.TK2dFont : ObjType = typeof(tk2dFont); break; + case eTermType.TK2dCollection : ObjType = typeof(tk2dSpriteCollection); break; +#endif + +#if TextMeshPro + case eTermType.TextMeshPFont : ObjType = typeof(TMP_FontAsset); break; +#endif + +#if SVG + case eTermType.SVGAsset : ObjType = typeof(SVGImporter.SVGAsset); break; +#endif + + case eTermType.Object : ObjType = typeof(Object); break; + } + + if (Obj!=null && !string.IsNullOrEmpty(MultiSpriteName)) + { + string sPath = AssetDatabase.GetAssetPath(Obj); + Object[] objs = AssetDatabase.LoadAllAssetRepresentationsAtPath(sPath); + Obj = null; + for (int j=0, jmax=objs.Length; j + { + term.SetTranslation(langIdx, translation, specialization); + i2source.Editor_SetDirty(); + }, specialization); + } + + static void EditPluralTranslations( ref string translation, int langIdx, string langCode ) + { + bool hasParameters = false; + int paramStart = translation.IndexOf("{["); + hasParameters = paramStart >= 0 && translation.IndexOf ("]}", paramStart) > 0; + + if (mShowPlural == langIdx && string.IsNullOrEmpty (translation)) + mShowPlural = -1; + + bool allowPlural = hasParameters || translation.Contains("[i2p_"); + + if (allowPlural) + { + if (GUILayout.Toggle (mShowPlural == langIdx, "", EditorStyles.foldout, GUILayout.Width (13))) + mShowPlural = langIdx; + else if (mShowPlural == langIdx) + mShowPlural = -1; + + GUILayout.Space (-5); + } + + string finalTranslation = ""; + bool unfolded = mShowPlural == langIdx; + bool isPlural = allowPlural && translation.Contains("[i2p_"); + if (unfolded) + GUILayout.BeginVertical ("Box"); + + ShowPluralTranslation("Plural", langCode, translation, ref finalTranslation, true, unfolded, unfolded|isPlural ); + ShowPluralTranslation("Zero", langCode, translation, ref finalTranslation, unfolded, true, true ); + ShowPluralTranslation("One", langCode, translation, ref finalTranslation, unfolded, true, true ); + ShowPluralTranslation("Two", langCode, translation, ref finalTranslation, unfolded, true, true ); + ShowPluralTranslation("Few", langCode, translation, ref finalTranslation, unfolded, true, true ); + ShowPluralTranslation("Many", langCode, translation, ref finalTranslation, unfolded, true, true ); + + if (unfolded) + GUILayout.EndVertical (); + + translation = finalTranslation; + } + + static void ShowPluralTranslation(string pluralType, string langCode, string translation, ref string finalTranslation, bool show, bool allowDelete, bool showTag ) + { + string tag = "[i2p_" + pluralType + "]"; + int idx0 = translation.IndexOf (tag, StringComparison.OrdinalIgnoreCase); + bool hasTranslation = idx0 >= 0 || pluralType=="Plural"; + if (idx0 < 0) idx0 = 0; + else idx0 += tag.Length; + + int idx1 = translation.IndexOf ("[i2p_", idx0, StringComparison.OrdinalIgnoreCase); + if (idx1 < 0) idx1 = translation.Length; + + var pluralTranslation = translation.Substring(idx0, idx1-idx0); + var newTrans = pluralTranslation; + + bool allowPluralForm = GoogleLanguages.LanguageHasPluralType (langCode, pluralType); + + if (hasTranslation && !allowPluralForm) { + newTrans = ""; + GUI.changed = true; + } + + if (show && allowPluralForm) + { + if (!hasTranslation) + GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.35f); + + GUILayout.BeginHorizontal (); + if (showTag) + GUILayout.Label (pluralType, EditorStyles.miniLabel, GUILayout.Width(35)); + newTrans = EditorGUILayout.TextArea (pluralTranslation, Style_WrapTextField); + + if (allowDelete && GUILayout.Button("X", EditorStyles.toolbarButton, GUILayout.Width(15))) + { + newTrans = string.Empty; + GUI.changed = true; + GUIUtility.keyboardControl = 0; + } + + GUILayout.EndHorizontal (); + if (!hasTranslation) + GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 1); + } + + if (!string.IsNullOrEmpty (newTrans)) + { + if (hasTranslation || newTrans != pluralTranslation) + { + if (pluralType != "Plural") + finalTranslation += tag; + finalTranslation += newTrans; + } + } + } + + /*static public int DrawTranslationTabs( int Index ) + { + GUIStyle MyStyle = new GUIStyle(GUI.skin.FindStyle("dragtab")); + MyStyle.fixedHeight=0; + + GUILayout.BeginHorizontal(); + for (int i=0; i mSelectedScenes = new List(); + + public enum eToolsMode { Parse, Categorize, Merge, NoLocalized, Script, CharSet } + public eToolsMode mCurrentToolsMode = eToolsMode.Parse; + + #endregion + + #region GUI + + void OnGUI_Tools( bool reset ) + { + GUILayout.Space(10); + eToolsMode OldMode = mCurrentToolsMode; + mCurrentToolsMode = (eToolsMode)GUITools.DrawShadowedTabs ((int)mCurrentToolsMode, new[]{"Parse", "Categorize", "Merge", "No Localized", "Script", "CharSet"}, 30); + if (mCurrentToolsMode != OldMode || reset) + { + ClearErrors(); + if (mCurrentToolsMode == eToolsMode.Script) + SelectTermsFromScriptLocalization(); + OnGUI_ScenesList_SelectAllScenes(true); + } + + switch (mCurrentToolsMode) + { + case eToolsMode.Parse : OnGUI_Tools_ParseTerms(); break; + case eToolsMode.Categorize : OnGUI_Tools_Categorize(); break; + case eToolsMode.Merge : OnGUI_Tools_MergeTerms(); break; + case eToolsMode.NoLocalized : OnGUI_Tools_NoLocalized(); break; + case eToolsMode.Script : OnGUI_Tools_Script(); break; + case eToolsMode.CharSet : OnGUI_Tools_CharSet(); break; + } + OnGUI_ShowMsg(); + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools.cs.meta new file mode 100644 index 00000000..f712a581 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3fa4621ebd4134e1989b73eb3f7b864f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Categorize.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Categorize.cs new file mode 100644 index 00000000..df6949ba --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Categorize.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + #region Variables + + Vector2 mScrollPos_CategorizedKeys = Vector2.zero; + string mNewCategory = string.Empty; + + #endregion + + #region GUI + + void OnGUI_Tools_Categorize() + { + OnGUI_ScenesList(true); + + GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1)); + GUI.backgroundColor = Color.white; + GUILayout.Space (5); + + EditorGUILayout.HelpBox("This tool changes the category of the selected Terms and updates the highlighted scenes", MessageType.Info); + + GUILayout.Space (5); + GUITools.CloseHeader(); + + OnGUI_Tools_Categorize_Terms(); + OnGUI_NewOrExistingCategory(); + } + + void OnGUI_Tools_Categorize_Terms() + { + GUILayout.Label("Change Category of the following Terms:", EditorStyles.toolbarButton, GUILayout.ExpandWidth(true)); + + GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f); + mScrollPos_CategorizedKeys = GUILayout.BeginScrollView( mScrollPos_CategorizedKeys, LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height ( 100)); + GUI.backgroundColor = Color.white; + + if (mSelectedKeys.Count==0) + { + GUILayout.FlexibleSpace(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + //GUILayout.BeginVertical(); + EditorGUILayout.HelpBox("No Terms has been selected", MessageType.Warning); + /*if (GUILayout.Button("Select Terms", EditorStyles.toolbarButton, GUILayout.ExpandWidth(true))) + mCurrentViewMode = eViewMode.Keys;*/ + //GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUILayout.FlexibleSpace(); + } + else + { + bool DoubleColumn = mSelectedKeys.Count>5; + int HalfCount = Mathf.CeilToInt(mSelectedKeys.Count/2.0f); + + for (int i=0, imax=mSelectedKeys.Count; i=HalfCount) break; + + GUILayout.BeginHorizontal(); + OnGUI_CategorizedTerm(mSelectedKeys[i]); + + if (DoubleColumn && i+HalfCount Categories = LocalizationManager.GetCategories(); + + for (int i=0, imax=Categories.Count; i TermReplacements; + + void AssignCategoryToSelectedTerms() + { + mIsParsing = true; + + EditorApplication.update -= AssignCategoryToSelectedTerms; + + mNewCategory = mNewCategory.Trim (LanguageSourceData.CategorySeparators); + + if (mNewCategory==LanguageSourceData.EmptyCategory) + mNewCategory = string.Empty; + + TermReplacements = new Dictionary(StringComparer.Ordinal); + for (int i=mSelectedKeys.Count-1; i>=0; --i) + { + string sKey, sCategory; + string OldTerm = mSelectedKeys[i]; + + LanguageSourceData.DeserializeFullTerm( OldTerm, out sKey, out sCategory ); + if (!string.IsNullOrEmpty(mNewCategory)) + sKey = string.Concat(mNewCategory, "/", sKey); + + if (OldTerm == sKey) + continue; + + TermReplacements[ OldTerm ] = sKey; + if (!mLanguageSource.ContainsTerm(sKey)) + { + TermData termData = mLanguageSource.GetTermData( OldTerm ); + if (termData != null) + termData.Term = sKey; + else + TermReplacements.Remove (OldTerm); + mLanguageSource.Editor_SetDirty(); + } + } + if (TermReplacements.Count<=0) + { + ShowError ("Unable to assign category: Terms were not found in the selected LanguageSource"); + } + else + { + mLanguageSource.UpdateDictionary(true); + ExecuteActionOnSelectedScenes( ReplaceTermsInCurrentScene ); + ParseTerms(true, false, true); + + if (string.IsNullOrEmpty(mNewCategory)) + mNewCategory = LanguageSourceData.EmptyCategory; + if (!mSelectedCategories.Contains(mNewCategory)) + mSelectedCategories.Add (mNewCategory); + //RemoveUnusedCategoriesFromSelected(); + ScheduleUpdateTermsToShowInList(); + } + TermReplacements = null; + mIsParsing = false; + } + + public static void ReplaceTermsInCurrentScene() + { + Localize[] Locals = (Localize[])Resources.FindObjectsOfTypeAll(typeof(Localize)); + + if (Locals==null) + return; + + bool changed = false; + for (int i=0, imax=Locals.Length; i mCharSetTool_Languages = new List(); + string mCharSet = string.Empty; + bool mCharSetTool_CaseSensitive; + + #endregion + + #region GUI Generate Script + + void OnGUI_Tools_CharSet() + { + bool computeSet = false; + + // remove missing languages + for (int i=mCharSetTool_Languages.Count-1; i>=0; --i) + { + if (mLanguageSource.GetLanguageIndex(mCharSetTool_Languages[i])<0) + mCharSetTool_Languages.RemoveAt(i); + } + + GUILayout.BeginHorizontal (EditorStyles.toolbar); + GUILayout.Label ("Languages:", EditorStyles.miniLabel, GUILayout.ExpandWidth(true)); + if (GUILayout.Button ("All", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + { + mCharSetTool_Languages.Clear (); + mCharSetTool_Languages.AddRange (mLanguageSource.mLanguages.Select(x=>x.Name)); + computeSet = true; + } + if (GUILayout.Button ("None", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + { + mCharSetTool_Languages.Clear (); + computeSet = true; + } + if (GUILayout.Button ("Invert", EditorStyles.toolbarButton, GUILayout.ExpandWidth(false))) + { + var current = mCharSetTool_Languages.ToList (); + mCharSetTool_Languages.Clear (); + mCharSetTool_Languages.AddRange (mLanguageSource.mLanguages.Select(x=>x.Name).Where(j=>!current.Contains(j))); + computeSet = true; + } + + + GUILayout.EndHorizontal (); + + //--[ Language List ]-------------------------- + + GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f); + mScrollPos_Languages = GUILayout.BeginScrollView( mScrollPos_Languages, LocalizeInspector.GUIStyle_OldTextArea, GUILayout.MinHeight (100), GUILayout.MaxHeight(Screen.height), GUILayout.ExpandHeight(false)); + GUI.backgroundColor = Color.white; + + for (int i=0, imax=mLanguageSource.mLanguages.Count; i (); + var LanIndexes = new List (); + for (int i=0; i c).ToArray() ); + mCharSet = Encoding.UTF8.GetString(bytes); + } + + void AppendToCharSet( HashSet sb, string text, bool isRTL ) + { + if (string.IsNullOrEmpty (text)) + return; + + text = RemoveTagsPrefix(text, "[i2p_"); + text = RemoveTagsPrefix(text, "[i2s_"); + + if (isRTL) + text = RTLFixer.Fix( text ); + + foreach (char c in text) + { + if (!mCharSetTool_CaseSensitive) + { + sb.Add(char.ToLowerInvariant(c)); + sb.Add(char.ToUpperInvariant(c)); + } + else + sb.Add(c); + } + } + + // Given "[i2p_" it removes all tags that start with that (e.g. [i2p_Zero] [i2p_One], etc) + string RemoveTagsPrefix(string text, string tagPrefix) + { + int idx = 0; + while (idx < text.Length) + { + idx = text.IndexOf(tagPrefix); + if (idx < 0) + break; + + int idx2 = text.IndexOf(']', idx); + if (idx2 < 0) + break; + + text = text.Remove(idx, idx2 - idx+1); + } + return text; + + } + + + + #endregion + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_CharSet.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_CharSet.cs.meta new file mode 100644 index 00000000..e54fcfa8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_CharSet.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 104713279df05ac4b96f5a76ab621c8a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_MergeTerms.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_MergeTerms.cs new file mode 100644 index 00000000..05d4f857 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_MergeTerms.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + #region Variables + + #endregion + + #region GUI + + void OnGUI_Tools_MergeTerms() + { + OnGUI_ScenesList(true); + + GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1)); + GUI.backgroundColor = Color.white; + GUILayout.Space (5); + + EditorGUILayout.HelpBox("This option replace all occurrences of this key in the selected scenes", MessageType.Info); + + GUILayout.Space (5); + GUITools.CloseHeader(); + + OnGUI_Tools_Categorize_Terms(); + OnGUI_NewOrExistingTerm(); + } + + void OnGUI_NewOrExistingTerm() + { + if (mKeyToExplore==null) + mKeyToExplore = string.Empty; + + GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1)); + GUI.backgroundColor = Color.white; + GUILayout.Space(5); + GUILayout.Label("Replace By:"); + GUILayout.EndVertical(); + + //--[ Create Term ]------------------------ + GUILayout.BeginHorizontal(); + mKeyToExplore = GUILayout.TextField(mKeyToExplore, EditorStyles.toolbarTextField, GUILayout.ExpandWidth(true)); + if (GUILayout.Button("Create", "toolbarbutton", GUILayout.Width(60))) + { + LanguageSourceData.ValidateFullTerm( ref mKeyToExplore ); + EditorApplication.update += ReplaceSelectedTerms; + } + GUILayout.EndHorizontal(); + + //--[ Existing Term ]------------------------ + int Index = 0; + List Terms = mLanguageSource.GetTermsList(); + + for (int i=0, imax=Terms.Count; i(StringComparer.Ordinal); + for (int i=mSelectedKeys.Count-1; i>=0; --i) + { + string OldTerm = mSelectedKeys[i]; + if (OldTerm == sNewKey) + continue; + + TermReplacements[ OldTerm ] = mKeyToExplore; + DeleteTerm(OldTerm); + } + ExecuteActionOnSelectedScenes( ReplaceTermsInCurrentScene ); + DoParseTermsInCurrentScene(); + + //--[ Update Selected Categories ]------------- + string mNewCategory = LanguageSourceData.GetCategoryFromFullTerm(sNewKey); + if (mNewCategory == string.Empty) + mNewCategory = LanguageSourceData.EmptyCategory; + if (!mSelectedCategories.Contains(mNewCategory)) + mSelectedCategories.Add (mNewCategory); + //RemoveUnusedCategoriesFromSelected(); + ScheduleUpdateTermsToShowInList(); + TermReplacements = null; + mIsParsing = false; + } + + void RemoveUnusedCategoriesFromSelected() + { + List Categories = LocalizationManager.GetCategories(); + for (int i=mSelectedCategories.Count-1; i>=0; --i) + if (!Categories.Contains( mSelectedCategories[i] )) + mSelectedCategories.RemoveAt(i); + + if (mSelectedCategories.Count == 0) + mSelectedCategories.AddRange(Categories); + + ScheduleUpdateTermsToShowInList(); + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_MergeTerms.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_MergeTerms.cs.meta new file mode 100644 index 00000000..52785835 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_MergeTerms.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d59fa53e0df75a34693c4673bba5ed94 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_NoLocalized.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_NoLocalized.cs new file mode 100644 index 00000000..e4a11e53 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_NoLocalized.cs @@ -0,0 +1,163 @@ +using System.Collections.Generic; +using TMPro; +using UnityEditor; +using UnityEngine; +using UnityEngine.UI; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + #region Variables + static string _Tools_NoLocalized_Include, + _Tools_NoLocalized_Exclude; + const string _Help_Tool_NoLocalized = "This selects all labels in the current scene that don't have a Localized component.\n\nWhen Include or Exclude are set, labels will be filtered based on those settings.Separate by (,) if multiple strings are used.\n(e.g. Include:\"example,tutorial\")"; + #endregion + + #region GUI Find NoLocalized Terms + + void OnGUI_Tools_NoLocalized() + { + //OnGUI_ScenesList(); + + if (_Tools_NoLocalized_Include==null) + { + _Tools_NoLocalized_Include = EditorPrefs.GetString ("_Tools_NoLocalized_Include", string.Empty); + _Tools_NoLocalized_Exclude = EditorPrefs.GetString ("_Tools_NoLocalized_Exclude", string.Empty); + } + + GUILayout.Space (5); + + GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1)); + GUI.backgroundColor = Color.white; + + EditorGUILayout.HelpBox(_Help_Tool_NoLocalized, MessageType.Info); + + GUILayout.Space(5); + GUILayout.BeginHorizontal(); + GUILayout.Label ("Include:", GUILayout.Width(60)); + _Tools_NoLocalized_Include = EditorGUILayout.TextArea(_Tools_NoLocalized_Include, GUILayout.ExpandWidth(true)); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Label ("Exclude:", GUILayout.Width(60)); + _Tools_NoLocalized_Exclude = EditorGUILayout.TextArea(_Tools_NoLocalized_Exclude, GUILayout.ExpandWidth(true)); + GUILayout.EndHorizontal(); + + GUILayout.Space (5); + + GUILayout.BeginHorizontal (); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Select No Localized Labels")) + EditorApplication.update += SelectNoLocalizedLabels; + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUILayout.EndVertical(); + } + + #endregion + + + #region Find No Localized + + void SelectNoLocalizedLabels() + { + EditorPrefs.SetString ("_Tools_NoLocalized_Include", _Tools_NoLocalized_Include); + EditorPrefs.SetString ("_Tools_NoLocalized_Exclude", _Tools_NoLocalized_Exclude); + + EditorApplication.update -= SelectNoLocalizedLabels; + + List labels = new List(); + + TextMesh[] textMeshes = (TextMesh[])Resources.FindObjectsOfTypeAll(typeof(TextMesh)); + if (textMeshes!=null && textMeshes.Length>0) + labels.AddRange(textMeshes); + +#if NGUI + UILabel[] uiLabels = (UILabel[])Resources.FindObjectsOfTypeAll(typeof(UILabel)); + if (uiLabels!=null && uiLabels.Length>0) + labels.AddRange(uiLabels); +#endif + Text[] uiTexts = (Text[])Resources.FindObjectsOfTypeAll(typeof(Text)); + if (uiTexts!=null && uiTexts.Length>0) + labels.AddRange(uiTexts); +#if TextMeshPro + TextMeshPro[] tmpText = (TextMeshPro[])Resources.FindObjectsOfTypeAll(typeof(TextMeshPro)); + if (tmpText!=null && tmpText.Length>0) + labels.AddRange(tmpText); + + TextMeshProUGUI[] uiTextsUGUI = (TextMeshProUGUI[])Resources.FindObjectsOfTypeAll(typeof(TextMeshProUGUI)); + if (uiTextsUGUI!=null && uiTextsUGUI.Length>0) + labels.AddRange(uiTextsUGUI); +#endif +#if TK2D + tk2dTextMesh[] tk2dTM = (tk2dTextMesh[])Resources.FindObjectsOfTypeAll(typeof(tk2dTextMesh)); + if (tk2dTM!=null && tk2dTM.Length>0) + labels.AddRange(tk2dTM); +#endif + + if (labels.Count==0) + return; + + string[] Includes = null; + string[] Excludes = null; + + if (!string.IsNullOrEmpty (_Tools_NoLocalized_Include)) + Includes = _Tools_NoLocalized_Include.ToLower().Split(',', ';'); + + if (!string.IsNullOrEmpty (_Tools_NoLocalized_Exclude)) + Excludes = _Tools_NoLocalized_Exclude.ToLower().Split(',', ';'); + + List Objs = new List(); + + for (int i=0, imax=labels.Count; i()!=null) + continue; + + if (ShouldFilter(label.name.ToLower(), Includes, Excludes)) + continue; + + Objs.Add( labels[i].gameObject ); + } + + if (Objs.Count>0) + Selection.objects = Objs.ToArray(); + else + ShowWarning("All labels in this scene have a Localize component assigned"); + } + + bool ShouldFilter( string Text, string[] Includes, string[] Excludes ) + { + if (Includes!=null && Includes.Length>0) + { + bool hasAny = false; + for (int j=0; j0) + { + for (int j=0; j mParsedTerms = new SortedDictionary(StringComparer.Ordinal); // All Terms resulted from parsing the scenes and collecting the Localize.Term and how many times the terms are used + public static HashSet mParsedCategories = new HashSet(StringComparer.Ordinal); + + public static List mShowableTerms = new List (); // this contains the terms from mParsedTerms that should be shown in the list (filtered by search string, usage, etc) + public static bool mParseTermsIn_Scenes = true; + public static bool mParseTermsIn_Scripts = true; + + #endregion + + #region GUI Parse Keys + + void OnGUI_Tools_ParseTerms() + { + OnGUI_ScenesList(); + + GUI.backgroundColor = Color.Lerp (Color.gray, Color.white, 0.2f); + GUILayout.BeginVertical(LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height(1)); + GUI.backgroundColor = Color.white; + + GUILayout.Space (5); + + EditorGUILayout.HelpBox("This tool searches all Terms used in the selected scenes and updates the usage counter in the Terms Tab", MessageType.Info); + + GUILayout.Space (5); + + GUILayout.BeginHorizontal (); + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal ("Box"); + mParseTermsIn_Scenes = GUILayout.Toggle(mParseTermsIn_Scenes, new GUIContent("Parse SCENES", "Opens the selected scenes and finds all the used terms")); + GUILayout.FlexibleSpace(); + mParseTermsIn_Scripts = GUILayout.Toggle(mParseTermsIn_Scripts, new GUIContent("Parse SCRIPTS", "Searches all .cs files and counts all terms like: ScriptLocalization.Get(\"xxx\")")); + GUILayout.EndHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal (); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Parse Localized Terms")) + { + EditorApplication.update += ParseTermsInSelectedScenes; + if (mParseTermsIn_Scripts) + EditorApplication.update += ParseTermsInScripts; + } + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUILayout.EndVertical(); + } + + #endregion + + #region Parsed Terms Handlers + + public static ParsedTerm GetParsedTerm( string Term ) + { + ParsedTerm data; + if (!mParsedTerms.TryGetValue(Term, out data)) + data = AddParsedTerm(Term, null, null, 0); + return data; + } + + static ParsedTerm AddParsedTerm( string FullTerm, string TermKey, string Category, int Usage ) + { + if (TermKey==null) + LanguageSourceData.DeserializeFullTerm(FullTerm, out TermKey, out Category); + + var data = new ParsedTerm(); + data.Usage = Usage; + data.FullTerm = FullTerm; + data.Term = TermKey; + data.Category = Category; + + mParsedTerms[FullTerm] = data; + return data; + } + + public static void RemoveParsedTerm( string Term ) + { + mParsedTerms.Remove(Term); + } + + public static void DecreaseParsedTerm( string Term ) + { + ParsedTerm data = GetParsedTerm(Term); + data.Usage = Mathf.Max (0, data.Usage-1); + } + + static void UpdateParsedCategories() + { + mParsedCategories.Clear(); + mParsedCategories.UnionWith( mParsedTerms.Select(x=>x.Value.Category) ); + + mSelectedCategories.RemoveAll(x=>!mParsedCategories.Contains(x)); + } + + + #endregion + + #region ParseKeys + + public static void ParseTermsInSelectedScenes() + { + EditorApplication.update -= ParseTermsInSelectedScenes; + ParseTerms(false, false, true); + } + + public static void DoParseTermsInCurrentScene() + { + EditorApplication.update -= DoParseTermsInCurrentScene; + ParseTerms(true, false, true); + } + + public static void DoParseTermsInCurrentSceneAndScripts() + { + EditorApplication.update -= DoParseTermsInCurrentSceneAndScripts; + ParseTerms(true, true, true); + } + + static void ParseTerms(bool OnlyCurrentScene, bool ParseScripts, bool OpenTermsTab) + { + mIsParsing = true; + + mParsedTerms.Clear(); + mSelectedKeys.Clear(); + mParsedCategories.Clear(); + + if (ParseScripts) + { + ParseTermsInScripts(); + FindTermsInLocalizedStrings(); + } + + if (mParseTermsIn_Scenes) + { + if (!OnlyCurrentScene) + ExecuteActionOnSelectedScenes(FindTermsInCurrentScene); + else + FindTermsInCurrentScene(); + } + + FindTermsNotUsed(); + ScheduleUpdateTermsToShowInList(); + + + if (mParsedTerms.Count <= 0) + { + ShowInfo("No terms where found during parsing"); + return; + } + + UpdateParsedCategories(); + { + mSelectedCategories.Clear(); + mSelectedCategories.AddRange(mParsedCategories); + } + + + if (mLanguageSource!=null) + { + var sourceCategories = mLanguageSource.GetCategories(); + mSelectedCategories.RemoveAll(x => !sourceCategories.Contains(x)); + } + + if (OpenTermsTab) + { + if ((mFlagsViewKeys & (int)eFlagsViewKeys.Missing) > 0) + { + mFlagsViewKeys = (int)eFlagsViewKeys.Used | (int)eFlagsViewKeys.NotUsed | (int)eFlagsViewKeys.Missing; + } + else + { + mFlagsViewKeys = (int)eFlagsViewKeys.Used | (int)eFlagsViewKeys.NotUsed; + } + mCurrentViewMode = eViewMode.Keys; + } + mIsParsing = false; + } + + static void FindTermsInCurrentScene() + { + Localize[] Locals = (Localize[])Resources.FindObjectsOfTypeAll(typeof(Localize)); + + if (Locals==null) + return; + + for (int i=0, imax=Locals.Length; i Type_localizedString.IsAssignableFrom(x.PropertyType) || + Attribute.IsDefined(x, typeof(TermsPopup))); + foreach (var p in props) + { + string value = null; + if (Type_localizedString.IsAssignableFrom(p.PropertyType)) + { + var varObj = p.GetValue(cmp,null); + value = Convert.ToString(varObj.GetType().GetField("mTerm").GetValue(varObj)); + } + else + { + value = Convert.ToString(p.GetValue(cmp,null)); + } + if (!string.IsNullOrEmpty(value)) + { + GetParsedTerm(value).Usage++; + } + + //Debug.LogFormat("{0} ({1})", p.Name, p.PropertyType); + //Debug.Log(value); + } + + + var variables = cmp.GetType() + .GetFields() + .Where(x => Type_localizedString.IsAssignableFrom(x.FieldType) || + Attribute.IsDefined(x, typeof(TermsPopup))); + foreach (var v in variables) + { + string value = null; + if (Type_localizedString.IsAssignableFrom(v.FieldType)) + { + var varObj = v.GetValue(cmp); + value = Convert.ToString(varObj.GetType().GetField("mTerm").GetValue(varObj)); + } + else + { + value = Convert.ToString(v.GetValue(cmp)); + } + if (!string.IsNullOrEmpty(value)) + { + GetParsedTerm(value).Usage++; + } + //Debug.LogFormat("{0} ({1})", v.Name, v.FieldType); + //Debug.Log(value); + } + } + } + + static void FindTermsNotUsed() + { + // every Term that is in the DB but not in mParsedTerms + if (mLanguageSource == null) + return; + + //string lastCategory = null; + foreach (TermData termData in mLanguageSource.mTerms) + GetParsedTerm(termData.Term); + } + + static void ParseTermsInScripts() + { + EditorApplication.update -= ParseTermsInScripts; + + string[] scriptFiles = AssetDatabase.GetAllAssetPaths().Where(path => path.ToLower().EndsWith(".cs")).ToArray(); + + string mLocalizationManager = @"GetTranslation\s?\(\s?\""(.*?)\"""; + string mLocalizationManagerOld = @"GetTermTranslation\s?\(\s?\""(.*?)\"""; + string mLocalizationManagerTry = @"TryGetTranslation\s?\(\s?\""(.*?)\"""; + string mSetTerm = @"SetTerm\s?\(\s?\""(.*?)\"""; + + Regex regex = new Regex(mLocalizationManager + "|" + mLocalizationManagerTry + "|" + mLocalizationManagerOld + "|" + mSetTerm, RegexOptions.Multiline); + + foreach (string scriptFile in scriptFiles) + { + string scriptContents = File.ReadAllText(scriptFile); + MatchCollection matches = regex.Matches(scriptContents); + for (int matchNum = 0; matchNum < matches.Count; matchNum++) + { + Match match = matches[matchNum]; + string term = I2Utils.GetCaptureMatch(match); + GetParsedTerm(term).Usage++; + } + } + ScheduleUpdateTermsToShowInList(); + } + #endregion + + #region Misc + + public static void SetAllTerms_When_InferredTerms_IsInSource() + { + var Locals = Resources.FindObjectsOfTypeAll(typeof(Localize)) as Localize[]; + + if (Locals==null) + return; + + foreach (var localize in Locals) + { + if (localize == null || localize.Source != null && localize.Source.SourceData != mLanguageSource || localize.gameObject == null || !GUITools.ObjectExistInScene (localize.gameObject)) + continue; + + if (!string.IsNullOrEmpty (localize.mTerm) && !string.IsNullOrEmpty (localize.SecondaryTerm)) + continue; + + ApplyInferredTerm( localize ); + } + + ParseTerms (true, false, true); + } + + public static void ApplyInferredTerm( Localize localize) + { + if (mLanguageSource==null) + return; + if (!string.IsNullOrEmpty (localize.mTerm) && !string.IsNullOrEmpty (localize.mTermSecondary)) + return; + + string sTerm, sSecTerm; + localize.GetFinalTerms (out sTerm, out sSecTerm); + + if (string.IsNullOrEmpty (localize.mTerm)) + { + var termData = mLanguageSource.GetTermData (sTerm, true); + if (termData!=null) + localize.mTerm = termData.Term; + } + + if (string.IsNullOrEmpty (localize.mTermSecondary)) + { + var termData = mLanguageSource.GetTermData (sSecTerm, true); + if (termData!=null) + localize.mTermSecondary = termData.Term; + } + + //localize.Source = mLanguageSource; + } + + #endregion + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_ParseTerms.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_ParseTerms.cs.meta new file mode 100644 index 00000000..093359fe --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_ParseTerms.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 697e1bc5d373845df927c0da625b7cad +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Scenes.cs b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Scenes.cs new file mode 100644 index 00000000..94a70a08 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Tools_Scenes.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public partial class LocalizationEditor + { + #region Variables + EditorBuildSettingsScene[] mScenesInBuildSettings; + bool Tools_ShowScenesList; + #endregion + + #region GUI + + void OnGUI_ScenesList( bool SmallSize = false ) + { + mScenesInBuildSettings = EditorBuildSettings.scenes; + string currentScene = Editor_GetCurrentScene (); + + List sceneList = mScenesInBuildSettings.Select(x=>x.path).ToList(); + if (!sceneList.Contains (currentScene)) + sceneList.Insert (0, currentScene); + + mSelectedScenes.RemoveAll (x => !sceneList.Contains(x)); + if (mSelectedScenes.Count==0) + mSelectedScenes.Add (currentScene); + + if (!Tools_ShowScenesList) + { + GUILayout.Space(5); + GUILayout.BeginHorizontal(); + Tools_ShowScenesList = GUILayout.Toggle(Tools_ShowScenesList, "", EditorStyles.foldout, GUILayout.ExpandWidth(false)); + + string sceneText = string.Empty; + if (mSelectedScenes.Count==1 && mSelectedScenes[0]== currentScene) + sceneText = "Current Scene"; + else + sceneText = string.Format("{0} of {1} Scenes", mSelectedScenes.Count, Mathf.Max(mScenesInBuildSettings.Length, mSelectedScenes.Count)); + var stl = new GUIStyle("toolbarbutton"); + stl.richText = true; + if (GUILayout.Button("Scenes to Parse: "+sceneText+"", stl)) + Tools_ShowScenesList = true; + GUILayout.EndHorizontal(); + GUILayout.Space(10); + return; + } + OnGUI_ScenesList_TitleBar(); + + GUI.backgroundColor = Color.Lerp(GUITools.LightGray, Color.white, 0.5f); + mScrollPos_BuildScenes = GUILayout.BeginScrollView( mScrollPos_BuildScenes, LocalizeInspector.GUIStyle_OldTextArea, GUILayout.Height ( SmallSize ? 100 : 200)); + GUI.backgroundColor = Color.white; + + for (int i=0, imax=sceneList.Count; i0) + { + try + { + string FilePath = AssetDatabase.GUIDToAssetPath(assets[0]); + return FilePath; + } + catch(Exception) + { } + } + + return "Assets/ScriptLocalization.cs"; + } + + void BuildScriptWithSelectedTerms( StringBuilder sbTrans, StringBuilder sbTerms ) + { + List Categories = LocalizationManager.GetCategories(); + foreach (string Category in Categories) + { + List CategoryTerms = ScriptTool_GetSelectedTermsInCategory(Category); + if (CategoryTerms.Count<=0) + continue; + + List AdjustedCategoryTerms = new List(CategoryTerms); + for (int i=0, imax=AdjustedCategoryTerms.Count; i ScriptTool_GetSelectedTermsInCategory( string Category ) + { + List list = new List(); + foreach (string FullKey in mSelectedKeys) + { + string categ = LanguageSourceData.GetCategoryFromFullTerm(FullKey); + if (categ == Category && ShouldShowTerm(FullKey)) + { + list.Add( LanguageSourceData.GetKeyFromFullTerm(FullKey) ); + } + } + + return list; + } + + void BuildScriptCategory( StringBuilder sbTrans, StringBuilder sbTerms, string Category, List AdjustedTerms, List Terms ) + { + if (Category==LanguageSourceData.EmptyCategory) + { + for (int i = 0; i < Terms.Count; ++i) + { + sbTrans.AppendLine( " public static string " + AdjustedTerms[i] + " \t\t{ get{ return LocalizationManager.GetTranslation (\"" + Terms[i] + "\"); } }"); + sbTerms.AppendLine(" public const string " + AdjustedTerms[i] + " = \"" + Terms[i] + "\";"); + } + } + else + for (int i=0; i=0) + Term = "_"+Term; + + if (!allowFullLength && Term.Length>Script_Tool_MaxVariableLength) + Term = Term.Substring(0, Script_Tool_MaxVariableLength); + + // Remove invalid characters + char[] chars = Term.ToCharArray(); + for (int i=0, imax=chars.Length; i=0) return true; + return c>='\u4e00' && c<='\u9fff'; // Chinese/Japanese characters + } + } + + void ScriptTool_EnumerateDuplicatedTerms(List AdjustedTerms) + { + string lastTerm = "$"; + int Counter = 1; + for (int i=0, imax=AdjustedTerms.Count; i +// { +// EditorApplication.update -= Callback; + +// if (source.GetComponents().Length<=2) +// { +// Debug.Log ("Deleting GameObject '" + source.name + "' and Openning the "+LocalizationManager.GlobalSources[0]+".prefab"); +// DestroyImmediate (source.gameObject); +// } +// else +// { +// Debug.Log ("Deleting the LanguageSource inside GameObject " + source.name + " and Openning the "+LocalizationManager.GlobalSources[0] +".prefab"); +// DestroyImmediate (source); +// } + +// GameObject Prefab = (Resources.Load(LocalizationManager.GlobalSources[0]) as GameObject); +// Selection.activeGameObject = Prefab; +// }; +// } +// GUILayout.FlexibleSpace(); +// GUILayout.EndHorizontal(); + +// GUILayout.Space(10); + } + + private bool bSourceInsidePluginsFolder = true; + public void OnGUI_Warning_SourceInsidePluginsFolder() + { + if (!bSourceInsidePluginsFolder || mLanguageSource.UserAgreesToHaveItInsideThePluginsFolder) + return; + + if (!mLanguageSource.IsGlobalSource()) + { + bSourceInsidePluginsFolder = false; + return; + } + + string pluginPath = UpgradeManager.GetI2LocalizationPath(); + string assetPath = AssetDatabase.GetAssetPath(target); + + if (!assetPath.StartsWith(pluginPath, StringComparison.OrdinalIgnoreCase)) + { + bSourceInsidePluginsFolder = false; + return; + } + + string Text = @"Its advised to move this Global Source to a folder outside the I2 Localization. +For example (Assets/I2/Resources) instead of (Assets/I2/Localization/Resources) + +That way upgrading the plugin its as easy as deleting the I2/Localization and I2/Common folders and reinstalling. + +Do you want the plugin to automatically move the LanguageSource to a folder outside the plugin?"; + EditorGUILayout.HelpBox(Text, MessageType.Warning); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Keep as is")) + { + SerializedProperty Agree = serializedObject.FindProperty("UserAgreesToHaveItInsideThePluginsFolder"); + Agree.boolValue = true; + bSourceInsidePluginsFolder = true; + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ask me later")) + { + bSourceInsidePluginsFolder = false; + } + + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Move to the Recommended Folder")) + EditorApplication.delayCall += MoveGlobalSource; + + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + + GUILayout.Space(10); + } + + public bool OnGUI_Warning_SourceNotUpToDate() + { + if (mProp_GoogleLiveSyncIsUptoDate.boolValue) + { + return false; + } + + string Text = "Spreadsheet is not up-to-date and Google Live Synchronization is enabled\n\nWhen playing in the device the Spreadsheet will be downloaded and override the translations built from the editor.\n\nTo fix this, Import or Export REPLACE to Google"; + EditorGUILayout.HelpBox(Text, MessageType.Warning); + return true; + } + + private static void MoveGlobalSource() + { + EditorApplication.delayCall -= MoveGlobalSource; + + string pluginPath = UpgradeManager.GetI2LocalizationPath(); + string assetPath = AssetDatabase.GetAssetPath(mLanguageSource.ownerObject); + + string I2Path = pluginPath.Substring(0, pluginPath.Length-"/Localization".Length); + string newPath = I2Path + "/Resources/" + mLanguageSource.ownerObject.name + ".prefab"; + + string fullresFolder = Application.dataPath + I2Path.Replace("Assets","") + "/Resources"; + bool folderExists = Directory.Exists (fullresFolder); + + if (!folderExists) + AssetDatabase.CreateFolder(I2Path, "Resources"); + AssetDatabase.MoveAsset(assetPath, newPath); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + var prefab = AssetDatabase.LoadAssetAtPath(newPath, typeof(GameObject)) as GameObject; + Selection.activeGameObject = prefab; + + Debug.Log("LanguageSource moved to:" + newPath); + ShowInfo("Please, ignore some console warnings/errors produced by this operation, everything worked fine. In a new release those warnings will be cleared"); + } + + public static void DelayedDestroySource() + { + + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Warnings.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Warnings.cs.meta new file mode 100644 index 00000000..bb324deb --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Localization/LocalizationEditor_Warnings.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 20e86d3a806624846bccd81bac9f935f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_ANDROID.cs b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_ANDROID.cs new file mode 100644 index 00000000..e82e75a9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_ANDROID.cs @@ -0,0 +1,151 @@ +#if UNITY_ANDROID +using UnityEditor.Callbacks; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEditor.Android; +using UnityEngine; + +namespace TEngine.Localization +{ + public class PostProcessBuild_Android + #if UNITY_2021_1_OR_NEWER + : IPostGenerateGradleAndroidProject + #endif + { + #if UNITY_2021_1_OR_NEWER + + public int callbackOrder => 0; + public void OnPostGenerateGradleAndroidProject(string path) + { + path = Path.Combine(path, "src/main"); + PostProcessAndroid(BuildTarget.Android, path); + } + + #else + + // Post Process Scene is a hack, because using PostProcessBuild will be called after the APK is generated, and so, I didn't find a way to copy the new files + [PostProcessScene] + public static void OnPostProcessScene() + { + // #if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 + // bool isFirstScene = (EditorBuildSettings.scenes.Length>0 && EditorBuildSettings.scenes[0].path == EditorApplication.currentScene); + // #else + // bool isFirstScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex <= 0; + // #endif + // + // if (!EditorApplication.isPlayingOrWillChangePlaymode && + // (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android) && + // isFirstScene) + // { + // string projPath = System.IO.Path.GetFullPath(Application.streamingAssetsPath + "/../../Temp/StagingArea"); + // //string projPath = System.IO.Path.GetFullPath(Application.dataPath+ "/Plugins/Android"); + // PostProcessAndroid(BuildTarget.Android, projPath); + // } + } + #endif + + + //[PostProcessBuild(10000)] + public static void PostProcessAndroid(BuildTarget buildTarget, string pathToBuiltProject) + { + if (buildTarget!=BuildTarget.Android) + return; + + if (LocalizationManager.Sources.Count <= 0) + LocalizationManager.UpdateSources(); + + // Get language with variants, but also add it without the variant to allow fallbacks (e.g. en-CA also adds en) + var langCodes = LocalizationManager.GetAllLanguagesCode(false).Concat( LocalizationManager.GetAllLanguagesCode(true) ).Distinct().ToList(); + + if (langCodes.Count <= 0) + return; + string stringXML = "\n"+ + "\n"+ + " {0}\n"+ + ""; + + SetStringsFile( pathToBuiltProject+"/res/values", "strings.xml", stringXML, LocalizationManager.GetAppName(langCodes[0]) ); + + + var list = new List(); + list.Add( pathToBuiltProject + "/res/values" ); + foreach (var code in langCodes) + { + // Android doesn't use zh-CN or zh-TW, instead it uses: zh-rCN, zh-rTW, zh + string fixedCode = code; + if (fixedCode.StartsWith("zh", System.StringComparison.OrdinalIgnoreCase)) + { + string googleCode = GoogleLanguages.GetGoogleLanguageCode(fixedCode); + if (googleCode==null) googleCode = fixedCode; + fixedCode = (googleCode == "zh-CN") ? "zh-CN" : googleCode; + } + fixedCode = fixedCode.Replace("-", "-r"); + + string dir = pathToBuiltProject + "/res/values-" + fixedCode; + + SetStringsFile( dir, "strings.xml", stringXML, LocalizationManager.GetAppName(code) ); + } + } + + static void CreateFileIfNeeded ( string folder, string fileName, string text ) + { + try + { + if (!System.IO.Directory.Exists( folder )) + System.IO.Directory.CreateDirectory( folder ); + + if (!System.IO.File.Exists( folder + "/"+fileName )) + System.IO.File.WriteAllText( folder + "/"+fileName, text ); + } + catch (System.Exception e) + { + Debug.Log( e ); + } + } + + static void SetStringsFile(string folder, string fileName, string stringXML, string appName) + { + try + { + appName = appName.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace("\"", "\\\"").Replace("'", "\\'"); + appName = appName.Replace("\r\n", string.Empty).Replace("\n", string.Empty).Replace("\r", string.Empty); + + if (!System.IO.Directory.Exists(folder)) + System.IO.Directory.CreateDirectory(folder); + + if (!System.IO.File.Exists(folder + "/" + fileName)) + { + // create the string file if it doesn't exist + stringXML = string.Format(stringXML, appName); + } + else + { + stringXML = System.IO.File.ReadAllText(folder + "/" + fileName); + // find app_name + var pattern = "\"app_name\">(.*)<\\/string>"; + var regexPattern = new System.Text.RegularExpressions.Regex(pattern); + if (regexPattern.IsMatch(stringXML)) + { + // Override the AppName if it was found + stringXML = regexPattern.Replace(stringXML, string.Format("\"app_name\">{0}", appName)); + } + else + { + // insert the appName if it wasn't there + int idx = stringXML.IndexOf(""); + if (idx > 0) + stringXML = stringXML.Insert(idx + "".Length, string.Format("\n {0}\n", appName)); + } + } + System.IO.File.WriteAllText(folder + "/" + fileName, stringXML); + } + catch (System.Exception e) + { + Debug.Log(e); + } + } + } +} +#endif \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_ANDROID.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_ANDROID.cs.meta new file mode 100644 index 00000000..c76dae8d --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_ANDROID.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4c8d936531867014da228239d095833c +timeCreated: 1489354551 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_IOS.cs b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_IOS.cs new file mode 100644 index 00000000..3b9e3150 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_IOS.cs @@ -0,0 +1,102 @@ +#if UNITY_IOS || UNITY_IPHONE +using UnityEditor.Callbacks; +using System.Collections; +using UnityEditor.iOS_I2Loc.Xcode; +using System.IO; +using UnityEditor; +using UnityEngine; +using System.Linq; + + +namespace TEngine.Localization +{ + public class PostProcessBuild_IOS + { + [PostProcessBuild(10000)] + public static void ChangeXcodePlist(BuildTarget buildTarget, string pathToBuiltProject) + { + if (buildTarget != BuildTarget.iOS) + return; + + if (LocalizationManager.Sources.Count <= 0) + LocalizationManager.UpdateSources(); + var langCodes = LocalizationManager.GetAllLanguagesCode(false).Concat(LocalizationManager.GetAllLanguagesCode(true)).Distinct().ToList(); + if (langCodes.Count <= 0) + return; + + try + { + //----[ Export localized languages to the info.plist ]--------- + + string plistPath = pathToBuiltProject + "/Info.plist"; + PlistDocument plist = new PlistDocument(); + plist.ReadFromString(File.ReadAllText(plistPath)); + + PlistElementDict rootDict = plist.root; + + // Get Language root + var langArray = rootDict.CreateArray("CFBundleLocalizations"); + + // Set the Language Codes + foreach (var code in langCodes) + { + if (code == null || code.Length < 2) + continue; + langArray.AddString(code); + } + + rootDict.SetString("CFBundleDevelopmentRegion", langCodes[0]); + + // Write to file + File.WriteAllText(plistPath, plist.WriteToString()); + + //--[ Localize App Name ]---------- + + string LocalizationRoot = pathToBuiltProject + "/I2Localization"; + if (!Directory.Exists(LocalizationRoot)) + Directory.CreateDirectory(LocalizationRoot); + + var project = new PBXProject(); + string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject); + //if (!projPath.EndsWith("xcodeproj")) + //projPath = projPath.Substring(0, projPath.LastIndexOfAny("/\\".ToCharArray())); + + project.ReadFromFile(projPath); + //var targetName = PBXProject.GetUnityTargetName(); + //string projBuild = project.TargetGuidByName( targetName ); + + project.RemoveLocalizationVariantGroup("I2 Localization"); + // Set the Language Overrides + foreach (var code in langCodes) + { + if (code == null || code.Length < 2) + continue; + + var LanguageDirRoot = LocalizationRoot + "/" + code + ".lproj"; + if (!Directory.Exists(LanguageDirRoot)) + Directory.CreateDirectory(LanguageDirRoot); + + var infoPlistPath = LanguageDirRoot + "/InfoPlist.strings"; + var InfoPlist = string.Format("CFBundleDisplayName = \"{0}\";", LocalizationManager.GetAppName(code)); + File.WriteAllText(infoPlistPath, InfoPlist); + + var langProjectRoot = "I2Localization/"+code+".lproj"; + + var stringPaths = LanguageDirRoot + "/Localizable.strings"; + File.WriteAllText(stringPaths, string.Empty); + + project.AddLocalization(langProjectRoot + "/Localizable.strings", langProjectRoot + "/Localizable.strings", "I2 Localization"); + project.AddLocalization(langProjectRoot + "/InfoPlist.strings", langProjectRoot + "/InfoPlist.strings", "I2 Localization"); + } + + project.WriteToFile(projPath); + + } + catch (System.Exception e) + { + Debug.Log (e); + } + } + } +} +#endif \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_IOS.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_IOS.cs.meta new file mode 100644 index 00000000..327da586 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_IOS.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2bf71e767aaa5a245b9d74f326a39549 +timeCreated: 1489354551 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_UnloadLanguages.cs b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_UnloadLanguages.cs new file mode 100644 index 00000000..d6367ceb --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_UnloadLanguages.cs @@ -0,0 +1,30 @@ +namespace TEngine.Localization +{ + public class PostProcessBuild_UnloadLanguages + { + // [PostProcessBuild] + // public static void SaveGlobalSources(BuildTarget buildTarget, string pathToBuiltProject) + // { + //if (LocalizationManager.Sources.Count <= 0) + // LocalizationManager.UpdateSources(); + + // foreach (var source in LocalizationManager.Sources.Where(x=>x.IsGlobalSource())) + // { + // source.SaveLanguages(true, PersistentStorage.eFileType.Streaming); + // } + // } + + // [PostProcessScene] + // public static void SaveLocalSources() + // { + // if (EditorApplication.isPlayingOrWillChangePlaymode) + // return; + + // LanguageSource[] sceneSources = (LanguageSource[])Resources.FindObjectsOfTypeAll(typeof(LanguageSource)); + // foreach (var source in sceneSources.Where(x=>!x.IsGlobalSource())) + // { + // source.SaveLanguages(true, PersistentStorage.eFileType.Streaming); + // } + // } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_UnloadLanguages.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_UnloadLanguages.cs.meta new file mode 100644 index 00000000..6daf1647 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/PostProcessBuild_UnloadLanguages.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 68151af3db9fb734fb3823c020c9b8c0 +timeCreated: 1489354551 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Unity XCode.meta b/EintooAR/Assets/TEngine/Editor/Localization/Unity XCode.meta new file mode 100644 index 00000000..926bf8b6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/Unity XCode.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d9276efd8270b104ea614946e5787aa1 +folderAsset: yes +timeCreated: 1489466610 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Localization/Unity XCode/UnityEditor.iOS_I2Loc.Xcode.dll b/EintooAR/Assets/TEngine/Editor/Localization/Unity XCode/UnityEditor.iOS_I2Loc.Xcode.dll new file mode 100644 index 0000000000000000000000000000000000000000..939cde4bb0ae0aeb8991307dcf140f041ded12df GIT binary patch literal 123904 zcmdqK37j28wLf0d-M8;LliazJJCk*Wz=WH*GZP5gkg$ZvF1WDon=Gm9-( zDgq+nhN2h+6%{w03vP&tisFI~MV7eZ?sI#}(`WpDzvonS_nn!<<^A6O|NH#sliaR4 zRdvp(Q>RXyTDtnklWsJ=F($zOzx~aakK)O{b@IFYpG`>a8@{K{++BQdhmZCg@!$@} zJoo(8$R%-fUVP^BMxJx##TQ2#M$S5CB;I)O$oUtK9Qe$mN1hj*ea>WWZ)qos`dJ4V zb3~7C@}GX^Nsik0%<_?P&o0J1+G9*Xpdzy6sN*059t$PWx z@?ZM2QG)Py9q>L=LY{e3fXWFv-Uy|Y$B1swIxKR763(lr1hG^s%sAi_e^BT zwV!66?=2_?KR>X6@50`gZfr=dQii<|I#R zzr&pGlAIUpe(23)>~*hLek0MYe%@EFUHeK~lEAf-%=}`>{Kp?}zH#ks786UZ{cl93 zPM5?xKX~~4#IXLF;diZltHnUz+GB}fjb`fk+2dk=ZxZ0j9tT`bU`K$@PJjyte69dDCcpxLM+@+E3Ggoz(0&5^LIV6Xfgphzp{rZ! z-zRWDfKAT<|D8a#au`250e*qNp9^qf0=$R7hXwfR1o&P8?-k$&65wqFzFUCM7EArr z1iltO)8HVeOudppGz5ZIGYG{DD$N&9!))QXVLB(zi>6^B5I=i5FV9n^VL}l4gbiX`N>4LIGG1a7=#lZT-)RV5ftZht1smD*G z)L8eJnlcz;RB=2|5;0X}FkYELDVLbKG8i8T=%DgTDaBNlE*>benA$QJw^9t0pr}h1 zXOw45eW}N9P4iN^qA-K;XHzI;9aCevFi`R_Ri+Edc8IAngYkc*7}zTD(tyyt@oS~d zHqy4~fdNEB?d~#!+SlPnj56S~%S?wfX_qDa`Z>}e*ChRhInp8FBprG>3qNF?q{F<- zN{7^w^jFQ14*4hPH_efbmPpdkZ)V{~n^UmNk^BQg&!@Jq`z*C zbhKTP{`#(T&!DZ4n56sBAJA{4f!5n5@q_3;0W)J6z#j!r+r>8+2fNA#(VrZGqTsn1Bz=lX&Oqdq8zPAE^n>&o~MjHdELol%58|Wk4N~h{duq9AZhW9S=|7QVC>!5g^bhjpH4n8s5hvO5O>>Wwv00?& zqWecj*AxF6HG)ihkwGbh49fX&uUYWI#tE#>*kbT^8TcDwz7~EV4&fmvdEdS(YaL0fp=35<|;ABE?cP#ORoTq|nx?}jH>oK@E) z#t#}r__8HytZA&m2zDEMg*qZH2EF4^9?Zh5cn$o7(J*pEBlsybcMc=4Q!4lOG?wGp zt|lU=6vj&y+Ph_8sFnQ2mU1|r4{ap}dYh&=X0(nqv)jS0j=s#JAQtjG)R<%?z4%fL zNuelLV*(K4d5t~sZ0wC63tx?3*@97RsAnPH*cAa2DlOLMbkqk@mioY!htZC#4>fs=td9ZfD_9}wvbHHIv>*X5LOq?Ffk9gEb6u57>$UFav|b=(AmFMA>I01*qM5Ah z{ZOs4)}xG>!I&Yh??HZuTiR}S@apt5KTw&v32A6@_>@5e8(HdYUQmp7Mxcff+G})I z4f?cOH7Av;g{D7DYgY|KWo!8=R4AKJ*|Hl{(ABLM{kVXr>Zd6x{Dv*%;&{I38dQ{~ z2h#A&)6BZ742D96N6qu!s4`%kP6TYk${%B07&X9iv=Tq1=E^X_u%YsABG9hSR477w zw=8l(|5}&Otwv$aDgCBq_BhnZ-eZG<7s@hzB~+<#1I5n?CE)a3*uf+{egesw(hdJp z7aSJS;^RCrj7~;Z5`D2qUEe_m5nY>ESM(jJD^zXns*X!l|H;0SoijHsX7A3)f^O7#v7YbLgqY-C3=jGckE;MUp2X*tv#g>yuL8y)emy@#y%jReT?Jd-^)MP zl|L{q0)AKv=uv}B>PHweOC>N5BZXKSXK*-0+dXW1@1SbLSioLT`%UK!@m?^)UV#8Y~yV;FTJC;78zs=X~IS zROZ5SOxT9k1m_5hlrY``Wv>J61rVAm?WPmioM?){*@;qyIz>N#Z4Rl;MfV&>WC}!9 zfC|RuFv6gO+Al3cYY^x)#SCxazIa8h-Afr>SSM(c)l9sLiPq$ltON8~8 zai!0UOlti-^K`T1JSPiJmS$BJYJlJsS=;Bczj8i;ad%Fe&^QYG(2L^0OCJlvhn1@@ z#x08r+Kp8?$~+zoDN`tSX|bS?-U7u7>b=eR9(o-6JN;{4-4F4{QPzz^Y5Dl%461!m zs)XV>*TtnzL;u*Xw@Fvr*CMIHvz56=&YTW`z<{IP5u5@Tp`5IS$cV3&e2Ix$Bpvxk zk3WWB1LRBAw5M8C3fovf3&!CF^l32X#sgG%R~Qrwp+U4C%GS4f=u-9gxI7&;mJ$)Q zV6I9ps@H<42T&8u?+2|LU>u`$ND`O5V&dTfMi$B2o#z1L0R;@vp;m&!(Rd+M^JGFZ!ta#jk|!{T_ZPz$zY^_7P7CSf2)(ZI5<}5H1>kY;_oqtddG32FmG2p{1Oy(g)9aSpeRqVg;iZ;S{ zF~feMV!5dUki_bW(pvvldQ5Te6-Yv2qXg{H!C*Ez1V7+zNi~RILZCAJxyE4#$S9eQ zWQK<{h^{p8*p^<*6AOr1pLLc`90HL#{Iz_4UR`1iw+@lDY(x|Sk(;-GBRIBUbU3I) zPbV7%ASy%{JWI7=f3a~S0$m&>mcF+N2MJjdj><#?MJz?nWa$zRm7-@cSne-3o;?#$ zDXkh*A6YFT*f!IH@zOH~o0XCCyI*Nme$<5@F)Mp|z&7*j(6jPz4YO^g0fS9Ld!h%3 z5sA^FBd$f!NEk=wQHxc+m>?gIL^cd`BICaIHkTB|rG+=sAE;CNH<>>j%lvlA@Oamh z0hBNwg0*tGw%#-@NNxHF;0*&5coPmHY%zrseZJS&0fn~qV3Z3DM49G<+%~c2ug9ADZBn0Id zUt~P^iVzKaMe7+-cSFgjdu*#5G>B&F4DlGTxTH4M z&=j0K%ky90PnUU)1CkZn=5O53H*=N}S3R7*?_t(nlJa^6;HW6po5)ki_~JX2o2&C8 zB&;&Y@B<%8Os>-kF0%E7kc})jDJOPa>HZn(N+AZU(5@@ZGy5H>ea+3w;n2b7v&zpF zDmBMLA&qe)FPaF6^%Z2HM;8usE+d1=V)PVI=dX16f&(+hlRh(*tn~!uN2oL0<+OeL z@m@dcrVL`x>eVg}=i$T14y)m`Qu|&39c1cFOcBd~CC;1CbISu2ldpw!%nzSm4XgQE zY6XKqu%}k4md10{LZ#VPh@Zf)T`h>yQ}IHCPGxs1R;6E;t7T*?mYS>bzqrf@VE5IgZ1v)>4G_&(l zH~zaRc>H~E*9btgg#Lz^S;$2@nBP)P)?dpQIS2AOAI?snrHkdW?4_QZj~ z{!#-z3r03mEw{0;7UXs1sZyGZ`p^{d|Oqmt?ev#!;*6Xi-u*VIGnU8TZXOWa#{3*sMR(jZ?n4 z0Q?+4epGiHSDEI-nU)}xlpR8c?GOs3qI3(wo^YnhX2;9#bdQ&I-tN|3nkS}wP>0uB zxuB)AyOf&qtr)z#uf4>MiCE^y?0rBv6lb4VGWJj5JQt+gIQw^TvY)_)U^Sk0q^`VFZiw&)~s{Jn(Zc z@yIIbQpLrISs0!F&*Ab|FI_Xn)S}xg$Pk4YMlG8_1uHiPx}>*2U?x9y6r@TG^F_mg z&Q3_6Euc+56i=r!b9QUnmoP7&Qw*yf z%Vs-V&!)pU`XNc1Zr=u{#wTdBGnJWXD4cATtaW*} zCW0A~IX>&MeLCCYdN!SZS#K`SROf%*r#jolmh!yKKDGKE)|>5cJ)6#A%ry>A+I0JR zQ_I*J`1e<3>ht4ni{t1Fo8kSO?&P?BGDCM}V7y}67*!XGX1L+-`Q~QegU)jB}(q{7asfYv+Y#{mEKS`m*$S4ok+|<&ZL*RniQj3;*tzi$Re6AJY%&r5(3t z<46`gR=7nE9cK&bywCJf+yR=0x*RvqQoR~6tB+Ftak|QHTm&u~FQ+ofJ`aS7T_o`0 zx1NU-PO`6+#Plc@RuYkUKLgJID@kDk&4GpdBp$&nM;v(E`A3iV>_MUVoVjJr7?9o( zlAgL5E}gRBA>$)wq(|Q(k}$roWG;!WhRCrTvH*J^62B7hjc}d3vT5R^mI7Y}VAU$-udhXJdMd`jv2Qq=54w<4htOvKBd%!iYA) zNpj4TO|zQ9i5Z}39=jmdAdKqSQzdtxZ)H!FWL&Ihi-=v@@D=8?pK1SkhS$Q0kg$Wr z(Li$BJrzu$y8BP z{>U6Xis4E(45s;`8@FlGo8~%$z3oX^#1N~pEK|fU-ZHB|aqxuR zqA$${4VbvUyJ=t#XUOn(U93Zv!C>p#kedpptN!z66&Cq}Z}aS#GJutyQwH@)6KBb! z)_$Q&^$LS0R0_g)Z*k)BF2d-9Gq}FEyILh=NLq%vh67jTsF^x(0CHKK*r7`&n4mgQ z3$)(VAgdLvM<@_gh_LZaM9TT;^(Zurd45)3^V68vIvRs3G&(0{oRpkC2zeXt0Jbh> z4o)$2bIF7`arOFxrw`hrzw?Y&oQ5Z75gUK#bezDDt$0Z~G?TRG^hHRLbBHW;SSD%N z>C2GB%`Yi+cqVCh{^`T>k;s*3NyK=bP#fV(f2YeYvT)g7vK*1gGCXqn@CXvQ)Gvt` zf0OdV>rNkDheR$>OCpSKk~o6C0_6Nf7OqN57WDlz3r~@NK7NsftI?7LT{M#gx`8bC zMV5Khd71?poXHYM7W^X1{OWwo0)=u}y4155@I?FQm*fnV)16I9?ZPF^)3LwyC>~ zSp|vRZQX67Hz0kRHo82k@V0IAMso3e*q_nvaq3^P(f%yLl&2Zc`odNZg(-wYOKee^z10#y4l7KF3Nwu}(J+{T^n#)=!{H9s1#2t~b=R zRL8#v~e+< z+VN$xKf0H4481dg2I)b5QFGBPh;xiedix9ttA$kJwml)!JAODFVj_dIbeF$;* z9s}R3!#Pp|)Zs{`a9oTpWeD~^h&v2H!-M#(3~@A!zswMaulTnNag>Yy$`Hq`c-}mO zI84R6F~rd*KA9m7K4Vsv?Ah@-gt8;6ERj?G;ujKrI&(b6&>0LJFdv~alMwn{5Vr|? z4nv=1=xm0*&k$;amSX5!hK{ZxbRI%u)A4&5elDR8GQ>Gn{9}eL(Dc7Bj9wPR&+JDC zHamzfXXtrMpNy|!m@@-}|BYcf_o&rh8KzScKfQ(!{TDz_XPCogd_6-P>QL^-40Gf{ zI5&VW`VzxOGt2=2;kPhMdkrk#W|#&yUbO%rT3zHglVKV>gl}cI%`n{O0Zy;6D%8Cu zw1NFnI-y(hap`D3jPo0oFdd7@v)&1XTgCLHOrM^Sj^4_%piCcTkIKI90UaP*dYZyL zd7l#P40z)qm^fdiAW{migeu6+I>y#}jR(aFV#$QIqYFSjy8vWt>?p4Vk(D}^BjQS{ z9LOj14|Lm1w0wGeFTg+-$i6oDbEr=j^EdOw;K>@9A zq4;d*!*fEvokBsMb{&ml&=at)Odka6nu66LOx_pKeCQd-_sF*LK?u-tb$i%&%HP8aF($Mwuv0OV^*No9s0NLQxY49b)(Ygk|n@0z|=%olm zFT+pkZjwh_@K<4g-#X9_udW*u3bK%+dqzV)|e#$d678u9!Xufvw@Iupruc z6;ekxF{Ob*&4$mPJphzG!gb+4pzK*HOV&BMnTcV%6t$BL>WO1;&Leln(j5A)Cj;(S@fimk6s7J(5aZVc&C5(4yDzUNi{vwY6>+|SC~m=z%>hEpb%3z2a}x%x2=)JquW5qrb8cnIR}MNnrAG3ic;9;5Uq_1L$-aQ zx3a`${7Cl?;~}QJ4RQ2qwgcZD&=#LWihVt#uyGlLtF}YdPkFeKQ}1jekAY{NFXdH3 z@DE@QHZDaeu?OShHijeHuqeSqUevIeQ|+YYNdK-(-G({8XmSmtu>xm>km{MM1`Ewug`g&KSeK1-8r{Qie673Sip5H8o{C6-|HfaaIY5sQtCM0SV#NLHi<2NYAl_L`3>QLQO zi`7bWC(;<|)ewYc5B}ed9h24Q=R6ETBUG{2dSl{(?!-?b(Vhp>doub{`9z;Wq7{$S0dAa=&$ZwTJN2I? zS6&-KLBJ?_A){}UL^*zHUz76MFwDr&E<;Swy~G=iFYbnZ22ejm@|F}yF1nA1v0tV< zp07NThv>7!mF&lA8`siwKl)snfjY1nb+|y&$x;vrS-H{yEI~S1=;u*3@l(}*T9KA# zt@TT8*Pmfe^)#DJU^*_HjmXY zul;6V(39f6zT&51P*9+nsP)Q4Uk6^=I9E@NOJ6yl8^7Z9BWYm~sDnrgcZu3z`-Wf# z9*(uQ^cb#n;*5p7iC)4>_m@Bx<$R?uc;Z0;a^>(Jc7ro7gIhby)N}A-{OolStK5+q zul-6?6Y7BZqQ0g%kbu5PQ24|cO55``U+OwH^??}!YxDT5EZ`$fU@#W6eO~)jMB5iVLL3}#f!2cH27u=+!^pe@!3m=6 z1;f48L2Q}<^3`_ zX;BM;Tv1-4D$3Z?pTmI{+(*Y_8noZ&0(BtgYAAJ;CQHFZd!3IOV*4%y%{H@g+p&(U zw9)nj3OmpN$N>bCna?0Ej>S0a+>9KWnVJ%z9W035B7Sa8k`;ksNR;8vOraqGq)9D^ z4WuVa#||2~H+#PE@fr%czMe*5)e-MU91omZ3bK`_VMOJ>W@|)OwI9e8jP9r;)kwLQ zTU_Jf8AB#-sbG8;4Mea_^SCvk!>OEdJM|1S+aG`w;b_)0MrQT z!F#XFFQ5oLh|EKne>@k7xwg4Pbku9V8hmB$pqctB^0;eg#DS|&kD8#DF^*GrBA2s| zs0Mpp)<7=sVB0K^{jq_QUDP76ZGoCQE~raB3uMQ1`NVPsYPq=aDETaqJ=EnByAx^lpdEM~|L?#tk{Xxbj= z_Xq5*^4=R#`2_y|C;pf5pMPwJ8vdh?n&tTK;B1FGePb>aTNeM6)5^!dM(5>_r5Ae( z5r3TVYbCxD<4-V7mGUNe!A1OH#(&H>6~>EiVEjqOZ5b zua!8~7cXi3jPcho-Z}~6afhyo*ZMi3FO%Re5F8a*s6WrmppqFCX{hJsAe4u8ZwH}7 zJh_t5K`0ZiO?fy7rJ|PJK`0khRR^JDR8t*MfflGmn$9E5W6+LV!l;H6+d#H$m`ovV=OwKh?JSEs?3FgVb;Mj*Q;a@4nb zMnzv-nDudC>X{2u7A{Qrx-jeJ!sNzzSE?RbL(hZy9D#=oSi%sLYn+Ml(Wz)@)5N-$sInG~euosd zI7kb*$Q2EveULv}R9QI&1=gIe@5Q6mtHHVT%G^7OMf2u&r0-u2!bNVePOUS6k26&o zp6K`F2(^I^v?w3J(3L8ozRsp^MJu<~VcpVoC>bbdtD-*=#h>ug+gx0XoVc9*88pgPML>hYLWC=(O1yrP%f?5*t;b!P zx@_ED3Vr2lfJ>lsWAgD0KwFy^R{OL`<|Q)hOKDf zRIB2SkZOePf%Utv+OJx(IjI}cmO$8Y{Ye!ysHQa#Q;hjoDMF)R$q$HX5nd)O)ds@q zfFcqTC5?@=1W^r$YAGU)fKeY2VNfsC7Bu&-E{NbWmTGl~yRP-E%X_w3X#)9zTzn7s zL>Py-gT|xO2_a=rTxfk1wO;^Q3sPD#TEI=kHBuxn2yGvXY77pA)gdJ{Bz~;oLaLym zwhsc;V2VnHnE|2#FQwW-pjsG#l~Qd{SY4#37U?UYDuIP5s)azcFhwP!5#IPMMR?)3 zR9oEKwYoT3$lwx4V2R3dWQprI1o5T8c)tW>P(T>HAB-*rc4v*y;`DfAtx7H#tt|zk zOXZr;+On{^Oc`CK*J3E6OH)Rd0@YH>sMqHB7{7-^d1QZlQ5GWa0h|X14b~S2fNR6m z;qe{9nK_~tpNj(N%`+P8 z_Z%0#DrnxNVXmp}2;3XQ*KE8EHmel2{tXXY*!M|1DuvK%dR{CL3c90bsXDGC7i$B(ORmZ6oDg0t#sM1Q3re zMT^PH5*E6S0D0>IqviOd!K(?9Ti}9}&7{sxCPfhIi_#U`uXhMk5bw)efvgdx<`_Gs zUIvdG1H@v+^aYP42&w~u$uF#$Y}?5@CgXLO`4^*be2QZSwdK`XoZ^n42K2!MJ&F4gF{Y+ikFg-kH)yFBV>6|-ql8@&Y&TxaErF}v8ECyW{Vw3!6Yb3TH7BqqnR;!0 z*rovKt6*P*cMeI;uze_?qZ30b!f zvoHXAQPh^P1NEAVIP>Zrt8vE#Y#@}R0mCn^QYLd;%!$k!A>PZNuhIz+UyS|tn*n=1 z>W4D0@nNZTAAZZ?%v4$pknZ)`be35kPDT5R@!4or1x728VMQ^%i4Bd#Jy}+!T*SSD zqi`y2Goo_`N5QsJLEDZCBZCQuO;^MXS8T6l!wSEkO+}@_61p^1A!1XxoCe70u1(wm z4>jNAtASdgWU9mE=5h?vqQI46e?{~T4{GjE9hXyojRHdsF}4pwuGw+D7~h%HP=rEn zG`>55Rk0S%j#jU`n-b%Pkhr<^SzrwtUl-hgZXk)6un5ouWqPymFOjn-QQ2G~49W1FLRsMJp`SqX{Ir3!f&Q zgrvG}djcDHoejesUKpGBgY$9cnPn5s$Mp=RS-j(#X9}@N-Y+zEb+6s|g$QF7y8sLt z4i&r2-OygzQBW(9Tw(o%E@zjom55J|H340d!^&qr`kH7>-h(yxBc%t3H1&^Bfv~%& z!801o!;rGCy~o$XuGsK3DgPe_|1V7VUj=R>?D{}ZYx2>q2vo3)G+XzCx;`jHGDlYPa*T@CZ;rCO;H4$t9y=9X)Y|t9H&<=u2EzScw))* zo!{-cz7s?_r?5ni=qCCG65U&fGNqAsL}yGx^nyQ`hM>!cvz#T2E+&0><^_MC&3S;O zePlQ7TS$A2&}ItnchL&Zm^$d4fHHN!ta3JOyFxwlPC(G+Jjc?0MmOy@lJ;7m%@kfE zq_k&Djr1BpnHs^0&ZfPMYXm`?a}!JZnccMCMB4iZZKm)pMWsDsI-@ra=8=)3?`+!J zxOot?IX$topVdwKR?^;AXfvfzcC=^AXeyY9RCGpz$Zbh`(%xTa zGljQBs?2B1W#)tSe4Wd{p^#0CF52@`+Veqseo7m5+tJ1+iLxF0Hqu@vw3)(}vz0cB zLH%Gt9?G(52%6T^JnDMZp1G5FC)jKyW6@cmo|-!W-yt`OY1ucV{EuGQvOHfT@w! zz76T=*$6#5ae}7r#Pqk$kxs83sgFxfzyS< zxn%g~`tm%_{0bD%g5#6Ij$^)nyq^WzzF;>BoF5{vUAc`=fZ-N##D+K;4H~RbMY>r z!IqqXxnq5HN*J#5I&Lahgwb7Zc`r9tx!D7+si^od?yi)gC{iLdxmDP z)c_MfMI2rIQ zR0i`X49%Dy%wlr}ZLlg$R&cE&a;l*+nf9651e68WL^A7vBnw;+bd7Xo!8MXhwk0{! zOzR7-ndFeP;AcZoRN7J_g`}mp(OV^cwiI(nQ$d)V9imoimL<3U!qB>P#TgZILft)) z6NIXJJ4?*Za(ZS{t~r4R*LCd)_ZG~Vd!q={A&CghX0Mw(lA0FW=ODqgrVhxeUzcq41EkC zlv&U4JxNZ?L4)`ignfdcV;K4*LnkrxDTFu{_&lR#u-1X`a+)IW8?bnI)!vRbUFodk z_R?9k?WMCC+e>GKx0lY!%}QSl{$U5efBVx+cgGU3jHK}|!3yFiqD0(DPHFf%?Oq~N zlGjcopJ>E1^*|4VuwQrkChdEfcnU<7^-btQT&uh=-O4bK`-wQ-Ix714n)nQ~gnX?4 zrnMa7H7U0;>kkC2vw*upEFjLcm(zh8vtXW;zZprqA+cG)1xLp~y9ZBQ9`GE50S zlqTyk__hVs5V)?V++`S-e3HS+E@WbJEBv-D71&)`_aG4DF57rtQu zJecmwZNJeuL@J+!k}-|>uAeL4xwG?Oa*Z~df$zN8`7jZlo$tBb`OXAgOj;ouECyk; zDXJiPn@6g!N+DjX)mH$Lq}7SAYFP9Ln{}S$xuurJ^jc-*E_tcua8>dT>`mS}b{_zG zn5YV0Cx8`viHL22%Z>Qf>ykq87JTfA7hhB8rEoAh6Hoj0Y5~}`xDTm~VT@~>%tSeW zc`usVk4~4k^GQ9S)BaqlPo7y1`l3&|-~L&oC91_+s`-jv61oQ2+CuL54_6(_Q41?6ju<&Q%LaIEXkEvK(z54ujC2+@P4Ex z{^}ls+M`mVSvU$SK`%P+?V1H0Xu@H<4J{m$q8&$hmhcBw-=UR`o{*o;4w zoXCQ)95;j$b0Tw5V$D2UaR$`ZodP_V_@5EjSImt&Sft+z2i2dad(7}Yhn+`k)e86Ml<><~zwNE3r6Vlrp%FyZ$wk{yF zn!IPNGPv2|go}Z`uUG=?4ejK0F&Cq1GnjMlYbzd1_=UIX_VK*n@8Nl^#nZoiJXilc zJXiz}ernst^U`hM;T-%KkooJ0$0-`R6{g?IaM}ZAx`e*jrs5}G%?t9qTZVZS1nN_o z_znyrPG4+-(Cw0f`)Hfm!#>m8+u1|?#>pFm=f)Y}3AP1B2OooM?S>d{Yda0k6`^*f zqj#{K32%d(kFY0Y=v<@!Xv4*?1YEQ>T1znXo^`qa&s&6!v@g+es)wPCIz8BcrQiV& zMu-%{T;l?k&x)XoQJ_aefO~_~wjeH*<|u&0`AnrjSnIp5S$dMz_ZqJS>s9J}0Yp4m zV()yBL3A_icql_&j|H!9wDM=(2m=`8KMD!M3X1$OR0TQ?%dfu9F=(6NY-E~vNSoox zv>9Mev)?7?GppCRcJRz{(6ly(Jo#>KOl71X*fvgkg-3Ww=1sGCJb7*&6Ly8sa{O*I zl08%0#&D|_-g^|Se0roLuRLOUQI2!VT}~>P)a*^OYUZa%wEY)=Q*q3-KVWq_t-NpFiwI%&1Q0n#$CaE^t z_6|T<=}wrXhda7@=LD8<(C4&WBaHKC^L3~+Msl<{Gz~*_X}o3w;>2b?(6qou0xU7V z$;pg5s!(Xqbm_dOwI4?1-MU59*f=0{R_+7&3ax z?6#k>ZNK4C^coro44e8nDGlbNRrMmWa=bIJs|q9y`{`K?i>{GtZN`FUBO+T#pXxIQ z9i7S!(t-hg2*lUl&{z^Sc7 zLox5Ou?vxdeh|;4t)Q=@ch(L0@w42Q|}I_3<@*d|e;k(8oji_@+Mo zoezs{hW=G|nyr6WD8v`V-j-?veS{rA`>kw$n}nBPIj6d)r#>=II}Z6V zZRQ%nC}=qM>=1;5Hmm7;v}X#0HFl6w1wz3%$aw;xj1&T)(1+U_G&YM)mcoO43J3p7 z_}`EJ@K9PPR>t#n@|+)kM4kod)#?eVY#Ye_Hj8H*`-$P;ByOOOKW~dYJhK?*q4%Q9 z+qHh*MY^lsZxIgKY@tRQ`efbC_%ALC235_%7HYgW$&!zYqb$i5(>mtk1p;B?IXUbI zh)}8&VwEJDT~iCON|GAjASy{Jii4;msWS?ZZxf*JncJoQnX!4heS2>*LK{7!Z$ApD zxW2ss?eTwG-=@a8zCB<2K0%Ea*}hLrW;zd5*mQy#9j3Ep930my`WO5CuO{6)yn*=K z5Edp>orlpHczlbGWPX4y7#{*D&lntVVu|KAJ|9WB7Cl}mjuljg$QMNN-X`bw=o0W% z+eB{XIJ$Rmhr&tQ!hQ2TdK21=zb{mH=r_xjyj% zJm1N>f+Pz@7Xw8Z{$CI6n0$%+GbEjQNuxmK2Gbsnbn5@XBfTaa@U?l|wCi%T557%J z{9%Og1xxeY>lUehNS-j>n|Ezr{&s9_ftSQbO4zS7SHmYF`}kI>6as0)Ti!K1GQZD|DgO18w%y2#+lyk~ZqtG88#YwsRxF%~Wz9i1n2*+Ka z&+0iM|fBdVJ0HS)Q&? zy$~QwobgRrG0Hd|ukUg>#bn-{GT&Si6Bc;o<~&8<>o=yzA^naVzh6e1i?&Wa{JiSc z2xCzR2OLo$co5)Wf!zA0UQ4A}_UgDFoSg8h(CWXO4m|HC9*$F`Xc|9DCi~L}E`)_2 zjY$EFHa-oz7!9e0tN{ZB3i3@dJZ^$;ba9|hY8*;E@wrrco|kgnDdBkrgMn9R;?r-q zb!L;}j(#Ki4cJ5-$IG~m2uZ@qAZ1%GVOaqsO(Mu4( z$KYm6@>)2o23HQ6$M*rU@A9Ey>eCm^%GJ7m#{2Q7zXPm|*MeJFC-tY{7InoRn-PC} zM*N8x@hxebHsXii{X^tEz70)@kEVz5T?jD!gOCg?n*aDo*- z#r&Ak$jd)y8O)VlPkx(424BY@0&&nVm*8Dk43-*Sj(AR^?nU)CcfDBS<)aIcc?F&q z+2`}*>Bq;RthnCsCWNAk0j^;C4LP5KAa^dfrJIk=W+3nGLR9%KH|M@A-JjeG9s6!+ z^IUulvEE38tUd0LnukZ`3uW>Z^!Vq@faWfBi3elxg%HZlfY)Go`2{->5CRziary}X zg^f2k0fmh>s(`|n0!alFs=%y-P$vF0((_he?!?`7I6a&Fq%N)zQdxy_%P1^(@*%E7 zMsc_jm7e6!1^5wB_IiF1h%%yt6hxHxmbC`(tpR&haz6dS_2#mB^r$oY1N;u&0f~MZ zh*rgy5VOcMt5N0VQEqG6!`HtkuHHgMSoGRT_^#$HBC7&IZxB%xMN&>M#V*BiyVrMg z?OvlYs!54-BGDwb7Xf}%H%829)2bWXN4+qI1pKw`!0;Jm!9!ltq##@A=L^np`{~rmHqmmV7FbTmQjvuEp|L-W`tgiU~jaG3u{$Cfw zKc`jymq><=$=GtQaSc2P{T9$7*xnCw9BI7|h9BP~jo!`yAdGIuL)@|50_-}(1+y|QW-pviivkh;yyMJ4mVhlV^mCh zwF_DLEu5p#*kq7B<~4A)R9-`>LCy8q z>^d_-X3X2X=03=pw*Nn-gj<73Va?g7Xg9mtuC}x(>a24%f6=z;?f5-)wwex)&0T3# zI8@qe?)@)S1qV!DW$R(d|DAf=_K(-2IY&LzMtIE~x`o%(%jMYXXaBM4Y?E8sxIGeH zhu2Py_`~Cqi~Zq!C+q%jW3uWGubiy-!|lnuKir}2$n<#-$EGobmgNL#w>yC2e7vWyL z@nInD{23A20#EjuK0(Ejb$$Fh)X zBTv>V1W&fO3;4@W?APtXv%o$H9iI^zKogpfcr-g!RNn3=XOCJ*<*;$#*jW6C9SEf zFUEIr$iD&dPR?2#fU=(!J_Y~KWSU0{#0) zzjZf}Lq4CtQx#qKU%EYxkexhehgfXUi&&`xrvdk8)4B~gp3p{WhHyfW)XFgGDm6%5 z&oq8g!0-+!LI?#TIx>Gspj|DJAA3=z1O5dXgYNy`d<31p;xTq@l3ed(lUuKZ+%yZ% z*JBlhXAP5ctH3gMZoCQHFN)YquhS!;d}hHg!fInlZo`XSB}!pe03YmL0n{~!m1eIq z-1?NyJv4(&0@`8L0v$U)Se|+{pn#B0gq2n-;GToYNsg{ut47g-p5U`i&FyWXARzS1%X)yoamf-P9R1{ajZnu~QW z0;lM*0&&}Oc5SK8ydk;E$mbaWb3f}QddH(|Nn@6qr(xBY)x*wJrg~^hPn~->aJbBF z&MIc%T1DOlL1(vsH8#~gV3$UGgKl(Xcvhr?Cxorfpq+4$5pJSz=Z*%O#)AB`FsK&m@o}hqrU)g!%5QzhGUje?}LYpHcVqYfqAS|}mVG9UrnOAW^ zjYp=ia9o=BjPmu$RJjsXtSkr2(~ft%1pFqK`J(Xha?1J`C|R+`V_-RmwrqWRnB4heFobU`)PjT0)*VlSlr9}9`atz zI`wg~iu{Xlfj++rp_#l~<3R{QBajQW*rNLZ=nETP#RGXC1$UYpY&=iph>>|1OWVA2 z1^G1)eIZk-`K&;$Ou=~oG{_R<<-IAg*Xl=K)Qn#z`sU8T#`BZLS%i%3SsA~feEcBc zqc4y?R`Fzyz*ctgE_tczmqk}H?`iqzbuGfTL@n@25QE*;P2jJQj<46l+zNr~jjCbe z%?L+t!4KBV?F$dwu0I+B5e5K3Cr1s1sX?#k7o*vDlS7YoyMA@5`#H3W3=cC}Cg^IJ z?CW3JPtGv=C-)?T<{&7W^HB3M+~w7}#=BMcXXx)&>Y8OEvFW z9CmmaHhiSTaT1-+=<{sHoT^Flw7hF@5yKA1%qCaiilNtb&*`Nh&B?rLcd7a?^0VdV z$ZwlJeUmPyV`aAWIXGa6skCNkGC15cL%`e(+P;A4=UQcA|C-M}xXAoG(6c|2@z0UI zi5+rm1v*LxJrGk2*bP0G^PtGSO{n#gd*t3vg-1__5~s;B9*=^~SJQI7=nW6t)AtPq zDoxx7Ls6%`vTt@KZ!CkuHtf#0xtKKlNG?0VzN|*=$EJBE)f4{;>pk>qG%xj2=s*Jk zoIrn;9Jnr{QP~Ko&R|p>><>g^_-T@yHvC?kdjU*|PkayKN3gY?5x2g=qVn6#?39ch z9>0HNzP@eVpO*0VQgBg*{XGhlx(^Uvi0(G?#7TFaqzxDy3;+b zd8FO)PL_B#7B3}ZLW%h(hgfM`ck*<`6G7qPD%uD5vV%1I3S;|A|3psG;wKyUoOy0~m0TBt&W}5#($f5-Io{aW zPsp;E-qj^v)O07nDw?iZiFRdG*wgoheTE%{?#lOUXXC{U;Sh{tTo3bFfN)I(#cNc( z7Di2}g>`;mJ*&5+=C1uE)!Q;|KN2%GUc)s=>`rkE^x}1MA(i(>`-4D$0;19PL!(Pw z8ePrPMDu3CUTh7sbR>FcnlHkwa*ma&ftm<;2iKXrC5-t}o_W8QvgH0L0& zHGCI}wcduVG`fi?Ty`(5uz9)oE=Q?(r6NQsDD_q|$do$a&fv?PT<5D`aihhY4fbL( zBm(2@)l!-r40l@8`Umu4q6O7{+&-wCY(U@P`w_%3(De>q($Mv4om>fCv1()S^+a#vY;PV_gmaPzhVI`*$30Q<#<$T;q>o@7 zh>C}aA{EQNFTxsS^^^@#3ilod7He6wMBm-m_Vzf~LRncaIVTnTm)WT;nyZ3(P$ z(M8rwed7Ty{+8q+Nb@wG51ElA z{Y2S-fusdPV71Hdt#OPz2p7Yr}|3`vB&}a{!_9 z%#)n+#sN_F5yC{hUEleRz+1ng*3miPhf|oz*A6UaCFu)3ihQj*Q4b!OJr5adK3s|R zZb0QS#^@a!Q*=GNA7yMmQ*?WRZQHR(8w)_@gp?;4UnH3qP_snzP9W3o3)PYLu}of$ zCfBWo?att1p2z=Ap46YhzO9M@HpDjvq3jbZi%)v7g0p-lxh-52Ds250lIrxLd>Ai6 z1INeV$NE*`H=T=_&Pk$l%p}(hAGKd{!t z_jADa7O8XkiZsh$FEiiA&37|pZ=IqvHCLe>wFFpK_9+m_~TTeMyL@asW5(=8D?5jsOW&GDBGL#zAy9^ z&P`9gEb%|0C$@}qejs!f&rL_ZLh(PPlU*-Z;@U{)zZmp?DD+3>rr($Lw|J&p$Iva5eB>ckhOd}+(JjX?h05A zG&AlBP>?L3S-V9a?#GaA>pdb`zw=y_f~&=x@ZsJI=nNmuH#{%$B-_KcYt(iXfFoQ^ zzCBW}G|$H|I)0RRl|@#l2Dc6)*A;L=SNn9?o5Ra@tH?ecLUIZO(=R61;zxkVm*4bVpco?A5uExyW``4~MPm#< z(R;)_7JC8L+WFd&F?ui3xCLViMt31@3#%OP8VBN&6p58vve)CvSR8o8QgOZyIK;R2 z<%~*?$ib%Byf`tUd9(EJv27Bee7O!iSGiiY9Nr$YY$bL3nY8Dg0MFr@%U6A@O_1K3 z^%A(g6Bx|?%+Iym9*2Ov_D&F|?ajL0*uOi*C0TE@!j9gL>XxTI0* zb~tPkUq#gYEDFtS2gxeK(Y8s7qSmt3Fro@m6vdYIfUV&|noe4q_y7mlD;6zSd(4MH z7oRh@3k-sU-43MH*_)FW0%vYZ6q@Jv7j%h@>s|?4eEs_w-E8q=3UjbkoSQ8LXW23! zv>6Oe+<>+$bT7+6L`xu|H4n+R;tJ#Wg1yuS{mOk44jV@N4uRPKiORwz!mwrX<xCFKt4*u)sNa>NAc)da3_^D#~DQ8uR15=k9~@H6_~zC()G>AO0DLBtHCE zh&W#)z7COGwyUPD=4K>Wf0lgA^k-LOc**TpRFGLy7S z#rJ1BAmaupZmnjtq^ z7()_g3;Xb?vjS3unHL+p7*CugKwBOpG`&s(sql(c@*%j8FRKe<8J@f3eF7+?^2Q~) z?IyBfTsaV!qmQt+abM6kxBJHYhBVbKh!u!0Lh0zE$b>rsST6b)!g|Zk2AfgyycF1Y z)sJMtk`Z?5reH5mRHG4Hhh*A}_(mWswpkmss{q|8AlA%o9iiMwC^x}dZt#}z9;rn{ zZ;9_kcCS5-?7Cv(rj?U~h>Cda2_id2S(S~Z8z4}}?}a7QDOo+oa42R_potme_ZhMY z9Cc{a;;&O6tSt73EFCfZMVS7gZkymsFZh(MZkrU-ZIfd6wh2n30fXosa9Jx)!R<8t zWuB7cce=8q$?3!_X81Ysx%kGuRD6Z2;6$H`k^g4Z#nNhGdkUWfdm0%LI`h-G6se{0 zv=BD0;$Kq^Ql!ttEDf8MW}goV2a*C5EX3B-e0+yXN|q%k#rh}-t#8>10J23EM;h#hN8_53}G?RnVE<6GFZ^bUOJ_+_Z z?BQ1T#5%Akv9b0c6m^0YxKxlEv^Xl5?nPCaF}n9#fr#fNc`76^3nH@dK5G#q#tlQx zN%qCCFQ!AcQ0YXVH>&B#fN*Y*+{x#04@4d{Z{qgJsQnT(C^w~o_mQcsESV=ZCp2DbG9B2 z=yX+dNQ0s>bGC`wHcgigWqA+|!GSOYn@5M@Q{=fY-Ym~W@sIdaM}b5A7pMALc)q z-oS1SZUns!e)(cw53xuXpLCWLV2MOq7*1Ng*l+G8C3c4^-8vhcdH@3!$8~ldo11!r1UJQG* z59mHcx>$qzG7_S%uxt~bW_=KWGG@VF#j~%ix@lnJ`ZV7*6`uDKK5qmp1e?KDx(;l?j> z@fC6+4O5X)hg@aX#2^EM_lVFZzed6KoA^eQq6(Il$xSZNHz;Sm!L;0Xn=sYXJ!c$` z)3vl|f};1aI@E^42eyW1A=0`FKbn0qz8NSt?a88|OLwE}U!+d%LKt+{e7!PtD-!A@ zEFvCeJggRgFo*cYLkLU^RDv~>%KZ?f>5XT20Z~?|&Pog|B9e*o{azQX%3Itx_e?fv@N=KK0 zOB_en$O{pHfwS)b;$EC*c!OHUAw4@TwByGU5~Qs~g&)$^gWD2iK4Dp}N0B$xc(2YN zc!2u`T}_s%CvT0u3F2zEjh@*T<^MZdo*(xJ7M7bUGX(7_ETCQZE)aasUf^JV!j#ap-E5v`@B(if zycFW^K}OaT3XXNaaZi??ZZ^mq-pw4&R*P)lEi#^yO<&vOn7I_Vx@04DLms>;6+@_5 zx-f#a&+P|vUi7UQa>m;&=C9;ydVfj(Hq*oLJ{!dhmlh4UAr9K3-H;#aN?0rS4w6Re z+`lcE(S`Q8$UYa_=b%1a`-kRD@b~%G!mw2ujeky6`ZazATOS1H9N2&@4yFLE;HN&= z`cMYGJK^i_v#2ZkMFela&%!S7>j{1neulch_YnN4S>VSB{=qD8VedJ?^9f#ppKjdy z5zMx)cac1p;FIvvUCn8Nuf$Jx?%U=Dzmwn(;-|ZoUnKa^SzvDsz$N^2<8BZERK13iA@=dgMD3O6FYP3yV8Y-wjO;?I}Xtf zxd_oNbP=LmJ}U-( z0*nA(3BOUf*KrGHg}P`<#!z2~bAtrOH|ERI-c~-&1#;lg8(%r{`CFGw*={c#CA3ULq^Q~6^w#sXMU)tC2aLo^I=5k?fY_fGDs<`POhL`!#lgK%? zCtiCy1OS<{k6r1@D+PRU;4lC+=01rFF9s-HM-+z>#h5SOZ^R)h26=A81_#n$uMM8& z&PPJEjsXlT9gD}<;oSOsD^Nn|avgYhIF^7jm!~nyfZkP|WRTOCXK2cq`Z${pds#MA z3D;f!1eI$16hCGR$5nnNfyvf8$@DqMJQn+UHoM=K)r+p9*&>YdkV}O@(O{*{#H;>~#{uzi$?oDVS3|*7Gd-`AW z=a{}3|5-kV|MYF>P5`B(VI^@1)8ImzYv(^c8k(spe{YxH1Lq$*S~G`Z5*L~i=C2qI z&3EMY9{IhlO2`TFd#U_J0^f7~CxPKs3I9=WUNiZZC80U8kH5{O{O#{KA`HzI`8`p7 zKQ6zQ;`em(F}PSIbDlt6yZnQGXuiE8e^*weENJzaM!^E>2AfdTq`Kh}fEfhnuQ~8mx z&>XVUBV%m~X%?90r}Oyxhh6yloJIVN2l=~8nZN(Fki5mq8SZQTWl5j8WcZB5p&6_|Re-*@oxesj?>{_gz$F!$#1QC8Rg_`T0elF3F^NPtN) zNk}3P0wiHmR6@cM2qBQLDGHO!kc><+ab^NUp%OvVigiO4MT-`#3w5P#Ma5k!ZLwlq zO8db|D_X3!MJp|}zxO%!KC>hN{q*zw;|H&tx$kq&J$F0z-0hiXlBjH}%Bh^Y3yCu` zVR`|kzQl##Z{+f)rV{_=5xLp1Vgc9gd~S!o*(vue7NRc{5}gBnqnL?9fkrVAG*%2L z`WFt^gvjUhBw4h?mi_qw^$ArJ1`@)TP@hnXU5O1iRctAvxLl1sFCdhM-#C)_xYZs( zlErwVAt7TVp|Sja!&EWKL6YZdG?`Hqz1J5yPv%ivBfWhWD1+lJ;&)=FitVKow@f_B zac?ndqjzvZ@_|tlx02qT2=pMwb=7Sx ze%=^D8wAb(k?tDKZ>{;<%rPDU3ejxJUUr6{$jU+)oAOEJ(h} zanFe9jP^2mUd&{42<5C2`$dCX56S&@LNAD=Dh_tGAML)J|1Rk+btD6P_AorU|^yE#q_qqr}`j~IPr zA#_4K!pLfMScNA)PKPw)hm005ij&6}omWAUN%F6ZZbv$YOqQn@*%_rs z1CvOq7!Fh^Gi5xZ%Q-GnCNi?6P`V*9O~oOHDbg+nG5Wbi*^IVmG=$N^8rd2BiBYaB zVDu((sDiB)GqP}gg|d{~70YuNJKSj2H7_ z&?)q06>i$*aGXOrtU*~W8yIEgIjr;XJ*o>BP0c6CN{Q1%(!#wmPU8FxXg~VB3cuyq z%IFF^p$QTPR%pW*wwDPKM<9?)96@pCYUCPAXo|$T9dRjH4(oO~MdEb?K(j^@s*>v& zImZ#2DzO@d&Jpn5Riav6ZzRAz%P~_<1Nwns$xjveSd3NSyX7|+7R0&WAF9L*c{3vi zqguHoLUNYeYFLrq4KXCyB=0gTK)GXu*e@5#yA1>RT|7YGTd|Aej~JCD5V{bEBuBC2 z#TvbZ*`*4jcDE6OxUVaOm@eG%o{0S1^2c13%eXA9@&QKU8MVnh2CZHWqed^_X6GT+ z@-WxPBOf!yivyKs4IVE%BZ;0jg6P@BM4fp=|5!-$&M`!9Vfu=V!Vjkqz0g7Q(m_OL zu!egr6yD2vW)Goo6Q|mod)DB5af4+;R=$`%subaShEVv?A*F+3W2ab04_>(brL=O; zf5a25C?NVh8_|agiS8Iujt9u=t>cmQylhJQb{x@j1`}Nkjuh9Ho&%YwmFEnO5r@jA zgfyQ_u7QTvEkqZT5Z%Y&wjv78$tC*Kc%nO*p2(u`9V2QYG|U9&-DIL4CJ;TpjA&Z{ zQDXwpjX6Y{2Qg*-mT?qr7((=Qj$K+fb8v;|7{4K_LR^?hG?l|cm`+S5&RHCGbJ)h= zg&ZEi^hX&a6J&ZGYuLhJ2h%Q=>EZC#Ow*ZGGFADyIed&I|Hbqy*7GKZt2s7{!yhm` zkVZL1migp3;{28Azd80xrVU)$qa1#N^^9lEHLOQz_?Y<%m@3ZgDz6BR;z#DF!XKPQ z=5+GJj}=bTj_ByYL`z{IkEGWj{7}gP(DaInK&R!B{roc5iP%d@SArT$$1(p%K_@t` zj#v$PvUn5dPfKnDy?NwqNLw^wH|Z&U2y}GuQ=nqRi=d;54}g}G{04MT*%8o!(oaFJ zDn0?aapX6kdxzVGK&C7m^iY`{o5m{~`JfLw#(=)zI2&}kV=Aa6e?I8P%o&Ps|Mgl5 z{zD}zK+`LHphnh)tnu7;VPOz$ zWB!bY*gzTaR~HbCOm$2U=lh&C9%(HoA=T@f^5BqS@pF`?SbTw!SjDf3&mLkG6L>5S z9?=b%4{fD`tzv5FmEgZu(uo$kbPV<5_n9uur*Kvd(cccZ4)r}<>{$snA~tmhNv=X# zDOQZR75dLjqJDpVtK*3J zvxwd>i0GVhqCI&;XIhD#UqJNM9HKj!=Eqa`EKn*r(G$s3wqJ5xcG#$d+bgMTV@FbW z6iP0&jI!j1N}fQfhf1CY^^boY)S3AU)S`04uR(`%s#QZN)enY}&DV{5cSxEzcPx#C zF*eoOD+hxU^9Q6IG?4h$4JUdr`DF1|w6=LW9v&OR-$%h?Dk^fydNKy84DRDZ>AzUG39gM^U?1WVb0Q_ zov@Q2hWUKcS zUxvDmVr%)R>}-_n(_yxugTyq99n&7N5|f86T>teDqW_2|nwUT|GbwrKSTVCC9rXGH zJE+G|gq0+wV=ZWfaW&`##?7ET#vP#d8TWzy%6J^~pT=|0a8~&npwuI=qMUNn^Y6T& z*TE)pn5Kf7d~5cN#809Tm8?B0jUf$0ht7 za+Kl^kSBXH{gvv+-wsFy|LrlQgBxfGB{tbU7!r$xQJY4_(Be2L)@#%mM`*i77mXsx zM;P^F4=Xy3hh^Slv{gJg;Ka}vQG?Zv5I1FyDEcRIIZ{MugDro=H$Z%m4K$!Q9{YJm zv5Lzn&IFpG(W&8iK+826UOWP5y+(y4P_X17PsIY7`&~l9qmR$+7ULkSW=xc!P)W{NdgFQ|>tkF+1x7p*xevRrA z@31F|BO2X1^d5V%__s!BaSsD!p2fL~YexUfo+c_a`X>8DoQ*VTbl2dY*)xS-qgOLi z#Xzx9qb;M~#97d8jn1>ZY0nZbYxMp6U)!_AQH`D%{3ehwT;-P&_nv*Q$kfQ4{HEP5 z$~F3B%18DbF;$~?kYBE7(rDHAPwjak7(!p#3&a*io5X{;RklJghK}FGCh;?%VsW2F zLkh675(gReh$n}hvX2lhI>^Ir|H1ri_K{+XM#uAQIitiOjV?}3%NZ?ZmMY0p`Dr<0 z#BPlSr);y26?n}*Yw_Ds5-LQ4Mjt0l${r_%(Xljg=t|Dc883D++A8V>*IOoteHz6k zudz+UOiz+q#la*(#~E!BuffVEiqz2*w@D03o|HXNY-F@moXoMLO%gjbN=&q*oh|TX zef;YY=h^de&Ji2OsC1JP&&oMp?A7S1__K1RildBr#4P)moN3|`>@O&X7TY#^tyrVc z_Tg2w**N!5aqpo$>&1SJ-btL8Gf!lftGMHdQ*#={a*g&RR@oMc_cVGQXo={=E`@UV z`_OInrQ$)2ehqZ7cwM88fvIA-SX-$iKh9p4;KYn)qB%Lu;&qL#9=tBWC5~$J#gL{P zw-`o8vB=?>vI}xr#ZrxaShmf6iNLeg95-cxGsi3bMH?YV{yKJ>y;BV1)8$R#VD=?B ze&G$FN!dYhRHOF6ld`)68lTh6MJufmdnYN>otP@t2wYO)UyoQa;Ujyu*sIaCnIG9N z6Z_AhxDBEemVCMRS|e-8r8#TG7J48EanF@pma|Swp`&D=!^1b^d{69S)FZ|v-WxHE!454Ro?h%JH`gmZK?LKil zgr3QHP)wew@_QcX9um7k=$V{H#TOc#GpNe8SJ-Nm%TSNYwTlAL=~>|(S@Y=rF|6OU;0#Gq91iTH&^*V+f?eky*a(Jn~-S$w9^c6(m# zaUtfa+&>&t9QT=UFxnu_8(Nh6nV6zcuwA3#Ghd-cN2J=m6xK$C{!l3KjO2Qa=8dVy{Yp%4QgJh}GW&mh z6}kTqr!?AwHzs^7vKJ`HaU&SC@jROcauglb7FC}8PsUWxC?TH z+^kXc=w(2=6|&uHcLBYq(Zlvja;1D*A>@~eyZfUd6eFzi%MePn#mLxZDw(p#SZPpt*hg}QO2;Ki3;ATbtk#Hpa*k}$h<#?w0{^Q z-_wZp4`XGCPidhYL#3Rk5$zbp$!j#C9m9C(x>QN78vmtzlC=5>^@#e47jw^+UX6Z~ z^H%O;d0$Y)ojX$E)?mykmCjp0=<9A3cewa)?i6|8GKI?XKgq3@JJ%DsN&HXw=RgM- zZ4%U*HFEO?ibKDnSEk9CR}tzF#|M0sJ54^q=q9nc;y=05W#=Y}yGi^jHz{wXY`R)W zUT81Qn=O}bCbUV=ZmCWlQiv^bj*RpLbL5`ul_dFsIr4x;U>`>k<~qGL3$VzFj2G(}?`UV%ek-`H2hUB^r^R zSSr_R^!v(%c^Aw3H2PcFMS08QuN2}ITrQ95IPw$A^IX4%x~%a6eojXDVd-W^i%b6|zmE0Tn;V zyF#uHNp7=WAzxGVdfrC)ltwS* z|0?e)c|@Z(3LekfBpbFXEqe=olXtbeL!*RL+)l~+Lg=g9Yvof4aXG&)4=RK@Y_oq~ zI(CqjjpF{i-{)cx5}LwQEj)$qZ*B~{UvX^ zY}iTZdc<{D@9vOKF?tn00sK|&4msrxilY_FHv4VT#b}er82e@3PWhfji?DCJL)z|S zNnsm%D(_BtM5CwkERG+_#XnSW2l5geyW|l@s(yD%>n@7hgmjsXd*l{ID);;3@w+&V zZQ_2Jd3PjQ&PZvwUv5xw(30cWBe#T5k>erxGNT@GG_S((m^|x8q~#_tDdAklUfHQp zWMCgCx0CtSYXz{6^MjbUb;3<6RjHp;MOM$zvLQ zIKJNUKXS|-mF_R&*VvB8ofoxjS z^1F^$W6x70*&|*V^sXb$xaMhvt^=|e>z`4mviw~~yfO1<3e^H77$-DJDf+!5(U`bT z#TiBKI+Bb}HJT9nks~>(4k^7*@w1dp)hNXnABAQ`p^KwXR|tLPNHMlB>Jg_#op7WY zhczl6dcu)rWIm@#)*4%AO*f`!bjOgBj&$Q1jsBeZAD}%NeVA1omth=Zv`JiA7@MDA zOnjcpDYhph0X?G84=d7v#_U&dw#;mx%^Ka4o(uF9Bl1$ifCj$6lI%4G8WTgPJb$3E zpHYu!id&a3$k_Oz()nfOx`ZramqwMN*Ck{d`!vcK-IO!f*#44|{NB)W@`oCWUnaCw zyl0u3Z#Rx=ly04ypJz0^qT>E&S(;y9?APc&7EgYWG4oZ5yGb;TU6p^9(Wa5letG_I zV+*6LSV3H!KgwADn$q&`vfJ`2jkT{U^l9au{IjF_c8YQ24c5u`BvXvzj5df}S43|c&S=;PWjqMs0R9>1>V>sTVbQ?u^ z<(v7_jO~nGO59%fPW}wz5sf@$vBnJJB}T8xCalE6Xa}QLIZoN&4C4bvYW&SGjwvk( zN+e2SKG$R3fWGS7g`q?AL=;T11&PXVDzDE9A+(8WMsZWxqm3P4SNl76B)h4 zEx*WUV6+vx-6Tlf#Yoj}k?}K)sI3=8we=$75XY&uMt+P;ownalexx%UI@f4)Z>GKA z0%Hp!mBWR`1*5fqRYD6`1M&;);KH)f(pVJuj0i{zqoyIwgRH>cD0*(69(!p`2mTMSM zS;iMQjn5gWQag>WLvfS)#4Z0VFjyN#NogjC78jm3;q%Xb@{j7UqMpgYQz)*0_}oNC>5#)*h@>x`s7 zvQG9(>x@!Hq-9;fx+pC@#;qKuwDcH{FjBeq7_W!YU0u)1TIp)z^-n1WHEypqj(tW* zwbIqbS$`puKO_}{BB8_Kp7gwbDee^_v>E{i%Fz0PRnbfhI!TxYCTNIYCT+1PAs z*XTyvk8L)d(kP?!oP^EBdyHNcl*4AD^mEGaRY5uYz*zhRp-ng)Sz)=+*rJfgnXoS5 zCgU-UY!ikWHyZ~vN`v*>V*E=XUQcW>lK!f+94sr!-D0>jy4OA_dyBDMAyF8&&3>!# zsz!7Ivdwr;ql8r4s~JguV=dyY0&m_9W3fV;hqvDPzB-|yIw4KJTzf)PZijuf`%N+(kJP&l=pnA)l zQ91n3*my!o{yC@K@X%BgXuu-{cN$e5}TX?fUaQb^FO{ixyBh%DqW<4TR_RP1qM zyGFmS{CmMqjr|(^t?Zu#PZ%F7#P;%}aZ1P0IoOj%<|$R%cPig5c*>Zp(WhmvIHXdfATJUF4t@|_MXB@WyznPa@7#+9IcuB{-E!HLMi%R#b z@s^HzT4WYJYy2%Dhv%XspEJJEl3$9Uh0huB|E4-@5Zh!y;qxIh$QWL@KZMRT#uUB~ zLM~%M;fo=3opD~_OGc*F@|ZEL@a0er?;CZ6uNZkc&T45aeAO7ih`ddX<27Sy2xU6n zFcySRj^lvg3n4sdYFw`nkN001cSgh=G=9uTwdcX8+8#6>=eP}c8OQ~N(Q$7X2X)+5 zwC7t<>3(heUdR0yaldA7YGF_NfbDIKUX@=a6vw?2LSG~}3&ZG72`dZVHIB0us;$59 zJtOfOwilqw3O_(PDFSiy4Y=i_Qd2D=W@u`vRs3!U@f-7rj zICC(`yaj3z2g>oSP&}a+){qFD2A-uO4uwt4O8*tC?R%UfX)suWMT{Osl0Q!-s=`Ws z))w`s(e)$B4uV} zhs(L6lER9r+*O-AiMm_G6Y=3vy)~HHJlrPKdSQ-gbIKRLCW)F_@vJAM4f7+zmZ(^2 z4U6d8N8z;5@+y}rxg{fIA~}7-ibHiY+c{hpvuv?L!)2zhs!M;d^%JP>&Dmsuudq&4 zlEbn6>sR@PON*xs*#?xIkOfM%#%TH#x8bA$>UY(H%IYF}O4UMXeui!7T4=Viwisb^ zkY;5q)XNq;4Q$rYtk=+pQKNEE+WLkSC(KtGBB?5;MI6Jpu!`Z_8l(-+Q=(M(bvm}F zuzm}kQl;1ji_AKj93@YAnVie}$o#+86Il|o%&NZO+|71VW&2A-@A4~7Wcd{*tid7_ zC$jvvlu(P^0UB8bi-_b$>Wt(^YL4WG^+%UEhkFNKvFMdoBwtzVPVT|6XnE5UKEfWu zKc4za_1(qn1Fwfyv53LwFDdrHdl+IntQybak0j2OY~dHe6G}0$lxRNl6%BB>VFdAS z=5RX7X6mP~#53q7HTidNNg`=q8CA}uJg(0aHuWpXNJ`HPVzhEQoNcGDqN;tyamy%~ z>o^z1f1FeO|6xA*E;CUv&rr2oW;LVH{Adw(^DLmeQ+yfq$djnAMZCtd)p71qWgAy> zJ8b1%Q{jbqBu`> zSlM>pFqJ`hBx_V!>V3;;IgwT|iGAR$Y|nL^dZ?F*mF`m26 zOz(n>A(~k71)f2u%}ou;k`-Uo@pn9al{Ztls6P5Gw6FfN*ecX)`$rxxjXVc^hOi-~ zVlI=SZ;q78Tq8BJwJ6Qcb6q0K7M7Iwra?HB7hx;DIY9bVUc|w-tzg3@ReU9LI{m8F z|6Q!oAD2UxP=GOF#rGEI4GtUF?~!H$-)i`8VpVyR6@5>Vo;9ErLEiwjia$#Oxl|0M z_j)|c^;I$yYx-@Kwl7`6);@x8yL2)8d zGVGo33+#}IVVT(fg^X$eH9C|ft9Izi@mr|fXcu6v+m)p9WAzvp7JPThv`j-pa+C$C znMj4z92!Yg?xfAs6IlkOS;^F4kAPqB8bH=1xi1u-R;L!dI#nE6`B?CcFDjK<^QbZ_ z`VgnEdrNX!AP(tjaP(q9N9@@<+)QVlTRSolVA!F4$FSV!p z^8`w(_61eE4|)QYY2dqO#E+ai)cmC^;Q^ktPZt~6!V7pDMRF)?umwi%g_V9K`8Dr< zRqI94$USB_Z0Nmkn4|WghTe6mepIyYSo?2Q2+?ai8dIt+rXP5XEkw~)p0oZt8lIJ+ zXQ*=C2SvuN$^n`pGXbj#)N#T6Z1ibHsPOc|0tzufsbRN?sOr1gFuHscvklHALZ`^4MjC&4L<`$l?XQ)R4i zmwXmauzCfZZ+rP1{biOsz>3W(P)&!i{>g$)_;<(!Wv7^CT1zF}Z@$3#OF3;Rr>z9VGaX1|vQqZtWVT8<|dKnkf$?Tx)T0c!z8*TM@ff%TSB06?E&cmRoNr^Xr(FGPN^p;@Bn* zzaf2<^_I7|P2P}~SAG`zKAzo575B?6cv|Ou`C@rq+$ZvSJejnY+vumf-|hB1++WYYoq@4+tQ39_*NZ- z*V+afONuwxh8v3pTyHx7$p;WVT=od)ym1F@@x~R%Ww6m%ni@ac7+N_b{t(yY5Z5K% zxNpqF_;{my!ujz#q>)n`cZmDtF!#%0?w7H~D=G8h-x8Z`&?BEtbH`6I_KxX@uQIlb z?TR03{0UEAQaPWGKgyPHoYS6QJ3qnpFxV)J`#63tYd*!Xr&x0>+9B0Oy>JpbNdwiC zo~k>5?;0j?uUQRh=On~RJV8Y5Y&EFOlQ^8jeVSy@SV&?^NYe5wBj}cE7|UcbKa89*6g`Ag@a9(>;Q8R`Mtt#Siha~s^qfSwKh)0xm2=DDa)6# zOdW^oIJ}g@OI2D9+c`{D{ZrJJ{J=1#l}t04)-YYlw3KNbQ#;cprjwbvn0lG6WxA2+ zFmAn4O{wly4p(w(XL2}`+r-Y{8ZK2Ow@;-(9%iyZ9xRhNHO#4FP7QOKn6s2QOPS+h zj+Z%g%n34QEptklvynNQnPX?p7Ut|^P7`x>GiMKTT+G?aoPErh%$%2*bAUNs<{Vk$z8=QmVH^(Xwq;wg z(71!&s~ne{DMwXINuI}TJ5MexTZ8ac+xp}lK_jIUl2Vi^%@(#C3*FOB<}%c98R|Iq zCd-!zpU2g4c`7aBH!|JKbPLm+Om{Qg$aUYtdF|!AD%pqc zW6sOWIl#Feg1i)mxrB!;G&&AjX!ITCG92aDqo~DDgKGD1%3(`&*&8WGp{LGzob?>H z&`g@i-X>GlmBnCO(>>k^3;EI$tl@rnJo%L61nW7$X{}c31*?_PzAq=1S<>E@mQ)+) zTjTTMlB`s!BrD~T$YnPjDsRKmktm}Upxmp05wJvhuty=iBeH(1*na?|+F@WN;A z1=dr^dMa6_l=V#J*vTAQ!?86SJDFq2JN2aRkmn9rm#{-tGTmsq6`a3i-VWNGwJSZ% zD9Qav`Vu2I=kfISB|Q~N{HGCHFr?7BL+&2=9KzlSmb5zL@|NG~Ad}kveFPm8@uwl`MacmF#Mdm8^OX^fwLK3;n*decX5Z zxbOCIUVFHXdr-n}YK#jBo1eC*v_NU&ZE-KqjEE+orKx8IBpoi-^k5uMVr~81_*5Iurf~*#e;2P zxp*<#hIe|s2HGYLfO^GSpq=73ph59l(48!^i)D7R%zYfYM;t-yBjS&sd&Q@qPl?Y# z_lXmr`^8Dn*E#J0PJ58k9^$m`aoWS2_6Vmv%4v^r+T)z|3-Jv!oDde2^J`%PjgeH& zG|+VMw0sdSe|uI^E!JD878@-TdyR!^vDrekxY0tj*kYktY_}vsa;GI7beDxnzT1+8 z@O>6L=pIWx=n*UFIcg<6$E>91xRvyLVI@7wW4NtixUFI+wv#zQaLRBWO*BJXg4ZAn z6#>vfaWm*haXV;**av!!_yn|Cd=5IB`Hdp3s0_cIO#Bux7U7lRLePL{D|!jvpMNd; zBc|1s4Whf~C8pI@4l`|uqkLaVBo5x%LNZJ($rP?mz7DY)nEr_AOH4mfbO6O#Qiv8Z z-Cs`HjxZG!6m~G3!gM*)^-Om$-Ouz0)8B{>@O$@v#&?w^b~jnFK#r0VWworAOQcKs zWS6{LUL~)SH_2`CCHZriV5AxOhTm9cJY_s@95ae7=UW;ri!ENuEtdN%k6PZg{KfKj zi(!qkmRToQms(xc;+Uy1wK3f>TVj41^NX0@#ry+by&M-iBep5_;@I}s%VU2KyDj$4 z*n494#6BMTdhBmv562#h{d?@m*b#BnakJtU#9bV>I&M?kjd6Fy?TybDNm$4m-2SX=P6&MoJz5z#;4|_ z7N?F*otRpcIzQEux;k}J>WVd)q&=4QblU#3 z18JY8eUTQMUXVT|eMx$A`pWdH({D(>H~ppbH`4!>F7Yc$xfvxH<1(ga%*$Amu`;7G zqbp-=#-@y$GInO%o3TIRNXChbjLgc+MVZSp+cR&-d?53Y%%?Kn&ODO&r_9eY#|^w- zple|J!0v%P1Fs%<{lHrX-ac^mz=sAtIdK2LHwONC;BN;W9r)=$F(`h}@ImE+0)uWI zbo-#)gMKmy-^|R~l(i-6zN}}n4rYCr^+{H7c4_u`*-hE5Y=8FU**)1eX5XHDclLwX zdoe2Et#E=jM5NkLC1qBe8XYQ20X=3P2>MXT&`|i8y@)xb%%O1N5XwEhVnQgK5>F-BS$Hlu?Pa~g zO8yC!QL$f_S3^?CpN{@KnR1DYReB;hcjc4JG5ZW?J5)9Y^q9So>0;1_N|xy`^_B(m z0iDnr2;uh)(R=ZrHuy9Hp=8hm{16fDKQL<;cw2P_Xfk@$5Cia5UjuQ2K~vGMG_T}< zrsIvi2ITNVVImX#YlyeeyHXqiHSp%s63`FOzf$}b)DSsxB*M9%hA5PyK!?fE;1q!x zc%SQ7(0Q@~bg3K%x?D~`tP>PxOmY(FVR;Vdhw@y|KgjbzkI5>?d;)5SPh~aepXD^r zujLHTQxd;ZBMf6UXreI(G|iX`YB%PAmKykFTQR{{0D6wG2z0Ws1ayjVA?S4DBG4Je zGSG#F6ZAr(1$3$523=>gBH!=yXadOX(aB1e#*#mK_L+95qA+e{kkKp9Gx14&9b+p`c+z0lS z8;zSnye}QOc;UU;VdEY6^Wm=(Ug=VJB|m{X)-`PgV5%I;wssY8uCj4#1-@W*I0)MaK z?>G4S6aK!!Uu?=K$iHsflKQ%FFaDm!-+|Nx7W<$@_`BBfdX~gHn+<+%GqRq1-lS#A z#*SGwMoeDN>2e0$4Sru|;Jjv&d0xx1Wi_5ar`OqC?R5qM@=E_aC2>Gb&VD*UdNV3*%r+urF7 z#W-El{l0d@xt;Bbxp=IqDT*JAA7<8r>~HkFR5@ zGeE2czuV<$K}#WATkZ3DRjfkoold{oPhqVl=p!`K8E9*C2NA0C1n2`rbK{35oxwJU zb_6TR#p3c%2@yJd3CqRwu8tPGcWSn~o7Y|{oO!~K7Y{diegcg<(y@? znBxvQy<=DDKsf@7D?-^Lbo%VWVwGnSLnIj%T6El*#1N^)#-B+Hky>oRnZyvO#U`Ff z43YR?OCkwc-`~eE12zvnFrl7@be5#FEiSg;g=g4yw2bXpT8Z!X>+IJ zr(RtRZhyen;q)$Ss27dhfuOs+tah$g=<~F==dN=5Ya2vWm&@a;^7v_-Hh3CDgVP^y zH=)O?8k-bgTOnlHO(>?;h1z&lc-;OFtIF?pb`x6A;R$w6b9rFKWuCc>%WBK(d@W^* zTYN5e87e7O(TH5OOjP^Y+nu6)S&b8KT0z8gRZF+u-O=JUnNzzwUKhofj7DFVzr`J3 zenT6Eml-kN9XMT7wXd_Abo7&Iy5HIEUhVU*>?f|V&F%Fzw)j1r!Cu)du4YEHuVaO$ zwac%%Raaw%-`CY?7HXl>?{Rhn!@QO@cgsq*-;AHzdG_RBP7>XF$hcaziK z>Q?D=79790I;u$IILvf9g}c+;fxc_$W`0C1rga4Uiixg(v8irAiPnU;&<)G&fbqbZ z!Z9wYczdA5=l6P=MW7kOq(#hewunGi^9rBW<@Psrx?4nJi?d^HC%h!=f*7zKFqLJ7 zU1FeYh8sB`s0aaswsCAA6j4oPVYaVJ)CL;h z=I8sM!6m3L9`HIaaPZmEh7mEN3nAqSs2B`an1N;*Gdwn!-@;bP!GM}~IINA0!|ltI zc_@HBj)1G3!IrjZYl7~M0GwAuM38NelhnIc^QU6fgp7=ttyEU@WHl9BHxS^|ZpBc3 zj%q;@Ft;rEFJd(Lq9EGXdLu?2 zeus$T7uS>28D!ay)=NB?RN+GGe|Nk^#Z67PRQA+ z8sFK0fU?5*9G>b~=@zglj5r@cQ{Ane4jo3b!;g900s|SeR?Ql;@DueuHA^rsmvR(= zRaT(W7hpbh8w?w+M^9@Jt_014CRKG~p$P4a!y|?5o_m^?!Gp2HA7p_V zhb+p)3>Y0*A!%Vutq>6=&&~Xx86Z_yP&mEJCN#avt3apUy-F{j8|@uMAme#Jm7mUU1EKn1lYhgU=f&=1VydAS2afmebEP*OPb zI?VL6Mr)=|FOhm5h^L{AKJ*IvfzKsj7L|kpyu{?t z+!g$xJp_lLWZD|6Vc;=n$wBib^P4a%J2<3W7KayO5rA!2N01TKB8s7=;wB$TUhV93 zHha8SrkYCDs8Eoq6Izq_$t^_f`mj<6ZR>d2rxiG@vS^eDU}QHn}V)z6pe*2s&O}WwYHK=4D-k( zwKsdao5;2F!}dE}?slhtWjHFdDhabpC1i*Tu?51CrEg@^oZ2^b2H!hE;axrRf5aJ*S`%*!+l_l+Q< z@OxU@`i;UVLPvKv&HOI7=yo^diF}l?hhwXn13oWx7)`_r=himxFyxW1LXB=eEm;B> zL5i`U*>hDMfCQ%ZBWnF=PZh}6N$)PF+6{)eSd9_oW zA*uD2*$K)Q(BV;tL-NSGss(lwz`PXJGTrSrq3R9P9y`OJ7Fk6H1bRhA<2W$28v?XS z;9Zfsr3>SFl_?RPQ*m%GKNP7JMKsW8zZ|j5QaOe;Z5pb5n+80;U>PeKS9&^YR|uNk zYO!rzGj|2er)n)O3}55* zT*g&9Q)F$svlTXhO&W>%%>dh1H4bvTzE;vc&F}a5=LA}XXAy1x#Z+g@%2pg~b-37F z3Y3xDCQta7M^usN#M)dvVeehGn1(B@6!{Zwm|*)dWdRg!W?P^TtwedF%`&~W7dqjz z@UDYKU2oA4&#wnPnLi7e3-H%(yG-u?1cA@s2b07yuX>+9b)V8u9oH@ zuHQ@*pff{Oi&mtKi7o&i=+MamS|jYsxFe%Eoy}_^1)>WV853Q;$e5@iMn)(nhk`{p zRMQ`EN$D=4gZ-><1=ObpCvR-QEYON|btiQhT2TemK7WzN1?Fm|Bva?^Xaxg15Bk7v zIzY>J7>?5)R6&gFMvvbkXyz2Y=1aI7Vzt}3Qd9-HJ6fupUT-t(PGGO60(ADk1`I9W zv(ZN2M%PLK*DZqhYhM;xDB9bR`m+!$OQ++btG~aOsROg2?+g+ap~%L4EF_ zBdITG)5vzp0pzScBOE}Ofy25ERY~S`xL5P1hg87s=#0OkRn-NXCr`WZ;P#}Qs!-h( z2qM(%3(^PWYu?7d?7LWGst+e3&JI;X6I2Dv5KW6(B4Y9|S&_3xh!(5q z_?WLh+$-SP+vYes=_Ds=g{01pNtV~6qM1&H~O>cZYWw5{TbhEZ*R_xNE35@2r` z#;~+7poW;+sP|wr2KlPP#H-ZaOprWnt3s>L78Z+Z+$~No`>7Yxs2o%s+pcHg91GgR2oJCH52W)TJniegUi z302)0&cMW84JYRIGbD@TKQZiQ&}>%`R685)LY2YnQy8h~>VYG_tZoi*?pQ{S9KTxF=G zgu2#%f$1@f=^IIPPlwM8=QumChW4BGND=_oNMo?+#H2>Uw>>EEelU3)p%ek5H3u0WQhR7DQ@V?4g2m?~hnCAlHLy z79O`efpR!fZ@Dnrr>4-?%Ti6|>fvwLeebh>Pgcr?hjS^|4i)p&Oj=IXm z9gtccfRCdgI%q+fetZBrV8+&0_}PewhV# ztIq$GBt|$Lf)MECsj+wpucO14cC3`WCg0^?F+~#zb5(#!*kV3(!bd|P)zpFPiFlL; zL?<1~2Y7W(4pW`2plPt7poa$3a{`$1^{G?n3|BP+uPI;)`Vcn2lkzHc2C5|ZFfCvn zPo1XZm;pL)s)oavE( zvQQ@l_+Ux7qX;G~L4t1F#na|xw}o<)i{_F@mEP7DHg zxTzCPpN1<^@p7cG6Ss*bOC2G=TX*^W4L&p-{!nvDg;fmi%&NN9Fyu!~z>av1mKTDm zsX9B^$zTNX8M+44pOLrOXmDCsnM$xCQ(Zu-CMpE&PIcR2(}iB*DLNqNK@EOBmkP(n zHz73BP1j5cs-j^sqB~$5yaY*wZacjbA|Go8sdOD^c=H)G^gT~PNadzG$PP}gmyM`q zugy4_Z78yR89f4}4^9IDk21oOhaNmYF`{5CKhhJ$qVuIF2JN}%C^?GR+c=^k&%DEo z5{=%sMMd$3CW?c)sclyvicQUj5Zrt}o ziK*RNZ!T2Q8EbcxC|!u?Whbphct@kGjSoK6!;*>-;d1C=A%Lwuf8btvspv~7so(pT$mLTQGpDmZE}P!&?-YGeY8v0OL+E> z=CK_f1W?X{v+2~~MoeT-hlf&elST6UsqT_E$SY(H!Doi&2+Bo?(t~`;C-B@{+Yx4? z#u`=yn2S>bZQKka_6RCE;@W^2DnD9kV8DfLuqdoLpF*_LAwxv*)Zj7!MW|&u$(u`d zQz{gLI;$0=An&Y$U~=B*CCnh`9?e(X*Kbt2vokD*>{L>H#iWx5*)y>FVN1m%6A0jn zF@REGGNG#q3VPiu(DiOwsw&4M+Soq{z6_`2+NwFoM-eb);p>D7_+>nILSge66fD@y zX)DC?1VX{uKpiGSw|}m`#?y+F?Ab+a6`e@qdgG0~*{&vD zxr{CnJ4{R0fVxAmaTh_cVatF$J6+mJ)IQS$5#}QJibWZ(86CO3q)i~M^CJ#=Xb(eY zAEA>UEkZZ$kz8}963J^cCyq!a9)7?bZzRVbp`1>o`FRqWM6?6pZIl_t$fnZ~!R-|~ zc)}(}A3@PM(YIzy0}Cj_`LLI}-`O)q8FsXkiaX{s?> zbJNpynC43YE&7uMaQ#JgNpliAjZnZ(oCpWV=cbq{{isg|_SUc>e7AzHk@@V0MgbJ@ zhh7kbhc?y)k=qX1ylFvlm2*6S09Ikil*%y%b{igcSH(yLlKyBg71sI_tkE* zFQ4}hoSasZ9B2+NCK>Yyv<~qHwXe>AF?>-J#@IIRl;FkuXpA|i8r^J|i!eHj5Q~|T z{nNIVIP85*fLxdf?fe-eiB;sGf? z27SWCUuMwRDRv*fu0)WV`GmUi`g-``sVhzw5s!hBi)s2m9c@4}V`zumO_9p)M)S-Bb)IHFz6cZ%*@{ttIZO2O><_VN zNlc&Wxt?%{cDG?f4uuf@*b@0^9b)i`lLF@90)=VZ(WZdH%GXn9CH~lK^;*5EgCsk- zO3LqGaY^onPGACP#?bRQb<;vO17ZR8+5JYC)4P6tk}N26JWW7*hA@wxU*X24FHPv7 zGmXQT2~>b)oJ+glzk=O76Lr8FDujLrABEv^(|i_D>*1-qcEz;zPNb|2)Z-3$u3sUf zG{+I;9yOBn79yG#F+YbAVz~4t6d4~1s|gx#O*g*xSJZ;MLh8V2a;ZU@ApROSO%ReTp|XnM{pB(P z((RC|#$N|y@$56c`rV)8OvE|SW=bc-k{#;K#TWpDRWT&sGjb({tMCi z_4rmlwGc|1(_ihVPI%A7X<{3ZmP#V}ZM#L>3uL?Kfw)CzrE2;jaG}|gs&C3*ZGPRi ztI-O6Sdu8|+lT$i70yJ8a3A(7QxxvOGvqib+z(CA=|itKgRa47>8E`8s)f&>Z(Kds z+pN(vXrfl`Kx?WI*{|M08re86&^Fnx%+UV&Nw@9ljnJCGNZybU~epLP#` z>q1E#Naf@7?JP}R4igu6Y82zaZPw_9WV>#iaGGXlcAzDu;_VlW{iG?2@VLU_5Mth3 zjJ0I~UmAsPtU|a3Xg*LQeDMN=syVz2-$1X&UlabSFg6u#1SUk7LNmyFk84DKP@7P1 zjplLOj1rUQ?gpODVHz8z4FO_Kr@g!EFi2|F-&RZe*8>H62Iz*3{ooEJ+WLWvxlJtZWSR0y&l2U?Qs!NGVH zlqy@Gxy6I}t19%LHR%aw?m#bhK)xGXHFg~67b+UPpFmlY6Rk}niEKICd}>sgwthC^ zM0?Y>G!m6wHI0{>i8NErln<4b8qLhB3}_Cxlp~E~YL8aPkhh?+h*8xjJK60rSY0h_ zkL-9FDA{Ne?2as2VOV88NiM`+9a1%fV#sc%!E)!|B@eK|G-VJjv@MNctP=9-kt6j2 zacJb4{zBDUw35g5qD84()V);FXc=l7DtB)_)rjgGEv@{;3TUEwb|6im_XZx;CLr8Ze5fr50dxG@-3%wAX?sEHJ)|-ZiEdlH(=3S5zUN zW;SRVdt~;MJLTL8E{$i?R!NR}kvu!KfCKNR7$erB{M9q5hxrU==p{v-y{x`#BAexrs^C8uOteJVae+ z1vfT}v>v6^TW`PNQ8}ixB8F%2AJFrT(p@oQ_=m_>XFaLk+}jhSEQq$q4%0p zCXye<86Z-MG}>=PTE8eH+r{Y;k5RSSqY_1qPFX@N-_GTAqr7Tu=V3n@sY}MMf((^W zWRL|>8L5Wa>p1%x*<=Sa_fxr49cc&M!kAhuTo%>h)C#mtrgYS1suaY<>J_hN=<7TB z%Yp2|qy4B_d7Cx<4!KN<+_#qDy=`Z~BBT9jZ9nB3F2s!QTE6HOpv9X%?q8A zb8pWLuaOpxReLD0?7QaMw_R2uU-I5+#nOMv%O%tXO(-SJGX2$^=4UtC%No4x?0?Z> zdCKpP;@+ltPOTrzc}iwQ_pZqo1J!!OTmz|HAx`SQqkYiQm`21X)LhMk{ns3QfuC>s z-_%`L@WUhho()CUgnFFbf=M-oPx@b2P6tX&t=5T8sz-NdR!3>)eAgBruMiCFZq#{5 z8El~wqfVWip;Q?(!pRa>BQF&vN6`!yd9D@hlSW~UM181E%j6OZm~)oOj$AH7;+LVvpY zvklr&kiBc~y6C&6BVBX`*@d19qIK|Q7<@X}TBv8Jj^S0D9EY@(WgXOm9IeECkko7 zi}T`Xo~GIh%-XbK;SS7_%9L?zhGcAn>KA*&TgTlS{ROV_v zy#En#YQ%`1_Q~RWEJ50l%z@!V%FP3URpbK1sVx<4C{>Xtb^#plbgoDNwBV&( zcpYC2woJ5LT7vD0~H|UX#7`0k(!WD4bs-IEXmP9i9?ry zVrg4Sr76G^PurYMaW=!-s!!AwHk=}&I}^iP z5tED;hl;KyUbH#j`aImPv|*mXn_FsKbE8R4g-kbm5T+(gvIE*+(&pQVzm+gUa=D}> za&xO3j=7-~gVpH}Z6#>%;{8ti2{X-CF(#gmT%)(@bc8^MZ{dp#F;a1=kuy2g@G_|u zh!%&cKi8lq1rAy%bzi*^GQ*Wjpe1N-YiklXmT!_DmFu7CP(ng{k3tu`qQ=^$`Pc1K! z)#jZ1BfM5TAv!V?akNluL3%of(A)52YGK+?^N|b|BQwy>BCcG04yPqDEn4Zc9xnsL zoJjteQqyvhw&3I$gF>c}9`eRs%$lq4@?8JTEtPif&=Qu%o)ltOuuA0Y`WcoOl^MZ}adtst7AF0ND_R61DbqAJdj zkh*(NW%fZU^>_FRh`c`eNCz}g9#l@Hqu*m<=jrvTs|RZ3Nd4;QBJ#>1pxc95iOQn< zS_kr`wxxblN3kNAmdw;v)N5k>{gGMIDvzdEHC3C5@yImP(CLmj6ln)*F52iko|=I= zl`^L4nzuvh&O$vKKuZmEB2Ui_&}2)?0oqegUYujEw9@Cmr-s#GgbO(NSMx=vI#DhUSVx+W~3Xh9X(j%E#&2~b_B z=V*9SF6tJG3^;7Aea)$FD%0tP?-oR;NBYL~r(Ictsx|eKxfnb{%Z;Y?qrDy3hzZ$UQ~(>V3bil zs2XE}BU@6fB=VzMjVyAmrgsE0al6B*&$LepJ* zsGoDFB&zPJmLx-Isr}{f6|fRop3^fG=*XjrP_E$T+Wfe>Qn;MdHqCrZ%L9Iu}U*>>Ntyhi%tz}qS)Adv%_It~) zidPrtT*s2g^3ua(YB15mC(0?QJ{9Mv!+Ltah8{8?N|*1{c6Hni^MUXZcJOE7Xn!<* zw8qp$H64$~e*Sm$3)e#(Y?foVng@X42fXBH%AFqap`J1Gr-vx$K?r)_XJ$mX8Zqdo z9^@*>(UEH=>u{mOV!{;GuMTU;E|qmJLmyI2+EAx{cdpgno~{i2G8%tG`_+Lnn#ji* zmZ2{67zb=HM_nsWU1k82eVTD7^WaA8#%fXT-j6VexFwKAedktzQfoA!EvR?s5vRG( zg%{T2a}LrfYp4D*IqEc!q-!BVkD{1)ios+T>cO>W%cDnF>Y%-zb<-#1v;;p`MB{=q zkfwU{)Bo4r`G@9pop=1a_kE@NN|vvstEyHS*?BW7SRt`3J8v3=YHQNSsZ8Zmwbj(w z9BRjMs!%5pNul26!o9FT`iHmmuW2LQG;l`)9dyt#m#s_;7d9{>8)10hG5--*|0pbD zfw{1)`+T40-uGTvO4|$y{iCm5o%5XE&w0*sp7WgNocmr~u?kPrbL(Q=3DR_#Lzc=< zTi?ZFbsQYK+BKMuY+r}Z>GFz~uGHuXm})%%CA>%B;qA+wB-cr!$rF}SA)hh2ZW9h` z#!Cu_ex>X<0k(BKH7ClraL=;M$X8GX4gk68EQRb<7Nr+iqCO60nw6qYIRcuYqK53U zqQ@t|LY(lMMv<+Y!0r^w%N+T{MV};B*j3G+muV{;5G~7+M{UmdB_i2Vs? zhI)*ao+e(r=&MC&a+tJV+J*31hF8Q9+m(fe5Bzlbj1C{IY`oP5a=VR{^I)l0b+~4F zi2ufjwg--r>uFN%H^*2zV--#(Y<6iY6n1acw4Q>-+75+#H^)1-h!fpjO^!QC_QvTz z)y{j&zalOHxX9MwVO zOUzKe4*Mir$Zx_Jt#nLZT?JSqq}k%*sBNK)IX=t7F0E2Lyh&Tqf5N>U_Ulyjd3n;t z0NduM9%FEeeXrE+Dz1J?67H9l@iAnCR)J@1U3d?j?ZA_kODq3pY=!v5kIUV}cK`5m zMju^;e6RVpb@W1wXHL=!ZRUIO?w-x_N<1#wX(O*qWf*k|>fEcxjY*1EwU_mlrq}kmZyN*mb$x4_163{bWtNZlE+G05hX(NDd_!c zNP`2c>bi#VJQp(#@Y29%Y2^rV?MtE2r}LkHi)8HcQm27V^GZ~?%zRulu;w2>-54mP zYG|IdE7<CT}|o^p0Uh%edOn%;?sK)53js_D2t=$?#p5;*D6Btm%Dk z1yj!~rZ8%Y{w}+#cB?xzx)fQhpyCdN-P$Nqyk?Umcqs)u|CV&j_I{9HhR=JpVypXQ zfTNy>GfEw>F*ZwXUQtJD!cw*T3L4}r_=?gxv?F}?=7)vc8dE$p!wrk-!8qAT3hTk; ze|`0-fB4ZmN5Aox;ZI-tr*9wA({+tjr_pHl;f#z4Oxj~QUWt2&?$k_B``fWmOk4U8+j&5l2~Axz1ugI9tY7*7)w9h z7}eo^nti)0u-c3p5&ubl+)M`2Hm`lA=wRF^`gNuPmn(3t0_Q7mp#m2xaH#@kD{!R( zXDaY?1y1+HkoA(elLNx%xX5hbDRaB#J~kTnkENfAk~E)6^BLSIis+rkFjCQIXm=vq z;n7Ba9FZs5TNM#atR%(CLJ&@EP2pQ&s}n|9p(BVl+JFfntEL+b#7))4zZhaPd?;?I zgi)W!(pQF^qW*DD8Vy4|m?Q#KnRZ!7Z8iqu78w${HnTf!*77YB*%qRDRSWg1U?g!t znlBi(lgTf|?KGc_5>=C!TV^Qz2u>kwb2ny-)LFVQTW?K)9^x>vw>CSzi3n9`__3WZ zG)C-hl(Yg^v|_kzXWU2C#3v+9LdwyQ45{anjL5T%L}=j+bfP`Up5{pQF9T3p6l72| z0+Ue$PwyEG{Q=h9leE2T6pg52RiaUx6j+SxWHGXnsUz#DP8c*X)orLnR0RdqfT~tp z5)FxttMo*l{?H`er`kyV4Va_t+~`=qRO;T?$l1mS@6t}9gw$t&H5-WpXHT<^Ohw75 zc!>6(Q;oKB1!?DMaXkj8#Vr>37He_yMcjOS zOgaynjHS53$&=t3!n?JBOKs+fk!3}=5<3|8 zTOtXXti-gV@puH_BL6B@`y}yTJ!$~{QjRv_x5Yq3w8X?`QOp(=6Be zACZf0|8OvX$CuL=NNkG^IU%Gsk$J+ut-1fx-)TbAB<{52B^G&EZr*3rPnjsihOiWC$VHDe>`N+_)%fP)X=6~KdNRwY>Qe}TYi(jSYs4+1rxaxW!G-W&Ed`UfqSs@S7wvV`VfBRLq4!j;k)E<-eCfW{$RDWfhKOOwXe=wBd{ zUEXELJWDlRnc;KUr$TmFjFI;x185fbe0^>x0r5E89%4jAFx48hJ7nG?iqLl;N+~5D zNj@5XFiO8bAWBymUkyigSsd$^w(k~K9~_#;LOIQ35K5ROG=;9hyK(t5d~ zVVy9sERKK}Uug%88-P|Nt6swjkr~9DrZg0qgOotiJ0@*Xvfji^`aDUmj4~{2$}ocD zboHdnkB})8oGD6DWD5CYzIvdg1FWKCDjrTo^55g@GnI^w70_mnNuo4{&lau;*w!f#$}Mfgk+map{XA}n9wxgsoI;e{eB zU*Y*8EMMWpA}n9wr6Md}VM!phFJIx=A}n9wnIbG-;nPJ}zQU_Tcr_8b-cIumq&dsL z`s49vntuzxhJTYFUn>TAEzS9^qkp9N7m6JKx^o*jl6|d_)R+IY`trY4F8=@~J@Yjr zzKRTX8bkphNtuA{(J&pu4OyCx%gx^4%NQDyY>yK15)tr5GJ%Ygze_qB>{S+WeJlDP ztmezA7Dc$z>)coB8YM>~qr}jAkv(M%&%tG1lh zIk@81ibpHH6}S4pR=m0$hfbp}M1?G8)<~A-lV!N;;cgk8^YC05p7-#48D8-4LK$B4 z@M0NW^6*j_p7ro-8J_X*Oc|c`@N~gy^2MstoA(Uef}KpWsxwWu&NS?TU9{LnE_>aC z?V7o-L250|*=x2T)Owt~W|A>el84cN((HA<2CSvo8rW#{dJR3jt(6&eX~q(ye6$)1 zS$M-%(foc`ax@+=CZG&o%ZCOBGkSAkH^b+uw|&(D*G8qAp^c^4wL-dO*9?biX?DE? zZj`{S5_o$!Ztqbc(7t9WW`Z7+U1L`xbu+tGpueFFQMRE>%DKZrkyh@2V{6cL8Y1nw zEwtAy>PDK~AnJxi-LR-zX?BaKTNZW8qTWukw~2b&qClwSou#o2qBn}ZZ%F6O)}d&$ zlNGGW!=??5F`ycjitYwN#?teRG~bZ^E9&JN(ytw|Xm(9fhF(`(k_@vPjbwku`e_`H zL_4${B0?K%YOth1#XVzDtj0`Pc2X3x+SB}6G=W}dI2P5?4$;tYjd9dK@-Bl+J- z86L^6C#JiJP5ADKcWf>EW>MHmXE$sZ*1=i@ivDId8T>T6X?SEefk?kuknQG}(jc34 zlX&|UT$#TGwbT49@4;I@C9U2v2GRH#pi$dgQLfzJAdRDG3@!QA7dP7sMh6wKiFVL# zD!JY6XUmFO)fYmVA3%*9$q$p7v~ikkX}GYUZylVd?qW77l%fQ%kbJgfcT)kHPK4wg zklyOEi11L{Uj+>J|7N{0vfak+B<{VvBOYirePTu8p5|cOE+gmxDX8X6=lp!Q@Pq6E z=VJi)k>-#x2dScm@W9@0B8nRYk%o zUvq?ETAQHnCiIqShGn7x_i~Lwk)!a#ET^EKKZ@*1UAMCK#PWQKs!fLG>$am@i`YJc zU4Cp*4wOf{EE%qxW>_pB?n_x=yj_XtnsU21T0F9Vzu6Car~P4gDQw@HMSx& z84r<{YRFr!U{la{!BWGlbph~=nA|?Glwc1Xk|7)3$p=>tjh*yS+>gGhS8l|zL~_lgyzz=OsCTP6jKcKBig~Pr`++deQFkK zR({GdO3}Pm+i%z-`wk0OeyX6!sU9(s#0B4XOv=HDMaFVrJhj)U=Q9p!LXJ8St)VmM z%?2!^ni{Zz?r6XT3=yA-$1B<^LZiWdHFl~I+ZA7nCPiNm7Uq?Z?j;(Rk^7l=cU7~v zi5y62RlYf1F+HI|zLGaYhiwy>8Yp;}_e?Rve(O5kD3(_i0hpnXRWblt$mp2nzif1D zd)#Ocant;9i)71>>3g`rBH9`RByzY|#tRlUYohXoyEfTcR||Ak(X8vbi~_w~(rP(m zs|Yoj`B-wY?@9{eN&X@%2N}J#%R*SiHb_6v29fQYRu}CHVQ0kMkoO-ep)>x-kg??z zbERQh*|nZ(gtARB2y26Wg^@KtqlgS0Xt)33H%>o&SNGPJTY*ojAt#c9Wg)Z_*#gnf zYRegx(~xjNGnjJ#UEcXw)&M2%i%~In#$RM(+JJ}6zvO}PrKRA#uXLkx8!8R z4-+%a|Aa^9<&Bc z-YIfi&V#~C_#n(2pZtOY%zI_{z8e3%9{xX2qA{=oSQL6`Yh?}UO#V$ZSD2|p7VQxW z@5 zwySo+JZVTBb;dhWfy)&*SAp{txKM$M6}VJ^vlX~ffio3&x&o(B=U_8!Y&av3J&OV2 zz(kf>ZIX%Plms+o1(@7nW=7kePFayD&H%|Y#o$=DYZl17J1DcH?_-IlsA8}lv34f5 zi^?BEz9MIxnZ1^ovX&XCSIXM%v``L5hA_10Oav)r2t+!#G4A46(F~v#z!(sb2jp2Y z+%SrjjCB=q(X^86{jxHc-^{I2m%G+6(5sXhXCrgrsRJ&fO7Ax*QshD?Q6JS{G6T z2BgE}jl6Z|BAL<^qBXQDHkNLgRs_e+xF{o-u~l<=F)^EaE|0BC?%w4%$mW@uFQaOY zC8iSVyh|qrc+mQ3#=jvDPGyrr&2qNDs7}nfXirCp9tyIbK4@$Z-8I}`U+88NkFi5@P|5oOhUD>R&z% z3n5q5WsL*{3!tnF^#Ul6a7>ZHMoQMpqy^#HJAw~C6Fy6WjPh?FvDVsz$B7z&EaHfK zeM`)hGR8WTuN#`{>L&!#o!O!dUU~V8uQtdROPdd!M!5UOyt6%o2OD9(W$2tb$16TM=a*mLWv2UI z?eKmTUgD>>-gTaT`IXKKpFGJWKC5$gBcxtr>HN8smv}ez=kzwsaDO9A>O~#)qNdK@ zywTa3sdHrdFb_{D=knq1bJLF;dFa50k34ktK=;Gb4;?uB=yQh;JaYJjdSIIX`B*re?+EDtW7*E`0-KqIv5#qH`UcmDqR>%STr#}~DQnE=(*|7wKQ ze{O^mC+AN7;~(Dt!{7POKUw(7zg_y>lYjJeC5J=2B;=J>5Alk_mp*@J?)(AOEnf(qed6U;<}O?~&f8nUi?5!0nU}U6T)x1yOFlok zk2Tyiv{BG;t|5y8Q|5uD)Uglyh+jV@+q55ZzK!aL!arDXJQs*%)T;FKiRv<_uC(q4pY47aN3p`+e<{Y^M?>F6d+q2Uh?lt1`V_v})TiFw5^=hO ztw-tn(sc2l1o_T{3F;~Prw1kUb3l5eh4;SW+M|%0>N{G)_#ip_vC?B)?q4AHIj+oB z{S#ksoupU))6`%4fhp?spFz~GH`*^af=`G18ZljjEgzGtdRF!8{otW%ymrwYcar)S zs9V3He!)gcKNVN|eUEM8I^hlQs@nFqY-~r<4s@8dhq(feH)w8DZ8_KJApl)5*4tae z8UE34Q8b{X()) + { + #if UNITY_5_6 + if (target == BuildTargetGroup.Switch) continue; // some releases of 5.6 defined BuildTargetGroup.Switch but didn't handled it correctly + #endif + EnablePluginsOnPlatform( target ); + } + + // Force these one (iPhone has the same # than iOS and iPhone is deprecated, so iOS was been skipped) + EnablePluginsOnPlatform(BuildTargetGroup.iOS); + } + + static void EnablePluginsOnPlatform( BuildTargetGroup Platform ) + { + string Settings = PlayerSettings.GetScriptingDefineSymbolsForGroup(Platform ); + + bool HasChanged = false; + List symbols = new List( Settings.Split(';')); + + HasChanged |= UpdateSettings("NGUI", "NGUIDebug", "", ref symbols); + HasChanged |= UpdateSettings("DFGUI", "dfPanel", "", ref symbols); + HasChanged |= UpdateSettings("TK2D", "tk2dTextMesh", "", ref symbols); + HasChanged |= UpdateSettings( "TextMeshPro", "TMPro.TMP_FontAsset", "TextMeshPro", ref symbols ); + HasChanged |= UpdateSettings( "SVG", "SVGImporter.SVGAsset", "", ref symbols ); + + if (HasChanged) + { + try + { + Settings = string.Empty; + for (int i=0,imax=symbols.Count; i0) Settings += ";"; + Settings += symbols[i]; + } + PlayerSettings.SetScriptingDefineSymbolsForGroup(Platform, Settings ); + } + catch (Exception) + { + } + } + } + + static bool UpdateSettings( string mPlugin, string mType, string AssemblyType, ref List symbols) + { + try + { + bool hasPluginClass = false; + + if (!string.IsNullOrEmpty( AssemblyType )) + { + var rtype = AppDomain.CurrentDomain.GetAssemblies() + .Where( assembly => assembly.FullName.Contains(AssemblyType) ) + .Select( assembly => assembly.GetType( mType, false ) ) + .Where( t => t!=null ) + .FirstOrDefault(); + if (rtype != null) + hasPluginClass = true; + } + + if (!hasPluginClass) + hasPluginClass = typeof( Localize ).Assembly.GetType( mType, false )!=null; + + + bool hasPluginDef = symbols.IndexOf(mPlugin)>=0; + + if (hasPluginClass != hasPluginDef) + { + if (hasPluginClass) symbols.Add(mPlugin); + else symbols.Remove(mPlugin); + return true; + } + } + catch(Exception) + { + } + return false; + + } + + //[MenuItem( "Tools/I2 Localization/Create I2Languages", false, 1)] + public static LanguageSourceAsset CreateLanguageSources() + { + var globalSourcesAsset = AssetDatabase.LoadAssetAtPath(I2GlobalSourcesEditorPath); + if (globalSourcesAsset != null) + { + return globalSourcesAsset; + } + + var asset = ScriptableObject.CreateInstance(); + + var assetFolder = Application.dataPath + I2GlobalSourcesEditorFolderPath.Replace("Assets", ""); + if (!Directory.Exists(assetFolder)) + Directory.CreateDirectory(assetFolder); + + AssetDatabase.CreateAsset(asset, I2GlobalSourcesEditorPath); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + return asset; + +#if false + if (LocalizationManager.GlobalSources==null || LocalizationManager.GlobalSources.Length==0) + return; + + Object GlobalSource = Resources.Load(LocalizationManager.GlobalSources[0]); + LanguageSourceData sourceData = null; + string sourcePath = null; + + if (GlobalSource != null) + { + if (GlobalSource is GameObject) + { + // I2Languages was a prefab before 2018.3, it should be converted to an ScriptableObject + sourcePath = AssetDatabase.GetAssetPath(GlobalSource); + LanguageSource langSourceObj = (GlobalSource as GameObject).GetComponent(); + sourceData = langSourceObj.mSource; + } + else + { + return; + } + } + + LanguageSourceAsset asset = ScriptableObject.CreateInstance(); + if (sourceData != null) + { + asset.mSource = sourceData; + AssetDatabase.DeleteAsset(sourcePath); + } + + if (string.IsNullOrEmpty(sourcePath)) + { + //string PluginPath = GetI2LocalizationPath(); + string ResourcesFolder = "Assets/Resources";//PluginPath.Substring(0, PluginPath.Length-"/Localization".Length) + "/Resources"; + + string fullresFolder = Application.dataPath + ResourcesFolder.Replace("Assets", ""); + if (!Directory.Exists(fullresFolder)) + Directory.CreateDirectory(fullresFolder); + + sourcePath = ResourcesFolder + "/" + LocalizationManager.GlobalSources[0] + ".asset"; + } + else + { + sourcePath = sourcePath.Replace(".prefab", ".asset"); + } + + AssetDatabase.CreateAsset(asset, sourcePath); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); +#endif + } + + [MenuItem("Tools/I2 Localization/Help", false, 30)] + [MenuItem("Help/I2 Localization")] + public static void MainHelp() + { + Application.OpenURL(LocalizeInspector.HelpURL_Documentation); + } + + private const string I2GlobalSourcesEditorFolderPath = "Assets/Editor/I2Localization"; + private const string I2GlobalSourcesEditorPath = "Assets/Editor/I2Localization/I2Languages.asset"; + + [MenuItem("Tools/I2 Localization/Open I2Languages.asset", false, 0)] + public static void OpenGlobalSource() + { + var globalSourcesAsset = CreateLanguageSources(); + + if (globalSourcesAsset == null) + Debug.LogError($"没有找到数据源 {I2GlobalSourcesEditorPath}"); + + Selection.activeObject = globalSourcesAsset; +#if false + CreateLanguageSources(); + LanguageSourceAsset GO = Resources.Load(LocalizationManager.GlobalSources[0]); + if (GO == null) + Debug.Log("Unable to find Global Language at Assets/Resources/" + LocalizationManager.GlobalSources[0] + ".asset"); + + Selection.activeObject = GO; +#endif + } + + + /*static void CreateScriptLocalization() + { + string[] assets = AssetDatabase.FindAssets("ScriptLocalization"); + if (assets.Length>0) + return; + + string ScriptsFolder = "Assets"; + string ScriptText = LocalizationEditor.mScriptLocalizationHeader + " }\n}"; + + System.IO.File.WriteAllText(ScriptsFolder + "/ScriptLocalization.cs", ScriptText); + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + }*/ + + public static string GetI2LocalizationPath() + { + string[] assets = AssetDatabase.FindAssets("LocalizationManager"); + if (assets.Length==0) + return string.Empty; + + string PluginPath = AssetDatabase.GUIDToAssetPath(assets[0]); + PluginPath = PluginPath.Substring(0, PluginPath.Length - "/Scripts/LocalizationManager.cs".Length); + + return PluginPath; + } + + public static string GetI2Path() + { + string pluginPath = GetI2LocalizationPath(); + return pluginPath.Substring(0, pluginPath.Length-"/Localization".Length); + } + + public static string GetI2CommonResourcesPath() + { + string I2Path = GetI2Path(); + return I2Path + "/Resources"; + } + } + + public static class UpgradeManagerHelper + { + public static bool HasAttributeOfType(this Enum enumVal) where T:Attribute + { + var type = enumVal.GetType(); + var memInfo = type.GetMember(enumVal.ToString()); + var attributes = memInfo[0].GetCustomAttributes(typeof(T), false); + return attributes.Length > 0; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Localization/UpgradeManager.cs.meta b/EintooAR/Assets/TEngine/Editor/Localization/UpgradeManager.cs.meta new file mode 100644 index 00000000..d3ab67c2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Localization/UpgradeManager.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6e61480936111c54883dc051751e0a5f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Postprocessor.meta b/EintooAR/Assets/TEngine/Editor/Postprocessor.meta new file mode 100644 index 00000000..4a9b4951 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Postprocessor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f9e50268851a5c449725ae364307d7f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs b/EintooAR/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs new file mode 100644 index 00000000..17526c43 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs @@ -0,0 +1,548 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEditor.U2D; +using UnityEngine; +using UnityEngine.U2D; +using Object = UnityEngine.Object; + +namespace GameFramework.Editor +{ + /// + /// 图集导入管线。 + /// + public class SpritePostprocessor : AssetPostprocessor + { + static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) + { + foreach (var s in importedAssets) + { + EditorSpriteSaveInfo.OnImportSprite(s); + } + + foreach (var s in deletedAssets) + { + EditorSpriteSaveInfo.OnDeleteSprite(s); + } + + foreach (var s in movedFromAssetPaths) + { + EditorSpriteSaveInfo.OnDeleteSprite(s); + } + + foreach (var s in movedAssets) + { + EditorSpriteSaveInfo.OnImportSprite(s); + } + } + } + + public static class EditorSpriteSaveInfo + { + private const string NormalAtlasDir = "Assets/AssetArt/Atlas"; + private const string UISpritePath = "Assets/AssetRaw/UIRaw"; + private const string UIAtlasPath = "Assets/AssetRaw/UIRaw/Atlas"; + private static readonly List _dirtyAtlasList = new List(); + private static readonly Dictionary> _allASprites = new Dictionary>(); + private static readonly Dictionary _uiAtlasMap = new Dictionary(); + private static bool _isInit = false; + private static bool m_dirty = false; + + public static void Init() + { + if (_isInit) + { + return; + } + + EditorApplication.update += CheckDirty; + + //读取所有图集信息 + string[] findAssets = AssetDatabase.FindAssets("t:SpriteAtlas", new[] { NormalAtlasDir }); + foreach (var findAsset in findAssets) + { + var path = AssetDatabase.GUIDToAssetPath(findAsset); + SpriteAtlas sa = AssetDatabase.LoadAssetAtPath(path, typeof(SpriteAtlas)) as SpriteAtlas; + if (sa == null) + { + Debug.LogError($"加载图集数据{path}失败"); + continue; + } + + string atlasName = Path.GetFileNameWithoutExtension(path); + var objects = sa.GetPackables(); + foreach (var o in objects) + { + if (!_allASprites.TryGetValue(atlasName, out var list)) + { + list = new List(); + _allASprites.Add(atlasName, list); + } + + list.Add(AssetDatabase.GetAssetPath(o)); + } + } + + _isInit = true; + } + + public static void CheckDirty() + { + if (m_dirty) + { + m_dirty = false; + + AssetDatabase.Refresh(); + float lastProgress = -1; + for (int i = 0; i < _dirtyAtlasList.Count; i++) + { + string atlasName = _dirtyAtlasList[i]; + Debug.Log("更新图集 : " + atlasName); + var curProgress = (float)i / _dirtyAtlasList.Count; + if (curProgress > lastProgress + 0.01f) + { + lastProgress = curProgress; + var progressText = $"当前进度:{i}/{_dirtyAtlasList.Count} {atlasName}"; + bool cancel = EditorUtility.DisplayCancelableProgressBar("刷新图集" + atlasName, progressText, curProgress); + if (cancel) + { + break; + } + } + + bool isUI = atlasName.StartsWith("UIRaw"); + SaveAtlas(atlasName, isUI); + } + + EditorUtility.ClearProgressBar(); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + _dirtyAtlasList.Clear(); + } + } + + public static void OnImportSprite(string assetPath) + { + if (!assetPath.StartsWith(UISpritePath)) + { + return; + } + + TextureImporter ti = AssetImporter.GetAtPath(assetPath) as TextureImporter; + + if (ti != null) + { + var modify = false; + + if (assetPath.StartsWith(UISpritePath)) + { + if (ti.textureType != TextureImporterType.Sprite) + { + ti.textureType = TextureImporterType.Sprite; + modify = true; + } + + if (!string.IsNullOrEmpty(ti.spritePackingTag)) + { + ti.spritePackingTag = string.Empty; + modify = true; + } + + var setting = new TextureImporterSettings(); + ti.ReadTextureSettings(setting); + if (setting.spriteGenerateFallbackPhysicsShape) + { + setting.spriteGenerateFallbackPhysicsShape = false; + ti.SetTextureSettings(setting); + modify = true; + } + + if (IsKeepRawImage(assetPath)) + { + //调整android格式 + var andPlatformSettings = ti.GetPlatformTextureSettings("Android"); + if (!andPlatformSettings.overridden) + { + andPlatformSettings.overridden = true; + modify = true; + } + + if (andPlatformSettings.format != TextureImporterFormat.ASTC_6x6) + { + andPlatformSettings.format = TextureImporterFormat.ASTC_6x6; + andPlatformSettings.compressionQuality = 50; + ti.SetPlatformTextureSettings(andPlatformSettings); + modify = true; + } + + //调整ios格式 + var iosPlatformSettings = ti.GetPlatformTextureSettings("iPhone"); + if (!iosPlatformSettings.overridden) + { + iosPlatformSettings.overridden = true; + modify = true; + } + + if (iosPlatformSettings.format != TextureImporterFormat.ASTC_5x5) + { + iosPlatformSettings.format = TextureImporterFormat.ASTC_5x5; + iosPlatformSettings.compressionQuality = 50; + ti.SetPlatformTextureSettings(iosPlatformSettings); + modify = true; + } + + //调整WebGL格式 + var webglSettings = ti.GetPlatformTextureSettings("WebGL"); + if (!webglSettings.overridden) + { + webglSettings.overridden = true; + modify = true; + } + + if (webglSettings.format != TextureImporterFormat.ASTC_6x6) + { + webglSettings.format = TextureImporterFormat.ASTC_6x6; + webglSettings.compressionQuality = 50; + ti.SetPlatformTextureSettings(webglSettings); + modify = true; + } + } + } + + if (modify) + { + ti.SaveAndReimport(); + } + + if (ti.textureType == TextureImporterType.Sprite) + { + OnProcessSprite(assetPath); + } + } + } + + /// + /// 是否保持散图(不打图集) + /// + /// + /// + public static bool IsKeepRawImage(string dirPath) + { + return dirPath.Contains("UIRaw/Raw/") || dirPath.Contains("UIRaw_Raw_"); + } + + public static string GetSpritePath(string assetPath) + { + string path = assetPath.Substring(0, assetPath.LastIndexOf(".", StringComparison.Ordinal)); + path = path.Replace("Assets/AssetRaw/", ""); + return path; + } + + /// + /// 根据文件路径,返回图集名称 + /// + /// + /// + public static string GetPackageTag(string fullName) + { + fullName = fullName.Replace("\\", "/"); + int idx = fullName.LastIndexOf("UIRaw", StringComparison.Ordinal); + if (idx == -1) + { + return ""; + } + + if (IsKeepRawImage(fullName)) + { + return ""; + } + + var atlasPath = fullName.Substring(idx); + string str = atlasPath; + str = str.Substring(0, str.LastIndexOf("/", StringComparison.Ordinal)).Replace("/", "_"); + + return str; + } + + public static void OnProcessSprite(string assetPath) + { + if (!assetPath.StartsWith("Assets")) + { + return; + } + + if (assetPath.StartsWith("Assets/UIRaw_Delete")) + { + return; + } + + Init(); + + var spriteName = Path.GetFileNameWithoutExtension(assetPath); + var spritePath = GetSpritePath(assetPath); + if (!_uiAtlasMap.TryGetValue(spriteName, out string oldAssetPath) || spritePath == oldAssetPath) + { + _uiAtlasMap[spriteName] = spritePath; + m_dirty = true; + } + else + { + Debug.LogError($"有重名的图片:{spriteName}\n旧图集:{oldAssetPath}\n新图集:{spritePath} "); + _uiAtlasMap[spriteName] = spritePath; + m_dirty = true; + } + + string atlasName = GetPackageTag(assetPath); + if (string.IsNullOrEmpty(atlasName)) + { + bool keepRaw = IsKeepRawImage(assetPath); + if (!keepRaw) + { + Debug.LogError($"empty packingTag of asset :{assetPath} !!!"); + } + + return; + } + else + { + List ret; + if (!_allASprites.TryGetValue(atlasName, out ret)) + { + ret = new List(); + _allASprites.Add(atlasName, ret); + } + + if (!ret.Contains(assetPath)) + { + ret.Add(assetPath); + m_dirty = true; + if (!_dirtyAtlasList.Contains(atlasName)) + { + _dirtyAtlasList.Add(atlasName); + } + } + } + } + + public static void OnDeleteSprite(string assetPath) + { + if (assetPath.StartsWith("Assets/UIRaw_Delete")) + { + return; + } + + if (!assetPath.StartsWith(UISpritePath)) + { + return; + } + + Init(); + string atlasName = GetPackageTag(assetPath); + if (!_allASprites.TryGetValue(atlasName, out var ret)) + { + return; + } + + //改成文件名的匹配 + if (!ret.Exists(s => Path.GetFileName(s) == Path.GetFileName(assetPath))) + { + return; + } + + if (assetPath.StartsWith(UISpritePath)) + { + var spriteName = Path.GetFileNameWithoutExtension(assetPath); + if (_uiAtlasMap.ContainsKey(spriteName)) + { + _uiAtlasMap.Remove(spriteName); + m_dirty = true; + } + } + + ret.Remove(assetPath); + m_dirty = true; + if (!_dirtyAtlasList.Contains(atlasName)) + { + _dirtyAtlasList.Add(atlasName); + } + } + + #region 更新图集 + + public static void SaveAtlas(string atlasName, bool isUI) + { + List spriteList = new List(); + if (_allASprites.TryGetValue(atlasName, out var list)) + { + list.Sort(StringComparer.Ordinal); + + foreach (var s in list) + { + var sprite = AssetDatabase.LoadAssetAtPath(s); + if (sprite != null) + { + spriteList.Add(sprite); + } + } + } + + var path = $"{NormalAtlasDir}/{atlasName}.spriteatlas"; + + if (spriteList.Count == 0) + { + if (File.Exists(path)) + { + AssetDatabase.DeleteAsset(path); + } + + return; + } + + var atlas = new SpriteAtlas(); + // var atlas = new SpriteAtlasAsset(); + var setting = new SpriteAtlasPackingSettings + { + blockOffset = 1, + padding = 2, + enableRotation = true + }; + + bool isOpaque = atlasName.Contains("Opaque"); + + var textureSetting = new SpriteAtlasTextureSettings + { + generateMipMaps = false, + sRGB = true, + filterMode = FilterMode.Bilinear + }; + atlas.SetTextureSettings(textureSetting); + + var iphonePlatformSetting = atlas.GetPlatformSettings("iPhone"); + if (!iphonePlatformSetting.overridden) + { + iphonePlatformSetting.overridden = true; + iphonePlatformSetting.format = TextureImporterFormat.ASTC_5x5; + iphonePlatformSetting.compressionQuality = 100; + atlas.SetPlatformSettings(iphonePlatformSetting); + } + + var androidPlatformSetting = atlas.GetPlatformSettings("Android"); + if (!androidPlatformSetting.overridden) + { + androidPlatformSetting.overridden = true; + androidPlatformSetting.format = TextureImporterFormat.ASTC_6x6; + androidPlatformSetting.compressionQuality = 100; + atlas.SetPlatformSettings(androidPlatformSetting); + } + + var webglSettings = atlas.GetPlatformSettings("WebGL"); + if (!webglSettings.overridden) + { + webglSettings.overridden = true; + webglSettings.format = TextureImporterFormat.ASTC_6x6; + webglSettings.compressionQuality = 50; + atlas.SetPlatformSettings(webglSettings); + } + + atlas.SetPackingSettings(setting); + atlas.Add(spriteList.ToArray()); + + AssetDatabase.CreateAsset(atlas, path); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + + #endregion + + #region 重新生成图集 + + private static readonly Dictionary> m_tempAllASprites = new Dictionary>(); + + [MenuItem("TEngine/Atlas/重新生成UI图集", false, 90)] + static void ForceGenAtlas() + { + Init(); + List needSaveAtlas = new List(); + m_tempAllASprites.Clear(); + _allASprites.Clear(); + var findAssets = AssetDatabase.FindAssets("t:sprite", new[] { UIAtlasPath }); + foreach (var findAsset in findAssets) + { + var path = AssetDatabase.GUIDToAssetPath(findAsset); + var atlasName = GetPackageTag(path); + if (!m_tempAllASprites.TryGetValue(atlasName, out var spriteList)) + { + spriteList = new List(); + m_tempAllASprites[atlasName] = spriteList; + } + + if (!spriteList.Contains(path)) + { + spriteList.Add(path); + } + } + + //有变化的才刷 + var iter = m_tempAllASprites.GetEnumerator(); + while (iter.MoveNext()) + { + bool needSave = false; + var atlasName = iter.Current.Key; + var newSpritesList = iter.Current.Value; + + if (_allASprites.TryGetValue(atlasName, out var existSprites)) + { + if (existSprites.Count != newSpritesList.Count) + { + needSave = true; + existSprites.Clear(); + existSprites.AddRange(newSpritesList); + } + else + { + for (int i = 0; i < newSpritesList.Count; i++) + { + if (!existSprites.Contains(newSpritesList[i])) + { + needSave = true; + break; + } + } + + if (needSave) + { + existSprites.Clear(); + existSprites.AddRange(newSpritesList); + } + } + } + else + { + needSave = true; + _allASprites.Add(atlasName, new List(newSpritesList)); + } + + if (needSave && !needSaveAtlas.Contains(atlasName)) + { + needSaveAtlas.Add(atlasName); + } + } + + iter.Dispose(); + foreach (var atlas in needSaveAtlas) + { + Debug.LogFormat("Gen atlas:{0}", atlas); + SaveAtlas(atlas, true); + } + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + SpriteAtlasUtility.PackAllAtlases(EditorUserBuildSettings.activeBuildTarget); + Debug.Log("Gen end"); + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs.meta b/EintooAR/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs.meta new file mode 100644 index 00000000..7d03fe8d --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Postprocessor/SpritePostprocessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0b37506bd00c3f14d83f966ae20ba8ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/ReleaseTools.meta b/EintooAR/Assets/TEngine/Editor/ReleaseTools.meta new file mode 100644 index 00000000..af5b4297 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ReleaseTools.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: defa3b5ccfc64b0392d67db95b3c528d +timeCreated: 1698043573 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/ReleaseTools/ReleaseTools.cs b/EintooAR/Assets/TEngine/Editor/ReleaseTools/ReleaseTools.cs new file mode 100644 index 00000000..6a9b8d46 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ReleaseTools/ReleaseTools.cs @@ -0,0 +1,258 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEditor.Build.Reporting; +using UnityEngine; +using YooAsset; +using YooAsset.Editor; +using BuildResult = UnityEditor.Build.Reporting.BuildResult; + +namespace TEngine.Editor +{ + /// + /// 打包工具类。 + /// 通过CommandLineReader可以不前台开启Unity实现静默打包以及CLI工作流,详见CommandLineReader.cs example1 + /// + public static class ReleaseTools + { + public static void BuildDll() + { + string platform = CommandLineReader.GetCustomArgument("platform"); + if (string.IsNullOrEmpty(platform)) + { + Debug.LogError($"Build Asset Bundle Error!platform is null"); + return; + } + + BuildTarget target = GetBuildTarget(platform); + + BuildDLLCommand.BuildAndCopyDlls(target); + } + + public static void BuildAssetBundle() + { + string outputRoot = CommandLineReader.GetCustomArgument("outputRoot"); + if (string.IsNullOrEmpty(outputRoot)) + { + Debug.LogError($"Build Asset Bundle Error!outputRoot is null"); + return; + } + + string packageVersion = CommandLineReader.GetCustomArgument("packageVersion"); + if (string.IsNullOrEmpty(packageVersion)) + { + Debug.LogError($"Build Asset Bundle Error!packageVersion is null"); + return; + } + + string platform = CommandLineReader.GetCustomArgument("platform"); + if (string.IsNullOrEmpty(platform)) + { + Debug.LogError($"Build Asset Bundle Error!platform is null"); + return; + } + + BuildTarget target = GetBuildTarget(platform); + BuildInternal(target, outputRoot); + Debug.LogWarning($"Start BuildPackage BuildTarget:{target} outputPath:{outputRoot}"); + } + + [MenuItem("TEngine/Quick Build/一键打包AssetBundle")] + public static void BuildCurrentPlatformAB() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + BuildInternal(target, Application.dataPath + "/../Builds/", packageVersion: GetBuildPackageVersion()); + AssetDatabase.Refresh(); + } + + private static BuildTarget GetBuildTarget(string platform) + { + BuildTarget target = BuildTarget.NoTarget; + switch (platform) + { + case "Android": + target = BuildTarget.Android; + break; + case "IOS": + target = BuildTarget.iOS; + break; + case "Windows": + target = BuildTarget.StandaloneWindows64; + break; + case "MacOS": + target = BuildTarget.StandaloneOSX; + break; + case "Linux": + target = BuildTarget.StandaloneLinux64; + break; + case "WebGL": + target = BuildTarget.WebGL; + break; + case "Switch": + target = BuildTarget.Switch; + break; + case "PS4": + target = BuildTarget.PS4; + break; + case "PS5": + target = BuildTarget.PS5; + break; + } + + return target; + } + + private static void BuildInternal(BuildTarget buildTarget, string outputRoot, string packageVersion = "1.0", + EBuildPipeline buildPipeline = EBuildPipeline.ScriptableBuildPipeline) + { + Debug.Log($"开始构建 : {buildTarget}"); + + IBuildPipeline pipeline = null; + BuildParameters buildParameters = null; + + if (buildPipeline == EBuildPipeline.BuiltinBuildPipeline) + { + // 构建参数 + BuiltinBuildParameters builtinBuildParameters = new BuiltinBuildParameters(); + + // 执行构建 + pipeline = new BuiltinBuildPipeline(); + buildParameters = builtinBuildParameters; + + builtinBuildParameters.CompressOption = ECompressOption.LZ4; + } + else + { + ScriptableBuildParameters scriptableBuildParameters = new ScriptableBuildParameters(); + + // 执行构建 + pipeline = new ScriptableBuildPipeline(); + buildParameters = scriptableBuildParameters; + + scriptableBuildParameters.CompressOption = ECompressOption.LZ4; + } + + buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot(); + buildParameters.BuildinFileRoot = AssetBundleBuilderHelper.GetStreamingAssetsRoot(); + buildParameters.BuildPipeline = buildPipeline.ToString(); + buildParameters.BuildTarget = buildTarget; + buildParameters.BuildMode = EBuildMode.IncrementalBuild; + buildParameters.PackageName = "DefaultPackage"; + buildParameters.PackageVersion = packageVersion; + buildParameters.VerifyBuildingResult = true; + buildParameters.FileNameStyle = EFileNameStyle.BundleName_HashName; + buildParameters.BuildinFileCopyOption = EBuildinFileCopyOption.ClearAndCopyAll; + buildParameters.BuildinFileCopyParams = string.Empty; + buildParameters.EncryptionServices = CreateEncryptionInstance("DefaultPackage",buildPipeline); + // 启用共享资源打包 + buildParameters.EnableSharePackRule = true; + + var buildResult = pipeline.Run(buildParameters, true); + if (buildResult.Success) + { + Debug.Log($"构建成功 : {buildResult.OutputPackageDirectory}"); + } + else + { + Debug.LogError($"构建失败 : {buildResult.ErrorInfo}"); + } + + } + + /// + /// 创建加密类实例 + /// + private static IEncryptionServices CreateEncryptionInstance(string packageName, EBuildPipeline buildPipeline) + { + var encryptionClassName = AssetBundleBuilderSetting.GetPackageEncyptionClassName(packageName, buildPipeline); + var encryptionClassTypes = EditorTools.GetAssignableTypes(typeof(IEncryptionServices)); + var classType = encryptionClassTypes.Find(x => x.FullName != null && x.FullName.Equals(encryptionClassName)); + if (classType != null) + { + Debug.Log($"Use Encryption {classType}"); + return (IEncryptionServices)Activator.CreateInstance(classType); + } + else + { + return null; + } + } + + [MenuItem("TEngine/Quick Build/一键打包Window", false, 90)] + public static void AutomationBuild() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + BuildDLLCommand.BuildAndCopyDlls(target); + AssetDatabase.Refresh(); + BuildInternal(target, Application.dataPath + "/../Builds/Windows", packageVersion: GetBuildPackageVersion()); + AssetDatabase.Refresh(); + BuildImp(BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows64, $"{Application.dataPath}/../Builds/Windows/Release_Windows.exe"); + } + + // 构建版本相关 + private static string GetBuildPackageVersion() + { + int totalMinutes = DateTime.Now.Hour * 60 + DateTime.Now.Minute; + return DateTime.Now.ToString("yyyy-MM-dd") + "-" + totalMinutes; + } + + [MenuItem("TEngine/Quick Build/一键打包Android", false, 90)] + public static void AutomationBuildAndroid() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + BuildDLLCommand.BuildAndCopyDlls(target); + AssetDatabase.Refresh(); + BuildInternal(target, outputRoot: Application.dataPath + "/../Bundles", packageVersion: GetBuildPackageVersion()); + AssetDatabase.Refresh(); + BuildImp(BuildTargetGroup.Android, BuildTarget.Android, $"{Application.dataPath}/../Build/Android/{GetBuildPackageVersion()}Android.apk"); + // BuildImp(BuildTargetGroup.Android, BuildTarget.Android, $"{Application.dataPath}/../Build/Android/Android.apk"); + } + + [MenuItem("TEngine/Quick Build/一键打包IOS", false, 90)] + public static void AutomationBuildIOS() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + BuildDLLCommand.BuildAndCopyDlls(target); + AssetDatabase.Refresh(); + BuildInternal(target, outputRoot: Application.dataPath + "/../Bundles", packageVersion: GetBuildPackageVersion()); + AssetDatabase.Refresh(); + BuildImp(BuildTargetGroup.iOS, BuildTarget.iOS, $"{Application.dataPath}/../Build/IOS/XCode_Project"); + } + + [MenuItem("TEngine/Quick Build/一键打包WebGL", false, 91)] + public static void AutomationBuildWebGL() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + BuildDLLCommand.BuildAndCopyDlls(target); + AssetDatabase.Refresh(); + BuildInternal(target, Application.dataPath + "/../Builds/WebGL", packageVersion: GetBuildPackageVersion()); + AssetDatabase.Refresh(); + BuildImp(BuildTargetGroup.WebGL, BuildTarget.WebGL, $"{Application.dataPath}/../Builds/WebGL"); + } + + public static void BuildImp(BuildTargetGroup buildTargetGroup, BuildTarget buildTarget, string locationPathName) + { + EditorUserBuildSettings.SwitchActiveBuildTarget(buildTargetGroup, BuildTarget.StandaloneWindows64); + AssetDatabase.Refresh(); + + BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions + { + scenes = EditorBuildSettings.scenes.Select(scene => scene.path).ToArray(), + locationPathName = locationPathName, + targetGroup = buildTargetGroup, + target = buildTarget, + options = BuildOptions.None + }; + var report = BuildPipeline.BuildPlayer(buildPlayerOptions); + BuildSummary summary = report.summary; + if (summary.result == BuildResult.Succeeded) + { + Debug.Log($"Build success: {summary.totalSize / 1024 / 1024} MB"); + } + else + { + Debug.Log($"Build Failed" + summary.result); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/ReleaseTools/ReleaseTools.cs.meta b/EintooAR/Assets/TEngine/Editor/ReleaseTools/ReleaseTools.cs.meta new file mode 100644 index 00000000..6c8f8f30 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ReleaseTools/ReleaseTools.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 336706b48f93452ea43f7272872e5451 +timeCreated: 1698043593 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Resource.meta b/EintooAR/Assets/TEngine/Editor/Resource.meta new file mode 100644 index 00000000..1433e671 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Resource.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 86e1ceb0af034fc0aca146e58c0be5ae +timeCreated: 1694879395 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Resource/Encryption.cs b/EintooAR/Assets/TEngine/Editor/Resource/Encryption.cs new file mode 100644 index 00000000..d4e7ccae --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Resource/Encryption.cs @@ -0,0 +1,53 @@ +using System; +using System.IO; +using TEngine; +using YooAsset; + +/// +/// 文件偏移加密方式 +/// +public class FileOffsetEncryption : IEncryptionServices +{ + public EncryptResult Encrypt(EncryptFileInfo fileInfo) + { + if (fileInfo.BundleName.Contains("DLL")) + { + + } + + int offset = 32; + byte[] fileData = File.ReadAllBytes(fileInfo.FilePath); + var encryptedData = new byte[fileData.Length + offset]; + Buffer.BlockCopy(fileData, 0, encryptedData, offset, fileData.Length); + + EncryptResult result = new EncryptResult(); + result.Encrypted = true; + result.EncryptedData = encryptedData; + return result; + } +} + +/// +/// 文件流加密方式 +/// +public class FileStreamEncryption : IEncryptionServices +{ + public EncryptResult Encrypt(EncryptFileInfo fileInfo) + { + if (fileInfo.BundleName.Contains("DLL")) + { + + } + + var fileData = File.ReadAllBytes(fileInfo.FilePath); + for (int i = 0; i < fileData.Length; i++) + { + fileData[i] ^= BundleStream.KEY; + } + + EncryptResult result = new EncryptResult(); + result.Encrypted = true; + result.EncryptedData = fileData; + return result; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Resource/Encryption.cs.meta b/EintooAR/Assets/TEngine/Editor/Resource/Encryption.cs.meta new file mode 100644 index 00000000..0a70ab82 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Resource/Encryption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37d5ebb52d476484c974184f2c8eb818 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Resource/ExtensionFilterRule.cs b/EintooAR/Assets/TEngine/Editor/Resource/ExtensionFilterRule.cs new file mode 100644 index 00000000..486ef394 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Resource/ExtensionFilterRule.cs @@ -0,0 +1,14 @@ +using System.IO; +using YooAsset.Editor; + +namespace UnityGameFramework.Editor +{ + [DisplayName("收集着色器")] + public class CollectShader : IFilterRule + { + public bool IsCollectAsset(FilterRuleData data) + { + return Path.GetExtension(data.AssetPath) == ".shader"; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Resource/ExtensionFilterRule.cs.meta b/EintooAR/Assets/TEngine/Editor/Resource/ExtensionFilterRule.cs.meta new file mode 100644 index 00000000..627cf7f8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Resource/ExtensionFilterRule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0e7486840c674c42afd16926eb15ad2d +timeCreated: 1708430564 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/TEngine.Editor.asmdef b/EintooAR/Assets/TEngine/Editor/TEngine.Editor.asmdef new file mode 100644 index 00000000..9c9d3d72 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/TEngine.Editor.asmdef @@ -0,0 +1,49 @@ +{ + "name": "TEngine.Editor", + "rootNamespace": "", + "references": [ + "GUID:24c092aee38482f4e80715eaa8148782", + "GUID:e34a5702dd353724aa315fb8011f08c3", + "GUID:4d1926c9df5b052469a1c63448b7609a", + "GUID:2373f786d14518f44b0f475db77ba4de", + "GUID:6e76b07590314a543b982daed6af2509", + "GUID:478a2357cc57436488a56e564b08d223", + "GUID:6055be8ebefd69e48b49212b09b47b2f", + "GUID:2e7f0f7a8ee6e144db6fb95614c6d8fe", + "GUID:9069ac25d95ca17448a247f3bb1c769f", + "GUID:a50e53feb834b454cb973fdcab1725ec", + "GUID:cfcd2ce455f8d1944942cdd919ecaa60", + "GUID:8990947d903fec847b19d9f51781afb1", + "GUID:448b0b55421917e4784a8f2f7449081f", + "GUID:1e113d3b5d77bc04eab508251483e8ff", + "GUID:cbb0d51b565003841ae81cdbaf747114", + "GUID:8f58f15387c7a6f4fad9857024eb47f7", + "GUID:8502decd0a029d84f9689fdde09f7b93", + "GUID:4c25c05f410a3a447a75c3b0909152ef", + "GUID:5b70f83da6937434491f26e0fd0cd099", + "GUID:718e7687a24939942bd6e3bf5c51911a", + "GUID:2289059ddf1745b4d80a0f184af99d6b", + "GUID:570288d68c06d364a82f87aca0bc1a34", + "GUID:66c2eb417c67ad849907d0769db96dbf", + "GUID:b47e40ab5d617e24989e362542a01644", + "GUID:61a68efbb0c03dc42ad7614dc4858ec4", + "GUID:f51ebe6a0ceec4240a699833d6309b23", + "GUID:6c99ff64c0c0f1e449657448dcdd2487", + "GUID:1b81d8fc2a073514ba9f462aec7ffb51", + "GUID:46ee17e5fcc7f436f9df354a1efda6a4", + "GUID:77cdc4b9a869f4caa8b2e41e3b794af0", + "GUID:f712e8ae9bab041c2a043390d1a751a1", + "GUID:bfb3a80268dac420ab25cd26e09e4475" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/TEngine.Editor.asmdef.meta b/EintooAR/Assets/TEngine/Editor/TEngine.Editor.asmdef.meta new file mode 100644 index 00000000..02934c9e --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/TEngine.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 48c39f1caa38fbd4e99e4c330e531180 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender.meta b/EintooAR/Assets/TEngine/Editor/ToolbarExtender.meta new file mode 100644 index 00000000..4c76858d --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 81dccabae12b7f64086d54bc04a85de0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom.meta b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom.meta new file mode 100644 index 00000000..a036a008 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 075130c21aee41b49b3977adc2bfa288 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher.meta b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher.meta new file mode 100644 index 00000000..9cd75db2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 20dbf6614352aaf488de29690deeab68 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor.meta b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor.meta new file mode 100644 index 00000000..0119ff6e --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fb0502859d7561142a3408d0ce2a19d8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/EditorResourceMode.cs b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/EditorResourceMode.cs new file mode 100644 index 00000000..f749f799 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/EditorResourceMode.cs @@ -0,0 +1,70 @@ +using UnityEditor; +using UnityEngine; +using UnityToolbarExtender; + +namespace TEngine.Editor +{ + [InitializeOnLoad] + public class EditorResourceMode + { + static class ToolbarStyles + { + public static readonly GUIStyle ToolBarButtonGuiStyle; + + static ToolbarStyles() + { + ToolBarButtonGuiStyle = new GUIStyle(ButtonStyleName) + { + padding = new RectOffset(2, 8, 2, 2), + alignment = TextAnchor.MiddleCenter, + fontStyle = FontStyle.Bold + }; + } + } + + static EditorResourceMode() + { + ToolbarExtender.RightToolbarGUI.Add(OnToolbarGUI); + _playModeIndex = EditorPrefs.GetInt("EditorPlayMode", 0); + } + + private const string ButtonStyleName = "Tab middle"; + static GUIStyle _buttonGuiStyle; + + private static readonly string[] _resourceModeNames = + { + "EditorMode (编辑器下的模拟模式)", + "OfflinePlayMode (单机模式)", + "HostPlayMode (联机运行模式)", + "WebPlayMode (WebGL运行模式)" + }; + + private static int _playModeIndex = 0; + public static int PlayModeIndex => _playModeIndex; + + static void OnToolbarGUI() + { + EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode); + { + GUILayout.Space(10); + + GUILayout.FlexibleSpace(); + + // 资源模式 + int selectedIndex = EditorGUILayout.Popup("", _playModeIndex, _resourceModeNames, ToolbarStyles.ToolBarButtonGuiStyle); + // ReSharper disable once RedundantCheckBeforeAssignment + if (selectedIndex != _playModeIndex) + { + Debug.Log($"更改编辑器资源运行模式 : {_resourceModeNames[selectedIndex]}"); + _playModeIndex = selectedIndex; + EditorPrefs.SetInt("EditorPlayMode", selectedIndex); + } + + GUILayout.FlexibleSpace(); + + GUILayout.Space(400); + } + EditorGUI.EndDisabledGroup(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/EditorResourceMode.cs.meta b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/EditorResourceMode.cs.meta new file mode 100644 index 00000000..ce80e39b --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/EditorResourceMode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ab26dd2998d84a08b35c0132e1814199 +timeCreated: 1683857308 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/SceneSwitcher.cs b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/SceneSwitcher.cs new file mode 100644 index 00000000..3aa688f0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/SceneSwitcher.cs @@ -0,0 +1,100 @@ +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityToolbarExtender; + +namespace TEngine +{ + [InitializeOnLoad] + public class SceneSwitchLeftButton + { + private static readonly string SceneMain = "main"; + + static SceneSwitchLeftButton() + { + ToolbarExtender.LeftToolbarGUI.Add(OnToolbarGUI); + } + + static readonly string ButtonStyleName = "Tab middle"; + static GUIStyle _buttonGuiStyle; + + static void OnToolbarGUI() + { + _buttonGuiStyle ??= new GUIStyle(ButtonStyleName) + { + padding = new RectOffset(2, 8, 2, 2), + alignment = TextAnchor.MiddleCenter, + fontStyle = FontStyle.Bold + }; + + GUILayout.FlexibleSpace(); + if (GUILayout.Button( + new GUIContent("Launcher", EditorGUIUtility.FindTexture("PlayButton"), $"Start Scene Launcher"), + _buttonGuiStyle)) + { + SceneHelper.StartScene(SceneMain); + } + } + } + + static class SceneHelper + { + static string _sceneToOpen; + + public static void StartScene(string sceneName) + { + if (EditorApplication.isPlaying) + { + EditorApplication.isPlaying = false; + } + + _sceneToOpen = sceneName; + EditorApplication.update += OnUpdate; + } + + static void OnUpdate() + { + if (_sceneToOpen == null || + EditorApplication.isPlaying || EditorApplication.isPaused || + EditorApplication.isCompiling || EditorApplication.isPlayingOrWillChangePlaymode) + { + return; + } + + EditorApplication.update -= OnUpdate; + + if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) + { + string[] guids = AssetDatabase.FindAssets("t:scene " + _sceneToOpen, null); + if (guids.Length == 0) + { + Debug.LogWarning("Couldn't find scene file"); + } + else + { + string scenePath = null; + // 优先打开完全匹配_sceneToOpen的场景 + for (var i = 0; i < guids.Length; i++) + { + scenePath = AssetDatabase.GUIDToAssetPath(guids[i]); + if (scenePath.EndsWith("/" + _sceneToOpen + ".unity")) + { + break; + } + } + + // 如果没有完全匹配的场景,默认显示找到的第一个场景 + if (string.IsNullOrEmpty(scenePath)) + { + scenePath = AssetDatabase.GUIDToAssetPath(guids[0]); + } + + EditorSceneManager.OpenScene(scenePath); + EditorApplication.isPlaying = true; + } + } + + _sceneToOpen = null; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/SceneSwitcher.cs.meta b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/SceneSwitcher.cs.meta new file mode 100644 index 00000000..262437c0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/Custom/SceneSwitcher/Editor/SceneSwitcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 45017e4df12424c4fb16db4708d239f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarCallback.cs b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarCallback.cs new file mode 100644 index 00000000..07eb09ae --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarCallback.cs @@ -0,0 +1,111 @@ +using System; +using UnityEngine; +using UnityEditor; +using System.Reflection; + +#if UNITY_2019_1_OR_NEWER +using UnityEngine.UIElements; +#else +using UnityEngine.Experimental.UIElements; +#endif + +namespace UnityToolbarExtender +{ + public static class ToolbarCallback + { + static Type m_toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar"); + static Type m_guiViewType = typeof(Editor).Assembly.GetType("UnityEditor.GUIView"); +#if UNITY_2020_1_OR_NEWER + static Type m_iWindowBackendType = typeof(Editor).Assembly.GetType("UnityEditor.IWindowBackend"); + static PropertyInfo m_windowBackend = m_guiViewType.GetProperty("windowBackend", + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + static PropertyInfo m_viewVisualTree = m_iWindowBackendType.GetProperty("visualTree", + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); +#else + static PropertyInfo m_viewVisualTree = m_guiViewType.GetProperty("visualTree", + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); +#endif + static FieldInfo m_imguiContainerOnGui = typeof(IMGUIContainer).GetField("m_OnGUIHandler", + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + static ScriptableObject m_currentToolbar; + + /// + /// Callback for toolbar OnGUI method. + /// + public static Action OnToolbarGUI; + public static Action OnToolbarGUILeft; + public static Action OnToolbarGUIRight; + + static ToolbarCallback() + { + EditorApplication.update -= OnUpdate; + EditorApplication.update += OnUpdate; + } + + static void OnUpdate() + { + // Relying on the fact that toolbar is ScriptableObject and gets deleted when layout changes + if (m_currentToolbar == null) + { + // Find toolbar + var toolbars = Resources.FindObjectsOfTypeAll(m_toolbarType); + m_currentToolbar = toolbars.Length > 0 ? (ScriptableObject) toolbars[0] : null; + if (m_currentToolbar != null) + { +#if UNITY_2021_1_OR_NEWER + var root = m_currentToolbar.GetType().GetField("m_Root", BindingFlags.NonPublic | BindingFlags.Instance); + var rawRoot = root.GetValue(m_currentToolbar); + var mRoot = rawRoot as VisualElement; + RegisterCallback("ToolbarZoneLeftAlign", OnToolbarGUILeft); + RegisterCallback("ToolbarZoneRightAlign", OnToolbarGUIRight); + + void RegisterCallback(string root, Action cb) { + var toolbarZone = mRoot.Q(root); + + var parent = new VisualElement() + { + style = { + flexGrow = 1, + flexDirection = FlexDirection.Row, + } + }; + var container = new IMGUIContainer(); + container.style.flexGrow = 1; + container.onGUIHandler += () => { + cb?.Invoke(); + }; + parent.Add(container); + toolbarZone.Add(parent); + } +#else +#if UNITY_2020_1_OR_NEWER + var windowBackend = m_windowBackend.GetValue(m_currentToolbar); + + // Get it's visual tree + var visualTree = (VisualElement) m_viewVisualTree.GetValue(windowBackend, null); +#else + // Get it's visual tree + var visualTree = (VisualElement) m_viewVisualTree.GetValue(m_currentToolbar, null); +#endif + + // Get first child which 'happens' to be toolbar IMGUIContainer + var container = (IMGUIContainer) visualTree[0]; + + // (Re)attach handler + var handler = (Action) m_imguiContainerOnGui.GetValue(container); + handler -= OnGUI; + handler += OnGUI; + m_imguiContainerOnGui.SetValue(container, handler); + +#endif + } + } + } + + static void OnGUI() + { + var handler = OnToolbarGUI; + if (handler != null) handler(); + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarCallback.cs.meta b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarCallback.cs.meta new file mode 100644 index 00000000..ced30864 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarCallback.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4314ecffdfd1d90488e39e9ae35d14a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarExtender.cs b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarExtender.cs new file mode 100644 index 00000000..95a79725 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarExtender.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace UnityToolbarExtender +{ + [InitializeOnLoad] + public static class ToolbarExtender + { + static int m_toolCount; + static GUIStyle m_commandStyle = null; + + public static readonly List LeftToolbarGUI = new List(); + public static readonly List RightToolbarGUI = new List(); + + static ToolbarExtender() + { + Type toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar"); + +#if UNITY_2019_1_OR_NEWER + string fieldName = "k_ToolCount"; +#else + string fieldName = "s_ShownToolIcons"; +#endif + + FieldInfo toolIcons = toolbarType.GetField(fieldName, + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + +#if UNITY_2019_3_OR_NEWER + m_toolCount = toolIcons != null ? ((int) toolIcons.GetValue(null)) : 8; +#elif UNITY_2019_1_OR_NEWER + m_toolCount = toolIcons != null ? ((int) toolIcons.GetValue(null)) : 7; +#elif UNITY_2018_1_OR_NEWER + m_toolCount = toolIcons != null ? ((Array) toolIcons.GetValue(null)).Length : 6; +#else + m_toolCount = toolIcons != null ? ((Array) toolIcons.GetValue(null)).Length : 5; +#endif + + ToolbarCallback.OnToolbarGUI = OnGUI; + ToolbarCallback.OnToolbarGUILeft = GUILeft; + ToolbarCallback.OnToolbarGUIRight = GUIRight; + } + +#if UNITY_2019_3_OR_NEWER + public const float space = 8; +#else + public const float space = 10; +#endif + public const float largeSpace = 20; + public const float buttonWidth = 32; + public const float dropdownWidth = 80; +#if UNITY_2019_1_OR_NEWER + public const float playPauseStopWidth = 140; +#else + public const float playPauseStopWidth = 100; +#endif + + static void OnGUI() + { + // Create two containers, left and right + // Screen is whole toolbar + + if (m_commandStyle == null) + { + m_commandStyle = new GUIStyle("CommandLeft"); + } + + var screenWidth = EditorGUIUtility.currentViewWidth; + + // Following calculations match code reflected from Toolbar.OldOnGUI() + float playButtonsPosition = Mathf.RoundToInt ((screenWidth - playPauseStopWidth) / 2); + + Rect leftRect = new Rect(0, 0, screenWidth, Screen.height); + leftRect.xMin += space; // Spacing left + leftRect.xMin += buttonWidth * m_toolCount; // Tool buttons +#if UNITY_2019_3_OR_NEWER + leftRect.xMin += space; // Spacing between tools and pivot +#else + leftRect.xMin += largeSpace; // Spacing between tools and pivot +#endif + leftRect.xMin += 64 * 2; // Pivot buttons + leftRect.xMax = playButtonsPosition; + + Rect rightRect = new Rect(0, 0, screenWidth, Screen.height); + rightRect.xMin = playButtonsPosition; + rightRect.xMin += m_commandStyle.fixedWidth * 3; // Play buttons + rightRect.xMax = screenWidth; + rightRect.xMax -= space; // Spacing right + rightRect.xMax -= dropdownWidth; // Layout + rightRect.xMax -= space; // Spacing between layout and layers + rightRect.xMax -= dropdownWidth; // Layers +#if UNITY_2019_3_OR_NEWER + rightRect.xMax -= space; // Spacing between layers and account +#else + rightRect.xMax -= largeSpace; // Spacing between layers and account +#endif + rightRect.xMax -= dropdownWidth; // Account + rightRect.xMax -= space; // Spacing between account and cloud + rightRect.xMax -= buttonWidth; // Cloud + rightRect.xMax -= space; // Spacing between cloud and collab + rightRect.xMax -= 78; // Colab + + // Add spacing around existing controls + leftRect.xMin += space; + leftRect.xMax -= space; + rightRect.xMin += space; + rightRect.xMax -= space; + + // Add top and bottom margins +#if UNITY_2019_3_OR_NEWER + leftRect.y = 4; + leftRect.height = 22; + rightRect.y = 4; + rightRect.height = 22; +#else + leftRect.y = 5; + leftRect.height = 24; + rightRect.y = 5; + rightRect.height = 24; +#endif + + if (leftRect.width > 0) + { + GUILayout.BeginArea(leftRect); + GUILayout.BeginHorizontal(); + foreach (var handler in LeftToolbarGUI) + { + handler(); + } + + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } + + if (rightRect.width > 0) + { + GUILayout.BeginArea(rightRect); + GUILayout.BeginHorizontal(); + foreach (var handler in RightToolbarGUI) + { + handler(); + } + + GUILayout.EndHorizontal(); + GUILayout.EndArea(); + } + } + + public static void GUILeft() { + GUILayout.BeginHorizontal(); + foreach (var handler in LeftToolbarGUI) + { + handler(); + } + GUILayout.EndHorizontal(); + } + + public static void GUIRight() { + GUILayout.BeginHorizontal(); + foreach (var handler in RightToolbarGUI) + { + handler(); + } + GUILayout.EndHorizontal(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarExtender.cs.meta b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarExtender.cs.meta new file mode 100644 index 00000000..8183f963 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/ToolbarExtender/ToolbarExtender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b71421f0295dfa4f9c32f3ace45690d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/UI.meta b/EintooAR/Assets/TEngine/Editor/UI.meta new file mode 100644 index 00000000..9ff0bde7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1b2fcf4655c847ef95af68f68fc9fc0a +timeCreated: 1695286287 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool.meta b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool.meta new file mode 100644 index 00000000..92318c0f --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bf1e53a3963b4dbf8c5f139ee8d80c3d +timeCreated: 1698301726 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSetting.cs b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSetting.cs new file mode 100644 index 00000000..03cd0f7c --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSetting.cs @@ -0,0 +1,45 @@ +using Sirenix.OdinInspector; +using UnityEngine; +using UnityEditor; + +/// +/// 自动绑定全局设置 +/// +public class AutoBindGlobalSetting : ScriptableObject +{ + [FolderPath] + [LabelText("默认组件代码保存路径")] + [SerializeField] + private string m_CodePath; + + [LabelText("绑定代码命名空间")] + [SerializeField] + private string m_Namespace; + + [LabelText("子组件名称(不会往下继续遍历)")] + [SerializeField] + private string m_WidgetName = "m_item"; + + public string CodePath => m_CodePath; + + public string Namespace => m_Namespace; + + public string WidgetName => m_WidgetName; + + [MenuItem("TEngine/CreateAutoBindGlobalSetting")] + private static void CreateAutoBindGlobalSetting() + { + string[] paths = AssetDatabase.FindAssets("t:AutoBindGlobalSetting"); + if (paths.Length >= 1) + { + string path = AssetDatabase.GUIDToAssetPath(paths[0]); + EditorUtility.DisplayDialog("警告", $"已存在AutoBindGlobalSetting,路径:{path}", "确认"); + return; + } + + AutoBindGlobalSetting setting = CreateInstance(); + AssetDatabase.CreateAsset(setting, "Assets/TEngine/ResRaw/AutoBindGlobalSetting.asset"); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSetting.cs.meta b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSetting.cs.meta new file mode 100644 index 00000000..b89331d2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSetting.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3dac541dae7b4c4d8b5497057739cfb0 +timeCreated: 1698304721 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSettingInspector.cs b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSettingInspector.cs new file mode 100644 index 00000000..fe8b6ed3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSettingInspector.cs @@ -0,0 +1,12 @@ +using Sirenix.OdinInspector.Editor; +using UnityEditor; + +[CustomEditor(typeof(AutoBindGlobalSetting))] +public class AutoBindGlobalSettingInspector : OdinEditor +{ + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + serializedObject.ApplyModifiedProperties(); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSettingInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSettingInspector.cs.meta new file mode 100644 index 00000000..f8c671be --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/AutoBindGlobalSettingInspector.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 020e5781e8c44c90bfbdf2cb12441e79 +timeCreated: 1698304745 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/ComponentAutoBindToolInspector.cs b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/ComponentAutoBindToolInspector.cs new file mode 100644 index 00000000..940b3425 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/ComponentAutoBindToolInspector.cs @@ -0,0 +1,534 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using System; +using BindData = ComponentAutoBindTool.BindData; +using System.Reflection; +using System.IO; + +[CustomEditor(typeof(ComponentAutoBindTool))] +public class ComponentAutoBindToolInspector : Editor +{ + private ComponentAutoBindTool m_Target; + + private SerializedProperty m_BindDatas; + private SerializedProperty m_BindComs; + private List m_TempList = new List(); + private List m_TempFiledNames = new List(); + private List m_TempComponentTypeNames = new List(); + + private string[] s_AssemblyNames = { "Assembly-CSharp", "TEngine.Runtime" }; + private string[] m_HelperTypeNames; + private string m_HelperTypeName; + private int m_HelperTypeNameIndex; + + private AutoBindGlobalSetting m_Setting; + + private SerializedProperty m_Namespace; + private SerializedProperty m_ClassName; + private SerializedProperty m_CodePath; + private SerializedProperty m_IsWidget; + + private void OnEnable() + { + m_Target = (ComponentAutoBindTool)target; + m_BindDatas = serializedObject.FindProperty("BindDatas"); + m_BindComs = serializedObject.FindProperty("bindComponents"); + + m_HelperTypeNames = GetTypeNames(typeof(IAutoBindRuleHelper), s_AssemblyNames); + + string[] paths = AssetDatabase.FindAssets("t:AutoBindGlobalSetting"); + if (paths.Length == 0) + { + Debug.LogError("不存在AutoBindGlobalSetting"); + return; + } + + if (paths.Length > 1) + { + Debug.LogError("AutoBindGlobalSetting数量大于1"); + return; + } + + string path = AssetDatabase.GUIDToAssetPath(paths[0]); + m_Setting = AssetDatabase.LoadAssetAtPath(path); + + + m_Namespace = serializedObject.FindProperty("m_Namespace"); + m_ClassName = serializedObject.FindProperty("m_ClassName"); + m_CodePath = serializedObject.FindProperty("m_CodePath"); + m_IsWidget = serializedObject.FindProperty("m_IsWidget"); + + m_Namespace.stringValue = string.IsNullOrEmpty(m_Namespace.stringValue) ? m_Setting.Namespace : m_Namespace.stringValue; + m_ClassName.stringValue = string.IsNullOrEmpty(m_ClassName.stringValue) ? m_Target.gameObject.name : m_ClassName.stringValue; + m_CodePath.stringValue = string.IsNullOrEmpty(m_CodePath.stringValue) ? m_Setting.CodePath : m_CodePath.stringValue; + + serializedObject.ApplyModifiedProperties(); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + DrawTopButton(); + + DrawHelperSelect(); + + DrawSetting(); + + DrawKvData(); + + serializedObject.ApplyModifiedProperties(); + } + + /// + /// 绘制顶部按钮 + /// + private void DrawTopButton() + { + EditorGUILayout.BeginHorizontal(); + + if (GUILayout.Button("排序")) + { + Sort(); + } + + if (GUILayout.Button("全部删除")) + { + RemoveAll(); + } + + if (GUILayout.Button("删除空引用")) + { + RemoveNull(); + } + + if (GUILayout.Button("自动绑定组件")) + { + AutoBindComponent(); + } + + if (GUILayout.Button("生成绑定代码")) + { + GenAutoBindCode(); + } + + EditorGUILayout.EndHorizontal(); + } + + /// + /// 排序 + /// + private void Sort() + { + m_TempList.Clear(); + foreach (BindData data in m_Target.BindDatas) + { + m_TempList.Add(new BindData(data.Name, data.BindCom, data.IsGameObject)); + } + + m_TempList.Sort((x, y) => string.Compare(x.Name, y.Name, StringComparison.Ordinal)); + + m_BindDatas.ClearArray(); + foreach (BindData data in m_TempList) + { + AddBindData(data.Name, data.BindCom, data.IsGameObject); + } + + SyncBindComs(); + } + + /// + /// 全部删除 + /// + private void RemoveAll() + { + m_BindDatas.ClearArray(); + + SyncBindComs(); + } + + /// + /// 删除空引用 + /// + private void RemoveNull() + { + for (int i = m_BindDatas.arraySize - 1; i >= 0; i--) + { + SerializedProperty element = m_BindDatas.GetArrayElementAtIndex(i).FindPropertyRelative("BindCom"); + if (element.objectReferenceValue == null) + { + m_BindDatas.DeleteArrayElementAtIndex(i); + } + } + + SyncBindComs(); + } + + /// + /// 自动绑定组件 + /// + private void AutoBindComponent() + { + m_BindDatas.ClearArray(); + + var transform = m_Target.transform; + Ergodic(transform, transform); + + SyncBindComs(); + } + + private void Ergodic(Transform rootTransform, Transform currentTransform) + { + for (int i = 0; i < currentTransform.childCount; ++i) + { + Transform child = currentTransform.GetChild(i); + + m_TempFiledNames.Clear(); + m_TempComponentTypeNames.Clear(); + + if (m_Target.RuleHelper.IsValidBind(child, m_TempFiledNames, m_TempComponentTypeNames)) + { + for (int index = 0; index < m_TempFiledNames.Count; index++) + { + string componentName = m_TempComponentTypeNames[index]; + bool isGameObject = componentName.Equals("GameObject"); + componentName = isGameObject ? "Transform" : componentName; + Component com = child.GetComponent(componentName); + if (com == null) + { + Debug.LogError($"{child.name}上不存在{componentName}的组件"); + } + else + { + AddBindData(m_TempFiledNames[index], child.GetComponent(componentName), isGameObject); + } + } + } + + if (!child.name.StartsWith(m_Setting.WidgetName)) + { + Ergodic(rootTransform, child); + } + } + } + + /// + /// 绘制辅助器选择框 + /// + private void DrawHelperSelect() + { + m_HelperTypeName = m_HelperTypeNames[0]; + + if (m_Target.RuleHelper != null) + { + m_HelperTypeName = m_Target.RuleHelper.GetType().Name; + + for (int i = 0; i < m_HelperTypeNames.Length; i++) + { + if (m_HelperTypeName == m_HelperTypeNames[i]) + { + m_HelperTypeNameIndex = i; + } + } + } + else + { + IAutoBindRuleHelper helper = (IAutoBindRuleHelper)CreateHelperInstance(m_HelperTypeName, s_AssemblyNames); + m_Target.RuleHelper = helper; + } + + foreach (GameObject go in Selection.gameObjects) + { + ComponentAutoBindTool autoBindTool = go.GetComponent(); + if (autoBindTool.RuleHelper == null) + { + IAutoBindRuleHelper helper = (IAutoBindRuleHelper)CreateHelperInstance(m_HelperTypeName, s_AssemblyNames); + autoBindTool.RuleHelper = helper; + } + } + + int selectedIndex = EditorGUILayout.Popup("AutoBindRuleHelper", m_HelperTypeNameIndex, m_HelperTypeNames); + if (selectedIndex != m_HelperTypeNameIndex) + { + m_HelperTypeNameIndex = selectedIndex; + m_HelperTypeName = m_HelperTypeNames[selectedIndex]; + IAutoBindRuleHelper helper = (IAutoBindRuleHelper)CreateHelperInstance(m_HelperTypeName, s_AssemblyNames); + m_Target.RuleHelper = helper; + } + } + + /// + /// 绘制设置项 + /// + private void DrawSetting() + { + EditorGUILayout.BeginHorizontal(); + m_Namespace.stringValue = EditorGUILayout.TextField(new GUIContent("命名空间:"), m_Namespace.stringValue); + if (GUILayout.Button("默认设置")) + { + m_Namespace.stringValue = m_Setting.Namespace; + } + + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + m_ClassName.stringValue = EditorGUILayout.TextField(new GUIContent("类名:"), m_ClassName.stringValue); + if (GUILayout.Button("物体名")) + { + m_ClassName.stringValue = m_Target.gameObject.name; + } + + EditorGUILayout.EndHorizontal(); + + bool isWidget = EditorGUILayout.Toggle("是否是组件", m_IsWidget.boolValue); + if (isWidget != m_IsWidget.boolValue) + { + m_IsWidget.boolValue = isWidget; + } + + EditorGUILayout.LabelField("代码保存路径:"); + EditorGUILayout.LabelField(m_CodePath.stringValue); + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("选择路径")) + { + string temp = m_CodePath.stringValue; + m_CodePath.stringValue = EditorUtility.OpenFolderPanel("选择代码保存路径", Application.dataPath, ""); + if (string.IsNullOrEmpty(m_CodePath.stringValue)) + { + m_CodePath.stringValue = temp; + } + } + + if (GUILayout.Button("默认设置")) + { + m_CodePath.stringValue = m_Setting.CodePath; + } + + EditorGUILayout.EndHorizontal(); + } + + /// + /// 绘制键值对数据 + /// + private void DrawKvData() + { + //绘制key value数据 + + int needDeleteIndex = -1; + + EditorGUILayout.BeginVertical(); + SerializedProperty property; + + for (int i = 0; i < m_BindDatas.arraySize; i++) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField($"[{i}]", GUILayout.Width(25)); + property = m_BindDatas.GetArrayElementAtIndex(i).FindPropertyRelative("Name"); + property.stringValue = EditorGUILayout.TextField(property.stringValue, GUILayout.Width(150)); + property = m_BindDatas.GetArrayElementAtIndex(i).FindPropertyRelative("BindCom"); + property.objectReferenceValue = EditorGUILayout.ObjectField(property.objectReferenceValue, typeof(Component), true); + + if (GUILayout.Button("X")) + { + //将元素下标添加进删除list + needDeleteIndex = i; + } + + EditorGUILayout.EndHorizontal(); + } + + //删除data + if (needDeleteIndex != -1) + { + m_BindDatas.DeleteArrayElementAtIndex(needDeleteIndex); + SyncBindComs(); + } + + EditorGUILayout.EndVertical(); + } + + /// + /// 添加绑定数据 + /// + private void AddBindData(string name, Component bindCom, bool isGameObject = false) + { + int index = m_BindDatas.arraySize; + m_BindDatas.InsertArrayElementAtIndex(index); + SerializedProperty element = m_BindDatas.GetArrayElementAtIndex(index); + element.FindPropertyRelative("Name").stringValue = name; + element.FindPropertyRelative("BindCom").objectReferenceValue = bindCom; + element.FindPropertyRelative("IsGameObject").boolValue = isGameObject; + } + + /// + /// 同步绑定数据 + /// + private void SyncBindComs() + { + m_BindComs.ClearArray(); + + for (int i = 0; i < m_BindDatas.arraySize; i++) + { + SerializedProperty property = m_BindDatas.GetArrayElementAtIndex(i).FindPropertyRelative("BindCom"); + m_BindComs.InsertArrayElementAtIndex(i); + m_BindComs.GetArrayElementAtIndex(i).objectReferenceValue = property.objectReferenceValue; + } + } + + /// + /// 获取指定基类在指定程序集中的所有子类名称 + /// + private string[] GetTypeNames(Type typeBase, string[] assemblyNames) + { + List typeNames = new List(); + foreach (string assemblyName in assemblyNames) + { + Assembly assembly = null; + try + { + assembly = Assembly.Load(assemblyName); + } + catch + { + continue; + } + + if (assembly == null) + { + continue; + } + + Type[] types = assembly.GetTypes(); + foreach (Type type in types) + { + if (type.IsClass && !type.IsAbstract && typeBase.IsAssignableFrom(type)) + { + typeNames.Add(type.FullName); + } + } + } + + typeNames.Sort(); + return typeNames.ToArray(); + } + + /// + /// 创建辅助器实例 + /// + private object CreateHelperInstance(string helperTypeName, string[] assemblyNames) + { + foreach (string assemblyName in assemblyNames) + { + Assembly assembly = Assembly.Load(assemblyName); + + object instance = assembly.CreateInstance(helperTypeName); + if (instance != null) + { + return instance; + } + } + + return null; + } + + + /// + /// 生成自动绑定代码 + /// + private void GenAutoBindCode() + { + GameObject go = m_Target.gameObject; + + string className = !string.IsNullOrEmpty(m_Target.ClassName) ? m_Target.ClassName : go.name; + string codePath = !string.IsNullOrEmpty(m_Target.CodePath) ? m_Target.CodePath : m_Setting.CodePath; + + if (!Directory.Exists(codePath)) + { + Debug.LogError($"{go.name}的代码保存路径{codePath}无效"); + } + + using (StreamWriter sw = new StreamWriter($"{codePath}/{className}.BindComponents.cs")) + { + sw.WriteLine( + "//------------------------------------------------------------------------------\n//\t\n//\t\tTime:[" + DateTime.Now + + "].\n//\t\tThis code was generated by autoBindTool.\n//\t\tChanges to this file may cause incorrect behavior and will be lost if\n//\t\tthe code is regenerated.\n//\t\n//------------------------------------------------------------------------------"); + sw.WriteLine("using UnityEngine;"); + sw.WriteLine("using UnityEngine.UI;"); + sw.WriteLine("using TEngine;"); + sw.WriteLine(""); + + if (!string.IsNullOrEmpty(m_Target.Namespace)) + { + //命名空间 + sw.WriteLine("namespace " + m_Target.Namespace); + sw.WriteLine("{"); + } + + //类名 + // if (!m_Target.IsWidget) + // { + // sw.WriteLine($"\tpublic partial class {className} : UIWindow"); + // } + // else + // { + // sw.WriteLine($"\tpublic partial class {className} : UIWidget"); + // } + sw.WriteLine($"\tpublic partial class {className}"); + sw.WriteLine("\t{"); + + //组件字段 + foreach (BindData data in m_Target.BindDatas) + { + if (data.IsGameObject) + { + sw.WriteLine($"\t\tprivate GameObject m_{data.Name};"); + } + else + { + sw.WriteLine($"\t\tprivate {data.BindCom.GetType().Name} m_{data.Name};"); + } + } + + sw.WriteLine(""); + + // sw.WriteLine( + // "\t\tpublic override void ScriptGenerator()\n\t\t{\n\t\t\tbase.ScriptGenerator();\n\t\t\tGetBindComponents(transform.gameObject);\n\t\t}"); + + sw.WriteLine("\t\tprivate void GetBindComponents(GameObject go)"); + sw.WriteLine("\t\t{"); + + //获取autoBindTool上的Component + sw.WriteLine($"\t\t\tComponentAutoBindTool autoBindTool = go.GetComponent();"); + sw.WriteLine(""); + + //根据索引获取 + + for (int i = 0; i < m_Target.BindDatas.Count; i++) + { + BindData data = m_Target.BindDatas[i]; + string filedName = $"m_{data.Name}"; + if (data.IsGameObject) + { + sw.WriteLine($"\t\t\t{filedName} = autoBindTool.GetBindComponent<{data.BindCom.GetType().Name}>({i}).gameObject;"); + } + else + { + sw.WriteLine($"\t\t\t{filedName} = autoBindTool.GetBindComponent<{data.BindCom.GetType().Name}>({i});"); + } + } + + sw.WriteLine("\t\t}"); + + sw.WriteLine("\t}"); + + if (!string.IsNullOrEmpty(m_Target.Namespace)) + { + sw.WriteLine("}"); + } + } + + AssetDatabase.Refresh(); + EditorUtility.DisplayDialog("提示", "代码生成完毕", "OK"); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/ComponentAutoBindToolInspector.cs.meta b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/ComponentAutoBindToolInspector.cs.meta new file mode 100644 index 00000000..def73a98 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/ComponentAutoBindTool/ComponentAutoBindToolInspector.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 77f2df681a094ff5a14e92e380ba90e7 +timeCreated: 1698304775 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/UI/ScriptGenerator.cs b/EintooAR/Assets/TEngine/Editor/UI/ScriptGenerator.cs new file mode 100644 index 00000000..7c7a9d1e --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/ScriptGenerator.cs @@ -0,0 +1,336 @@ +using System.Collections.Generic; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor.UI +{ + public class ScriptGenerator + { + private const string Gap = "/"; + + [MenuItem("GameObject/ScriptGenerator/UIProperty", priority = 41)] + public static void MemberProperty() + { + Generate(false); + } + + [MenuItem("GameObject/ScriptGenerator/UIProperty - UniTask", priority = 43)] + public static void MemberPropertyUniTask() + { + Generate(false, true); + } + + [MenuItem("GameObject/ScriptGenerator/UIPropertyAndListener", priority = 42)] + public static void MemberPropertyAndListener() + { + Generate(true); + } + + [MenuItem("GameObject/ScriptGenerator/UIPropertyAndListener - UniTask", priority = 44)] + public static void MemberPropertyAndListenerUniTask() + { + Generate(true, true); + } + + private static void Generate(bool includeListener, bool isUniTask = false) + { + var root = Selection.activeTransform; + if (root != null) + { + StringBuilder strVar = new StringBuilder(); + StringBuilder strBind = new StringBuilder(); + StringBuilder strOnCreate = new StringBuilder(); + StringBuilder strCallback = new StringBuilder(); + Ergodic(root, root, ref strVar, ref strBind, ref strOnCreate, ref strCallback, isUniTask); + StringBuilder strFile = new StringBuilder(); + + if (includeListener) + { +#if ENABLE_TEXTMESHPRO + strFile.Append("using TMPro;\n"); +#endif + if (isUniTask) + { + strFile.Append("using Cysharp.Threading.Tasks;\n"); + } + + strFile.Append("using UnityEngine;\n"); + strFile.Append("using UnityEngine.UI;\n"); + strFile.Append("using TEngine;\n\n"); + strFile.Append($"namespace {SettingsUtils.GetUINameSpace()}\n"); + strFile.Append("{\n"); + strFile.Append("\t[Window(UILayer.UI)]\n"); + strFile.Append("\tclass " + root.name + " : UIWindow\n"); + strFile.Append("\t{\n"); + } + + // 脚本工具生成的代码 + strFile.Append("\t\t#region 脚本工具生成的代码\n"); + strFile.Append(strVar); + strFile.Append("\t\tprotected override void ScriptGenerator()\n"); + strFile.Append("\t\t{\n"); + strFile.Append(strBind); + strFile.Append(strOnCreate); + strFile.Append("\t\t}\n"); + strFile.Append("\t\t#endregion"); + + if (includeListener) + { + strFile.Append("\n\n"); + // #region 事件 + strFile.Append("\t\t#region 事件\n"); + strFile.Append(strCallback); + strFile.Append("\t\t#endregion\n\n"); + + strFile.Append("\t}\n"); + strFile.Append("}\n"); + } + + TextEditor te = new TextEditor(); + te.text = strFile.ToString(); + te.SelectAll(); + te.Copy(); + } + UnityEngine.Debug.Log($"脚本已生成到剪贴板,请自行Ctl+V粘贴"); + } + + public static void Ergodic(Transform root, Transform transform, ref StringBuilder strVar, ref StringBuilder strBind, ref StringBuilder strOnCreate, + ref StringBuilder strCallback, bool isUniTask) + { + for (int i = 0; i < transform.childCount; ++i) + { + Transform child = transform.GetChild(i); + WriteScript(root, child, ref strVar, ref strBind, ref strOnCreate, ref strCallback, isUniTask); + if (child.name.StartsWith("m_item")) + { + // 子 Item 不再往下遍历 + continue; + } + + Ergodic(root, child, ref strVar, ref strBind, ref strOnCreate, ref strCallback, isUniTask); + } + } + + private static string GetRelativePath(Transform child, Transform root) + { + StringBuilder path = new StringBuilder(); + path.Append(child.name); + while (child.parent != null && child.parent != root) + { + child = child.parent; + path.Insert(0, Gap); + path.Insert(0, child.name); + } + + return path.ToString(); + } + + public static string GetBtnFuncName(string varName) + { + return "OnClick" + varName.Replace("m_btn", string.Empty) + "Btn"; + } + + public static string GetToggleFuncName(string varName) + { + return "OnToggle" + varName.Replace("m_toggle", string.Empty) + "Change"; + } + + public static string GetSliderFuncName(string varName) + { + return "OnSlider" + varName.Replace("m_slider", string.Empty) + "Change"; + } + + private static void WriteScript(Transform root, Transform child, ref StringBuilder strVar, ref StringBuilder strBind, ref StringBuilder strOnCreate, + ref StringBuilder strCallback, bool isUniTask) + { + string varName = child.name; + string componentName = string.Empty; + + var rule = SettingsUtils.GetScriptGenerateRule().Find(t => varName.StartsWith(t.uiElementRegex)); + + if (rule != null) + { + componentName = rule.componentName; + } + + if (componentName == string.Empty) + { + return; + } + + string varPath = GetRelativePath(child, root); + if (!string.IsNullOrEmpty(varName)) + { + strVar.Append("\t\tprivate " + componentName + " " + varName + ";\n"); + switch (componentName) + { + case "Transform": + strBind.Append($"\t\t\t{varName} = FindChild(\"{varPath}\");\n"); + break; + case "GameObject": + strBind.Append($"\t\t\t{varName} = FindChild(\"{varPath}\").gameObject;\n"); + break; + case "AnimationCurve": + strBind.Append($"\t\t\t{varName} = FindChildComponent(\"{varPath}\").m_animCurve;\n"); + break; + case "RichItemIcon": + case "CommonFightWidget": + case "PlayerHeadWidget": + strBind.Append($"\t\t\t{varName} = CreateWidgetByType<{componentName}>(\"{varPath}\");\n"); + break; + case "RedNoteBehaviour": + case "TextButtonItem": + case "SwitchTabItem": + case "UIActorWidget": + case "UIEffectWidget": + case "UISpineWidget": + strBind.Append($"\t\t\t{varName} = CreateWidget<{componentName}>(\"{varPath}\");\n"); + break; + case "ActorNameBinderText": + strBind.Append($"\t\t\t{varName} = FindTextBinder(\"{varPath}\");\n"); + break; + case "ActorNameBinderEffect": + strBind.Append($"\t\t\t{varName} = FindEffectBinder(\"{varPath}\");\n"); + break; + default: + strBind.Append($"\t\t\t{varName} = FindChildComponent<{componentName}>(\"{varPath}\");\n"); + break; + } + + if (componentName == "Button") + { + string varFuncName = GetBtnFuncName(varName); + if (isUniTask) + { + strOnCreate.Append($"\t\t\t{varName}.onClick.AddListener(UniTask.UnityAction({varFuncName}));\n"); + strCallback.Append($"\t\tprivate async UniTaskVoid {varFuncName}()\n"); + strCallback.Append("\t\t{\n await UniTask.Yield();\n\t\t}\n"); + } + else + { + strOnCreate.Append($"\t\t\t{varName}.onClick.AddListener({varFuncName});\n"); + strCallback.Append($"\t\tprivate void {varFuncName}()\n"); + strCallback.Append("\t\t{\n\t\t}\n"); + } + } + else if (componentName == "Toggle") + { + string varFuncName = GetToggleFuncName(varName); + strOnCreate.Append($"\t\t\t{varName}.onValueChanged.AddListener({varFuncName});\n"); + strCallback.Append($"\t\tprivate void {varFuncName}(bool isOn)\n"); + strCallback.Append("\t\t{\n\t\t}\n"); + } + else if (componentName == "Slider") + { + string varFuncName = GetSliderFuncName(varName); + strOnCreate.Append($"\t\t\t{varName}.onValueChanged.AddListener({varFuncName});\n"); + strCallback.Append($"\t\tprivate void {varFuncName}(float value)\n"); + strCallback.Append("\t\t{\n\t\t}\n"); + } + } + } + + public class GeneratorHelper : EditorWindow + { + [MenuItem("GameObject/ScriptGenerator/About", priority = 49)] + public static void About() + { + GeneratorHelper welcomeWindow = (GeneratorHelper)EditorWindow.GetWindow(typeof(GeneratorHelper), false, "About"); + } + + public void Awake() + { + minSize = new Vector2(400, 600); + } + + protected void OnGUI() + { + GUILayout.BeginVertical(); + foreach (var item in SettingsUtils.GetScriptGenerateRule()) + { + GUILayout.Label(item.uiElementRegex + ":\t" + item.componentName); + } + + GUILayout.EndVertical(); + } + } + + public class SwitchGroupGenerator + { + private const string Condition = "m_switchGroup"; + + public static readonly SwitchGroupGenerator Instance = new SwitchGroupGenerator(); + + public string Process(Transform root) + { + var sbd = new StringBuilder(); + var list = new List(); + Collect(root, list); + foreach (var node in list) + { + sbd.AppendLine(Process(root, node)).AppendLine(); + } + + return sbd.ToString(); + } + + public void Collect(Transform node, List nodeList) + { + if (node.name.StartsWith(Condition)) + { + nodeList.Add(node); + return; + } + + var childCnt = node.childCount; + for (var i = 0; i < childCnt; i++) + { + var child = node.GetChild(i); + Collect(child, nodeList); + } + } + + private string Process(Transform root, Transform groupTf) + { + var parentPath = GetPath(root, groupTf); + var name = groupTf.name; + var sbd = new StringBuilder(@" +var _namePath = ""#parentPath""; +var _nameTf = FindChild(_namePath); +var childCnt = _nameTf.childCount; +SwitchTabItem[] _name; +_name = new SwitchTabItem[childCnt]; +for (var i = 0; i < childCnt; i++) +{ + var child = _nameTf.GetChild(i); + _name[i] = CreateWidget(_namePath + ""/"" + child.name); +}"); + sbd.Replace("_name", name); + sbd.Replace("#parentPath", parentPath); + return sbd.ToString(); + } + + public string GetPath(Transform root, Transform childTf) + { + if (childTf == null) + { + return string.Empty; + } + + if (childTf == root) + { + return childTf.name; + } + + var parentPath = GetPath(root, childTf.parent); + if (parentPath == string.Empty) + { + return childTf.name; + } + + return parentPath + "/" + childTf.name; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/UI/ScriptGenerator.cs.meta b/EintooAR/Assets/TEngine/Editor/UI/ScriptGenerator.cs.meta new file mode 100644 index 00000000..5934b0f1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/ScriptGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5cde6b81462affb4bac5ca8cd0862f38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/UI/TEUIHelper.cs b/EintooAR/Assets/TEngine/Editor/UI/TEUIHelper.cs new file mode 100644 index 00000000..57e8fd9b --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/TEUIHelper.cs @@ -0,0 +1,73 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using UnityEngine; +#region +//作者:Saber +#endregion +namespace TEngine.Editor.UI +{ + public class TEUIHelper + { + + public static string Generate(bool includeListener, bool isUniTask = false, Transform root = null, string nameSpace = "",string className="") + { + if (root != null) + { + StringBuilder strVar = new StringBuilder(); + StringBuilder strBind = new StringBuilder(); + StringBuilder strOnCreate = new StringBuilder(); + StringBuilder strCallback = new StringBuilder(); + + ScriptGenerator.Ergodic(root, root, ref strVar, ref strBind, ref strOnCreate, ref strCallback, isUniTask); + + //object[] args = new object[] { root, root, strVar, strBind, strOnCreate, strCallback, isUniTask }; + //typeof(TEngine.Editor.UI.ScriptGenerator).GetMethod("Ergodic",System.Reflection.BindingFlags.NonPublic| System.Reflection.BindingFlags.Static).Invoke(null,args); + //strVar = args[2] as StringBuilder; + //strBind = args[3] as StringBuilder; + //strOnCreate = args[4] as StringBuilder; + //strCallback = args[5] as StringBuilder; + + StringBuilder strFile = new StringBuilder(); + + if (includeListener) + { +#if ENABLE_TEXTMESHPRO + strFile.Append("using TMPro;\n"); +#endif + if (isUniTask) + { + strFile.Append("using Cysharp.Threading.Tasks;\n"); + } + } + strFile.Append("using UnityEngine;\n"); + strFile.Append("using UnityEngine.UI;\n"); + strFile.Append("using TEngine;\n\n"); + nameSpace = string.IsNullOrEmpty(nameSpace) ? SettingsUtils.GetUINameSpace() : nameSpace; + strFile.Append($"namespace {nameSpace}\n"); + strFile.Append("{\n"); + //strFile.Append("\t[Window(UILayer.UI)]\n"); + strFile.Append("\tpartial class " + className + "\n"); + strFile.Append("\t{\n"); + + // 脚本工具生成的代码 + strFile.Append("\t\t#region 脚本工具生成的代码\n"); + strFile.Append(strVar); + strFile.Append("\t\tprotected override void ScriptGenerator()\n"); + strFile.Append("\t\t{\n"); + strFile.Append(strBind); + strFile.Append(strOnCreate); + strFile.Append("\t\t}\n"); + strFile.Append("\t\t#endregion"); + + strFile.Append("\n\t}"); + strFile.Append("\n}"); + return strFile.ToString(); + + } + return string.Empty; + } + + } +} + diff --git a/EintooAR/Assets/TEngine/Editor/UI/TEUIHelper.cs.meta b/EintooAR/Assets/TEngine/Editor/UI/TEUIHelper.cs.meta new file mode 100644 index 00000000..23acdd8a --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/TEUIHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 783105f2b5405eb45bb29a4f5131dc3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/UI/TEUIHelperWindiw.cs b/EintooAR/Assets/TEngine/Editor/UI/TEUIHelperWindiw.cs new file mode 100644 index 00000000..806b04ee --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/TEUIHelperWindiw.cs @@ -0,0 +1,138 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using Sirenix.OdinInspector; +using Sirenix.OdinInspector.Editor; +using System.IO; +using UnityEditor; +using UnityEditor.SceneManagement; +#region +//作者:Saber +#endregion +namespace TEngine.Editor.UI +{ + + public class TEUIToolWindow : OdinEditorWindow + { + public enum Type + { + normal, + unitask, + listener, + all + } + [ReadOnly, LabelText("选中物体")] + public Transform root; + [LabelText("生成类型")] + public Type type; + [LabelText("命名空间")] + public string nameSpace = ""; + [LabelText("类名")] + public string className; + [LabelText("生成位置"), FolderPath] + public string savePath= "Assets/Scripts/UIScriptsAuto"; + + [ReadOnly, LabelText("生成的脚本"),HorizontalGroup(GroupID ="BS")] + public TextAsset buildScript; + + protected override void OnDisable() + { + base.OnDisable(); + Save(); + + } + void Save() + { + EditorPrefs.SetString($"Last_UIScriptsAutoNameSpace", nameSpace); + EditorPrefs.SetInt($"Last_UIScriptsAutoType", (int)type); + EditorPrefs.SetString($"Last_UIScriptsAutoSavePath", savePath); + } + void Load() + { + nameSpace = EditorPrefs.GetString($"Last_UIScriptsAutoNameSpace", nameSpace); + type = (Type)EditorPrefs.GetInt($"Last_UIScriptsAutoType", (int)type); + var newSavePath = EditorPrefs.GetString($"Last_UIScriptsAutoSavePath", savePath); + if (string.IsNullOrEmpty(newSavePath)==false) + { + savePath = newSavePath; + OnSavePathChange(); + } + } + void OnSavePathChange() + { + var originPath = $"{savePath}/{className}_Auto.cs"; + var path = Path.GetFullPath(originPath); + if (File.Exists(path)) + buildScript = AssetDatabase.LoadAssetAtPath(originPath); + } + [Button(SdfIconType.Trash, Name = ""), HorizontalGroup(GroupID = "BS", Width = 50)] + void Delete() + { + AssetDatabase.DeleteAsset($"{savePath}/{className}.cs"); + buildScript = null; + } + [Sirenix.OdinInspector.PropertySpace(30)] + [Button(Icon = SdfIconType.Gem, Name = "生成"), HorizontalGroup(GroupID = "AA" /*, Width = 150*/,MinWidth =200,MarginLeft =0.3f,MarginRight =0.3f)] + public void Build() + { + var str = TEUIHelper.Generate(type == Type.listener || type == Type.all, type == Type.unitask || type == Type.all, root, nameSpace, className); + if (string.IsNullOrEmpty(str)) + { + Debug.LogError("出错啦,请检查是否选中root为空" + root == null); + return; + } + var originPath = $"{savePath}/{className}_Auto.cs"; + var path = Path.GetFullPath(originPath); + MakeSure(path); + File.WriteAllText(path, str); + AssetDatabase.Refresh(); + buildScript= AssetDatabase.LoadAssetAtPath(originPath); + Debug.Log($"保存完毕:Cs->{className}.cs ,位置:{path}"); + } + + public void OnInit(Transform root) + { + this.root = root; + this.className = this.root.name; + Load(); + } + [MenuItem("GameObject/ScriptGenerator/BuildWindow", priority = 40)] + static void OpenWindow() + { + var root = Selection.activeTransform; + if (root != null && (PrefabUtility.IsPartOfAnyPrefab(root) || (PrefabStageUtility.GetCurrentPrefabStage() != null && PrefabStageUtility.GetCurrentPrefabStage().IsPartOfPrefabContents(root.gameObject)))) + { + var window = GetWindow(); + // 设置窗口大小 + window.minSize = new Vector2(600, 250); + window.OnInit(root); + + } + else + Debug.LogError("仅支持预制体,请选中预制体"); + } + static void OpenTopWindow() + { + var window = EditorWindow.GetWindow(); + //Debug.Log("windiw" + window.name + "_aaa"); + window.position = new Rect(0, 0, 600, 800); + } + + public static void MakeSure(string path) + { + path = path.Replace("\\", "/"); + var extion = Path.GetExtension(path); + + var dire = System.IO.Path.GetDirectoryName(path); + if (System.IO.Directory.Exists(dire) == false) + System.IO.Directory.CreateDirectory(dire); + + if (string.IsNullOrEmpty(extion) == false) + { + if (System.IO.File.Exists(path) == false) + System.IO.File.Create(path).Dispose(); + } + } + } +} + diff --git a/EintooAR/Assets/TEngine/Editor/UI/TEUIHelperWindiw.cs.meta b/EintooAR/Assets/TEngine/Editor/UI/TEUIHelperWindiw.cs.meta new file mode 100644 index 00000000..21a0001f --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/UI/TEUIHelperWindiw.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1012810e422c9249a0e302985d02b45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Utility.meta b/EintooAR/Assets/TEngine/Editor/Utility.meta new file mode 100644 index 00000000..fc80b2d7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1ed0876b4517e58479840179b3fde246 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Utility/ClassHelper.cs b/EintooAR/Assets/TEngine/Editor/Utility/ClassHelper.cs new file mode 100644 index 00000000..531f860d --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/ClassHelper.cs @@ -0,0 +1,69 @@ +using UnityEditor; +using UnityEngine; + +/// +/// Unity编辑器类帮助类。 +/// +public static class ClassHelper +{ + /// + /// 获取MonoBehaviour的脚本Id。 + /// + /// 脚本类型。 + /// 脚本Id。 + public static int GetClassID(System.Type type) + { + GameObject gameObject = EditorUtility.CreateGameObjectWithHideFlags("Temp", HideFlags.HideAndDontSave); + Component component = gameObject.AddComponent(type); + SerializedObject @class = new SerializedObject(component); + int classID = @class.FindProperty("m_Script").objectReferenceInstanceIDValue; + Object.DestroyImmediate(gameObject); + return classID; + } + + /// + /// 获取MonoBehaviour的脚本Id。 + /// + /// 脚本类型。 + /// 脚本Id。 + public static int GetClassID() where T : MonoBehaviour + { + return GetClassID(typeof(T)); + } + + #region Method Documentation + /************************************************************************************************************ + Example: + [MenuItem("GameObject/UI/转化成CustomText", false, 1999)] + public static void ConvertToCustomText(MenuCommand menuCommand) + { + GameObject go = menuCommand.context as GameObject; + if (go != null) + { + Text text = go.GetComponent(); + if (text != null) + { + var ob = ClassHelper.ReplaceClass(text, typeof(CustomText)); + ob.ApplyModifiedProperties(); + } + } + } + ************************************************************************************************************/ + #endregion + /// + /// 替换MonoBehaviour脚本。 + /// + /// + /// + /// + public static SerializedObject ReplaceClass(MonoBehaviour monoBehaviour, System.Type type) + { + int classID = GetClassID(type); + SerializedObject @class = new SerializedObject(monoBehaviour); + @class.Update(); + @class.FindProperty("m_Script").objectReferenceInstanceIDValue = classID; + @class.ApplyModifiedProperties(); + @class.Update(); + return @class; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Utility/ClassHelper.cs.meta b/EintooAR/Assets/TEngine/Editor/Utility/ClassHelper.cs.meta new file mode 100644 index 00000000..8150e8c7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/ClassHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: aa5c786315234462bb549c4533d4d858 +timeCreated: 1698042158 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Utility/CommandLineReader.cs b/EintooAR/Assets/TEngine/Editor/Utility/CommandLineReader.cs new file mode 100644 index 00000000..5167c4d5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/CommandLineReader.cs @@ -0,0 +1,120 @@ +#region Class Documentation +/************************************************************************************************************ +Class Name: CommandLineReader.cs +Type: Util, Static +Definition: + CommandLineReader.cs give the ability to access [Custom Arguments] sent + through the command line. Simply add your custom arguments under the + keyword '-CustomArgs:' and seperate them by ';'. +Example: + C:\Program Files (x86)\Unity\Editor\Unity.exe [ProjectLocation] -executeMethod [Your entrypoint] -quit -CustomArgs:Language=en_US;Version=1.02 + +Example1: + set WORKSPACE=. + set UNITYEDITOR_PATH=G:/UnityEditor/2021.3.20f1c1/Editor + set LOGFILE=./build.log + set BUILDROOT=G:/github/TEngine/UnityProject/Bundles + + %UNITYEDITOR_PATH%/Unity.exe %WORKSPACE%/UnityProject -logFile %LOGFILE% -executeMethod TEngine.ReleaseTools.BuildPackage -quit -batchmode -CustomArgs:Language=en_US;Version=1.02;outputRoot=%BUILDROOT% + + @REM for /f "delims=[" %%i in (%LOGFILE%) do echo %%i + + pause +************************************************************************************************************/ +#endregion + +#region Using +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using Debug = UnityEngine.Debug; +#endregion + +/// +/// Unity命令行拓展帮助类。 +/// 可以用来制定自己项目的打包、编辑器工作流。 +/// +public class CommandLineReader +{ + //Config + private const string CUSTOM_ARGS_PREFIX = "-CustomArgs:"; + private const char CUSTOM_ARGS_SEPARATOR = ';'; + + public static string[] GetCommandLineArgs() + { + return Environment.GetCommandLineArgs(); + } + + public static string GetCommandLine() + { + string[] args = GetCommandLineArgs(); + + if (args.Length > 0) + { + return string.Join(" ", args); + } + else + { + Debug.LogError("CommandLineReader.cs - GetCommandLine() - Can't find any command line arguments!"); + return ""; + } + } + + public static Dictionary GetCustomArguments() + { + Dictionary customArgsDict = new Dictionary(); + string[] commandLineArgs = GetCommandLineArgs(); + string[] customArgs; + string[] customArgBuffer; + string customArgsStr = ""; + + try + { + customArgsStr = commandLineArgs.Where(row => row.Contains(CUSTOM_ARGS_PREFIX)).Single(); + } + catch (Exception e) + { + Debug.LogError("CommandLineReader.cs - GetCustomArguments() - Can't retrieve any custom arguments in the command line [" + commandLineArgs + "]. Exception: " + e); + return customArgsDict; + } + + customArgsStr = customArgsStr.Replace(CUSTOM_ARGS_PREFIX, ""); + customArgs = customArgsStr.Split(CUSTOM_ARGS_SEPARATOR); + + foreach (string customArg in customArgs) + { + customArgBuffer = customArg.Split('='); + if (customArgBuffer.Length == 2) + { + customArgsDict.Add(customArgBuffer[0], customArgBuffer[1]); + } + else + { + Debug.LogWarning("CommandLineReader.cs - GetCustomArguments() - The custom argument [" + customArg + "] seem to be malformed."); + } + } + + return customArgsDict; + } + + /// + /// 获取cmd输入的自定义参数数值。 + /// + /// 自定义参数名称。 + /// 自定义参数数值。 + public static string GetCustomArgument(string argumentName) + { + Dictionary customArgsDict = GetCustomArguments(); + + if (customArgsDict.TryGetValue(argumentName, out var argument)) + { + return argument; + } + else + { + Debug.LogError("CommandLineReader.cs - GetCustomArgument() - Can't retrieve any custom argument named [" + argumentName + "] in the command line [" + GetCommandLine() + "]."); + return ""; + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Utility/CommandLineReader.cs.meta b/EintooAR/Assets/TEngine/Editor/Utility/CommandLineReader.cs.meta new file mode 100644 index 00000000..66cfde6a --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/CommandLineReader.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9f4bc66bca9a460cb714a36a127739e7 +timeCreated: 1698041943 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Utility/GetAssetHelper.cs b/EintooAR/Assets/TEngine/Editor/Utility/GetAssetHelper.cs new file mode 100644 index 00000000..c1e72dce --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/GetAssetHelper.cs @@ -0,0 +1,41 @@ +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor +{ + /// + /// 获取资源路径相关的实用函数。 + /// + public static class GetAssetHelper + { + [MenuItem("Assets/Get Asset Path", priority = 3)] + static void GetAssetPath() + { + UnityEngine.Object selObj = Selection.activeObject; + + if (selObj != null) + { + string assetPath = AssetDatabase.GetAssetPath(selObj); + EditorGUIUtility.systemCopyBuffer = assetPath; + Debug.Log($"Asset path is {assetPath}"); + } + } + + [MenuItem("Assets/Get Addressable Path", priority = 3)] + static void GetAddressablePath() + { + UnityEngine.Object selObj = Selection.activeObject; + + if (selObj != null) + { + string assetPath = AssetDatabase.GetAssetPath(selObj); + var split = assetPath.Split('/'); + var name = split.Last(); + assetPath = name.Split('.').First(); + EditorGUIUtility.systemCopyBuffer = assetPath; + Debug.Log($"Addressable path is {assetPath}"); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Utility/GetAssetHelper.cs.meta b/EintooAR/Assets/TEngine/Editor/Utility/GetAssetHelper.cs.meta new file mode 100644 index 00000000..f1060ca3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/GetAssetHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9cda2f3725dfe964a94ccdc9218e8ebc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Utility/HelperInfo.cs b/EintooAR/Assets/TEngine/Editor/Utility/HelperInfo.cs new file mode 100644 index 00000000..72305ad1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/HelperInfo.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor +{ + internal sealed class HelperInfo where T : MonoBehaviour + { + private const string CustomOptionName = ""; + + private readonly string m_Name; + + private SerializedProperty m_HelperTypeName; + private SerializedProperty m_CustomHelper; + private string[] m_HelperTypeNames; + private int m_HelperTypeNameIndex; + + public HelperInfo(string name) + { + m_Name = name; + + m_HelperTypeName = null; + m_CustomHelper = null; + m_HelperTypeNames = null; + m_HelperTypeNameIndex = 0; + } + + public void Init(SerializedObject serializedObject) + { + m_HelperTypeName = serializedObject.FindProperty(Utility.Text.Format("m_{0}HelperTypeName", m_Name)); + m_CustomHelper = serializedObject.FindProperty(Utility.Text.Format("m_Custom{0}Helper", m_Name)); + } + + public void Draw() + { + string displayName = FieldNameForDisplay(m_Name); + int selectedIndex = EditorGUILayout.Popup(Utility.Text.Format("{0} Helper", displayName), m_HelperTypeNameIndex, m_HelperTypeNames); + if (selectedIndex != m_HelperTypeNameIndex) + { + m_HelperTypeNameIndex = selectedIndex; + m_HelperTypeName.stringValue = selectedIndex <= 0 ? null : m_HelperTypeNames[selectedIndex]; + } + + if (m_HelperTypeNameIndex <= 0) + { + EditorGUILayout.PropertyField(m_CustomHelper); + if (m_CustomHelper.objectReferenceValue == null) + { + EditorGUILayout.HelpBox(Utility.Text.Format("You must set Custom {0} Helper.", displayName), MessageType.Error); + } + } + } + + public void Refresh() + { + List helperTypeNameList = new List + { + CustomOptionName + }; + + helperTypeNameList.AddRange(Type.GetRuntimeTypeNames(typeof(T))); + m_HelperTypeNames = helperTypeNameList.ToArray(); + + m_HelperTypeNameIndex = 0; + if (!string.IsNullOrEmpty(m_HelperTypeName.stringValue)) + { + m_HelperTypeNameIndex = helperTypeNameList.IndexOf(m_HelperTypeName.stringValue); + if (m_HelperTypeNameIndex <= 0) + { + m_HelperTypeNameIndex = 0; + m_HelperTypeName.stringValue = null; + } + } + } + + private string FieldNameForDisplay(string fieldName) + { + if (string.IsNullOrEmpty(fieldName)) + { + return string.Empty; + } + + string str = Regex.Replace(fieldName, @"^m_", string.Empty); + str = Regex.Replace(str, @"((?<=[a-z])[A-Z]|[A-Z](?=[a-z]))", @" $1").TrimStart(); + return str; + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Utility/HelperInfo.cs.meta b/EintooAR/Assets/TEngine/Editor/Utility/HelperInfo.cs.meta new file mode 100644 index 00000000..79841bae --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/HelperInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5e1e932beb704b8d855ada90d41d6b56 +timeCreated: 1695116209 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Utility/LogRedirection.cs b/EintooAR/Assets/TEngine/Editor/Utility/LogRedirection.cs new file mode 100644 index 00000000..ac27b0a6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/LogRedirection.cs @@ -0,0 +1,123 @@ +using System; +using System.Reflection; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEditorInternal; + +namespace TEngine.Editor +{ + /// + /// 日志重定向相关的实用函数。 + /// + internal static class LogRedirection + { + [OnOpenAsset(0)] + private static bool OnOpenAsset(int instanceID, int line) + { + if (line <= 0) + { + return false; + } + // 获取资源路径 + string assetPath = AssetDatabase.GetAssetPath(instanceID); + + // 判断资源类型 + if (!assetPath.EndsWith(".cs")) + { + return false; + } + + bool autoFirstMatch = assetPath.Contains("Logger.cs") || + assetPath.Contains("DefaultLogHelper.cs") || + assetPath.Contains("GameFrameworkLog.cs") || + assetPath.Contains("AssetsLogger.cs") || + assetPath.Contains("Log.cs"); + + var stackTrace = GetStackTrace(); + if (!string.IsNullOrEmpty(stackTrace) && (stackTrace.Contains("[Debug]") || + stackTrace.Contains("[INFO]") || + stackTrace.Contains("[ASSERT]") || + stackTrace.Contains("[WARNING]") || + stackTrace.Contains("[ERROR]") || + stackTrace.Contains("[EXCEPTION]"))) + + { + if (!autoFirstMatch) + { + var fullPath = UnityEngine.Application.dataPath.Substring(0, UnityEngine.Application.dataPath.LastIndexOf("Assets", StringComparison.Ordinal)); + fullPath = $"{fullPath}{assetPath}"; + // 跳转到目标代码的特定行 + InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line); + return true; + } + + // 使用正则表达式匹配at的哪个脚本的哪一行 + var matches = Regex.Match(stackTrace, @"\(at (.+)\)", + RegexOptions.IgnoreCase); + while (matches.Success) + { + var pathLine = matches.Groups[1].Value; + + if (!pathLine.Contains("Logger.cs") && + !pathLine.Contains("DefaultLogHelper.cs") && + !pathLine.Contains("GameFrameworkLog.cs") && + !pathLine.Contains("AssetsLogger.cs") && + !pathLine.Contains("Log.cs")) + { + var splitIndex = pathLine.LastIndexOf(":", StringComparison.Ordinal); + // 脚本路径 + var path = pathLine.Substring(0, splitIndex); + // 行号 + line = Convert.ToInt32(pathLine.Substring(splitIndex + 1)); + var fullPath = UnityEngine.Application.dataPath.Substring(0, UnityEngine.Application.dataPath.LastIndexOf("Assets", StringComparison.Ordinal)); + fullPath = $"{fullPath}{path}"; + // 跳转到目标代码的特定行 + InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line); + break; + } + + matches = matches.NextMatch(); + } + + return true; + } + + return false; + } + + /// + /// 获取当前日志窗口选中的日志的堆栈信息。 + /// + /// 选中日志的堆栈信息实例。 + private static string GetStackTrace() + { + // 通过反射获取ConsoleWindow类 + var consoleWindowType = typeof(EditorWindow).Assembly.GetType("UnityEditor.ConsoleWindow"); + // 获取窗口实例 + var fieldInfo = consoleWindowType.GetField("ms_ConsoleWindow", + BindingFlags.Static | + BindingFlags.NonPublic); + if (fieldInfo != null) + { + var consoleInstance = fieldInfo.GetValue(null); + if (consoleInstance != null) + if (EditorWindow.focusedWindow == (EditorWindow)consoleInstance) + { + // 获取m_ActiveText成员 + fieldInfo = consoleWindowType.GetField("m_ActiveText", + BindingFlags.Instance | + BindingFlags.NonPublic); + // 获取m_ActiveText的值 + if (fieldInfo != null) + { + var activeText = fieldInfo.GetValue(consoleInstance).ToString(); + return activeText; + } + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Utility/LogRedirection.cs.meta b/EintooAR/Assets/TEngine/Editor/Utility/LogRedirection.cs.meta new file mode 100644 index 00000000..f7ace159 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/LogRedirection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e219db54fde57a4aae694a55da3e1b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Utility/OpenFolderHelper.cs b/EintooAR/Assets/TEngine/Editor/Utility/OpenFolderHelper.cs new file mode 100644 index 00000000..77b67dfd --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/OpenFolderHelper.cs @@ -0,0 +1,83 @@ +using System.Diagnostics; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Editor +{ + /// + /// 打开文件夹相关的实用函数。 + /// + public static class OpenFolderHelper + { + /// + /// 打开 Data Path 文件夹。 + /// + [MenuItem("TEngine/Open Folder/Data Path", false, 10)] + public static void OpenFolderDataPath() + { + Execute(Application.dataPath); + } + + /// + /// 打开 Persistent Data Path 文件夹。 + /// + [MenuItem("TEngine/Open Folder/Persistent Data Path", false, 11)] + public static void OpenFolderPersistentDataPath() + { + Execute(Application.persistentDataPath); + } + + /// + /// 打开 Streaming Assets Path 文件夹。 + /// + [MenuItem("TEngine/Open Folder/Streaming Assets Path", false, 12)] + public static void OpenFolderStreamingAssetsPath() + { + Execute(Application.streamingAssetsPath); + } + + /// + /// 打开 Temporary Cache Path 文件夹。 + /// + [MenuItem("TEngine/Open Folder/Temporary Cache Path", false, 13)] + public static void OpenFolderTemporaryCachePath() + { + Execute(Application.temporaryCachePath); + } + +#if UNITY_2018_3_OR_NEWER + + /// + /// 打开 Console Log Path 文件夹。 + /// + [MenuItem("TEngine/Open Folder/Console Log Path", false, 14)] + public static void OpenFolderConsoleLogPath() + { + Execute(System.IO.Path.GetDirectoryName(Application.consoleLogPath)); + } + +#endif + + /// + /// 打开指定路径的文件夹。 + /// + /// 要打开的文件夹的路径。 + public static void Execute(string folder) + { + folder = $"\"{folder}\""; + switch (Application.platform) + { + case RuntimePlatform.WindowsEditor: + Process.Start("Explorer.exe", folder.Replace('/', '\\')); + break; + + case RuntimePlatform.OSXEditor: + Process.Start("open", folder); + break; + + default: + throw new System.Exception($"Not support open folder on '{Application.platform}' platform."); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Editor/Utility/OpenFolderHelper.cs.meta b/EintooAR/Assets/TEngine/Editor/Utility/OpenFolderHelper.cs.meta new file mode 100644 index 00000000..4f3bbaa5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/OpenFolderHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce4febf89f4174a46be07146ae57de86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Editor/Utility/ShellHelper.cs b/EintooAR/Assets/TEngine/Editor/Utility/ShellHelper.cs new file mode 100644 index 00000000..057a4751 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/ShellHelper.cs @@ -0,0 +1,106 @@ +using System; +using System.Diagnostics; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// Unity编辑器主动执行cmd帮助类。 + /// + public static class ShellHelper + { + public static void Run(string cmd, string workDirectory, List environmentVars = null) + { + System.Diagnostics.Process process = new(); + try + { +#if UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX + string app = "bash"; + string splitChar = ":"; + string arguments = "-c"; +#elif UNITY_EDITOR_WIN + string app = "cmd.exe"; + string splitChar = ";"; + string arguments = "/c"; +#endif + ProcessStartInfo start = new ProcessStartInfo(app); + + if (environmentVars != null) + { + foreach (string var in environmentVars) + { + start.EnvironmentVariables["PATH"] += (splitChar + var); + } + } + + process.StartInfo = start; + start.Arguments = arguments + " \"" + cmd + "\""; + start.CreateNoWindow = true; + start.ErrorDialog = true; + start.UseShellExecute = false; + start.WorkingDirectory = workDirectory; + + if (start.UseShellExecute) + { + start.RedirectStandardOutput = false; + start.RedirectStandardError = false; + start.RedirectStandardInput = false; + } + else + { + start.RedirectStandardOutput = true; + start.RedirectStandardError = true; + start.RedirectStandardInput = true; + start.StandardOutputEncoding = System.Text.Encoding.UTF8; + start.StandardErrorEncoding = System.Text.Encoding.UTF8; + } + + bool endOutput = false; + bool endError = false; + + process.OutputDataReceived += (sender, args) => + { + if (args.Data != null) + { + UnityEngine.Debug.Log(args.Data); + } + else + { + endOutput = true; + } + }; + + process.ErrorDataReceived += (sender, args) => + { + if (args.Data != null) + { + UnityEngine.Debug.LogError(args.Data); + } + else + { + endError = true; + } + }; + + process.Start(); + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + while (!endOutput || !endError) + { + } + + process.CancelOutputRead(); + process.CancelErrorRead(); + } + catch (Exception e) + { + UnityEngine.Debug.LogException(e); + } + finally + { + process.Close(); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Utility/ShellHelper.cs.meta b/EintooAR/Assets/TEngine/Editor/Utility/ShellHelper.cs.meta new file mode 100644 index 00000000..6b9f3c7e --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/ShellHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a1d4e955485549fcbcc754c333953255 +timeCreated: 1695193247 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Utility/Type.cs b/EintooAR/Assets/TEngine/Editor/Utility/Type.cs new file mode 100644 index 00000000..2486e282 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/Type.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Reflection; + +namespace TEngine.Editor +{ + /// + /// 类型相关的实用函数。 + /// + internal static class Type + { + private static readonly string[] RuntimeAssemblyNames = + { + "TEngine.Runtime", + "Assembly-CSharp", + "GameMain.Runtime", + "GameMain", + }; + + private static readonly string[] RuntimeOrEditorAssemblyNames = + { + "TEngine.Runtime", + "Assembly-CSharp", + "TEngine.Editor", + "Assembly-CSharp-Editor", + "GameMain", + "GameMain.Editor" + }; + + /// + /// 在运行时程序集中获取指定基类的所有子类的名称。 + /// + /// 基类类型。 + /// 指定基类的所有子类的名称。 + internal static string[] GetRuntimeTypeNames(System.Type typeBase) + { + return GetTypeNames(typeBase, RuntimeAssemblyNames); + } + + /// + /// 在运行时或编辑器程序集中获取指定基类的所有子类的名称。 + /// + /// 基类类型。 + /// 指定基类的所有子类的名称。 + internal static string[] GetRuntimeOrEditorTypeNames(System.Type typeBase) + { + return GetTypeNames(typeBase, RuntimeOrEditorAssemblyNames); + } + + private static string[] GetTypeNames(System.Type typeBase, string[] assemblyNames) + { + List typeNames = new List(); + foreach (string assemblyName in assemblyNames) + { + Assembly assembly = null; + try + { + assembly = Assembly.Load(assemblyName); + } + catch + { + continue; + } + + if (assembly == null) + { + continue; + } + + System.Type[] types = assembly.GetTypes(); + foreach (System.Type type in types) + { + if (type.IsClass && !type.IsAbstract && typeBase.IsAssignableFrom(type)) + { + typeNames.Add(type.FullName); + } + } + } + + typeNames.Sort(); + return typeNames.ToArray(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Editor/Utility/Type.cs.meta b/EintooAR/Assets/TEngine/Editor/Utility/Type.cs.meta new file mode 100644 index 00000000..86ee46a8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Editor/Utility/Type.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a791d3891e3eeb40b35602635e8093b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/ResRaw.meta b/EintooAR/Assets/TEngine/ResRaw.meta new file mode 100644 index 00000000..2c480dd1 --- /dev/null +++ b/EintooAR/Assets/TEngine/ResRaw.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bb886178eb4db0a438530b2af5356a15 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/ResRaw/AutoBindGlobalSetting.asset b/EintooAR/Assets/TEngine/ResRaw/AutoBindGlobalSetting.asset new file mode 100644 index 00000000..3ca041f0 --- /dev/null +++ b/EintooAR/Assets/TEngine/ResRaw/AutoBindGlobalSetting.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3dac541dae7b4c4d8b5497057739cfb0, type: 3} + m_Name: AutoBindGlobalSetting + m_EditorClassIdentifier: + m_CodePath: Assets/GameScripts + m_Namespace: GameLogic + m_WidgetName: m_item diff --git a/EintooAR/Assets/TEngine/ResRaw/AutoBindGlobalSetting.asset.meta b/EintooAR/Assets/TEngine/ResRaw/AutoBindGlobalSetting.asset.meta new file mode 100644 index 00000000..8fe9d9be --- /dev/null +++ b/EintooAR/Assets/TEngine/ResRaw/AutoBindGlobalSetting.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eb33bb9d9cdf9484997cc91b0517ba4d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/ResRaw/Resources.meta b/EintooAR/Assets/TEngine/ResRaw/Resources.meta new file mode 100644 index 00000000..ee6af039 --- /dev/null +++ b/EintooAR/Assets/TEngine/ResRaw/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 73100f2fc5d7d9742847254741b10b46 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/ResRaw/Resources/TEngineGlobalSettings.asset b/EintooAR/Assets/TEngine/ResRaw/Resources/TEngineGlobalSettings.asset new file mode 100644 index 00000000..78fb7eed --- /dev/null +++ b/EintooAR/Assets/TEngine/ResRaw/Resources/TEngineGlobalSettings.asset @@ -0,0 +1,105 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 29ba4d7c4a4b4c018116005145021a90, type: 3} + m_Name: TEngineGlobalSettings + m_EditorClassIdentifier: + m_FrameworkGlobalSettings: + m_ScriptAuthor: Default + m_ScriptVersion: 0.1 + mAppStageEnum: 1 + m_DefaultFont: Arial + m_ResourcesArea: + m_ResAdminType: Default + m_ResAdminCode: 0 + m_ServerType: 1 + m_CleanCommitPathRes: 1 + m_InnerResourceSourceUrl: https://a.unity.cn/client_api/v1/buckets/74fab9f5-8f47-4e9c-a272-58a9968544cd/release_by_badge/online/content/ + m_ExtraResourceSourceUrl: https://a.unity.cn/client_api/v1/buckets/74fab9f5-8f47-4e9c-a272-58a9968544cd/release_by_badge/online/content/ + m_FormalResourceSourceUrl: https://a.unity.cn/client_api/v1/buckets/74fab9f5-8f47-4e9c-a272-58a9968544cd/release_by_badge/online/content/ + m_AtlasFolder: Assets/AssetRaw/Atlas + HostServerURL: http://127.0.0.1:8081/AssetRoot + FallbackHostServerURL: http://127.0.0.1:8081/AssetRoot + EnableUpdateData: 0 + WindowsUpdateDataUrl: http://127.0.0.1 + MacOSUpdateDataUrl: http://127.0.0.1 + IOSUpdateDataUrl: http://127.0.0.1 + AndroidUpdateDataUrl: http://127.0.0.1 + WebGLUpdateDataUrl: http://127.0.0.1 + m_CurUseServerChannel: + m_ServerChannelInfos: [] + namespace: GameLogic + scriptGenerateRule: + - uiElementRegex: m_go + componentName: GameObject + - uiElementRegex: m_item + componentName: GameObject + - uiElementRegex: m_tf + componentName: Transform + - uiElementRegex: m_rect + componentName: RectTransform + - uiElementRegex: m_text + componentName: Text + - uiElementRegex: m_richText + componentName: RichTextItem + - uiElementRegex: m_btn + componentName: Button + - uiElementRegex: m_img + componentName: Image + - uiElementRegex: m_rimg + componentName: RawImage + - uiElementRegex: m_scrollBar + componentName: Scrollbar + - uiElementRegex: m_scrollRect + componentName: ScrollRect + - uiElementRegex: m_input + componentName: InputField + - uiElementRegex: m_grid + componentName: GridLayoutGroup + - uiElementRegex: m_hlay + componentName: HorizontalLayoutGroup + - uiElementRegex: m_vlay + componentName: VerticalLayoutGroup + - uiElementRegex: m_red + componentName: RedNoteBehaviour + - uiElementRegex: m_slider + componentName: Slider + - uiElementRegex: m_group + componentName: ToggleGroup + - uiElementRegex: m_curve + componentName: AnimationCurve + - uiElementRegex: m_canvasGroup + componentName: CanvasGroup + - uiElementRegex: m_tmpinput + componentName: TMP_InputField + - uiElementRegex: m_tmpDropdown + componentName: TMP_Dropdown + - uiElementRegex: m_tmptext + componentName: TextMeshProUGUI + - uiElementRegex: m_mpimg + componentName: MPImage + m_HybridCLRCustomGlobalSettings: + HotUpdateAssemblies: + - GameBase.dll + - GameProto.dll + - GameLogic.dll + AOTMetaAssemblies: + - mscorlib.dll + - System.dll + - System.Core.dll + - UnityEngine.CoreModule.dll + - YooAsset.dll + - UniTask.dll + - TEngine.Runtime.dll + LogicMainDllName: GameLogic.dll + AssemblyTextAssetExtension: .bytes + AssemblyTextAssetPath: AssetRaw/DLL + HybridCLRGlobalSettings: Settings/HybridCLRGlobalSettings diff --git a/EintooAR/Assets/TEngine/ResRaw/Resources/TEngineGlobalSettings.asset.meta b/EintooAR/Assets/TEngine/ResRaw/Resources/TEngineGlobalSettings.asset.meta new file mode 100644 index 00000000..087172d6 --- /dev/null +++ b/EintooAR/Assets/TEngine/ResRaw/Resources/TEngineGlobalSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2210e2cede7258f4b823752f33f7ff55 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime.meta b/EintooAR/Assets/TEngine/Runtime.meta new file mode 100644 index 00000000..1beaffec --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2643d8429401bc94abfe98d7b090576c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core.meta b/EintooAR/Assets/TEngine/Runtime/Core.meta new file mode 100644 index 00000000..50a7a537 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 345151b15de4f8942b1f0d9aa9f483a1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Constant.meta b/EintooAR/Assets/TEngine/Runtime/Core/Constant.meta new file mode 100644 index 00000000..d406ab82 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Constant.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dadd7a10664840828468fffa9fa24a4e +timeCreated: 1695137851 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Constant/Constant.cs b/EintooAR/Assets/TEngine/Runtime/Core/Constant/Constant.cs new file mode 100644 index 00000000..5b7ded4f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Constant/Constant.cs @@ -0,0 +1,32 @@ +namespace TEngine +{ + /// + /// 资源相关常量。 + /// + public static partial class Constant + { + /// + /// 默认资源加载优先级。 + /// + internal const int DefaultPriority = 0; + } + + /// + /// 常用设置相关常量。 + /// + public static partial class Constant + { + public static class Setting + { + public const string Language = "Setting.Language"; + public const string SoundGroupMuted = "Setting.{0}Muted"; + public const string SoundGroupVolume = "Setting.{0}Volume"; + public const string MusicMuted = "Setting.MusicMuted"; + public const string MusicVolume = "Setting.MusicVolume"; + public const string SoundMuted = "Setting.SoundMuted"; + public const string SoundVolume = "Setting.SoundVolume"; + public const string UISoundMuted = "Setting.UISoundMuted"; + public const string UISoundVolume = "Setting.UISoundVolume"; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Constant/Constant.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Constant/Constant.cs.meta new file mode 100644 index 00000000..914f45d6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Constant/Constant.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c8f9a76deb8d4bad81a01ccbad94795d +timeCreated: 1695137859 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct.meta b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct.meta new file mode 100644 index 00000000..934c180e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8ec6e7d944f94bdcac7d00c1ec1902b4 +timeCreated: 1694797221 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkDictionary.cs b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkDictionary.cs new file mode 100644 index 00000000..cb5e8a03 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkDictionary.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 游戏框架字典类。 + /// + /// 指定字典Key的元素类型。 + /// 指定字典Value的元素类型。 + public class GameFrameworkDictionary + { + protected readonly List KeyList = new List(); + protected readonly Dictionary Dictionary = new Dictionary(); + + /// + /// 存储键的列表。 + /// + public List Keys => KeyList; + + /// + /// 存储字典实例。 + /// + public int Count => KeyList.Count; + + /// + /// 通过KEY的数组下标获取元素。 + /// + /// 下标。 + /// TValue。 + public TValue GetValueByIndex(int index) + { + return Dictionary[KeyList[index]]; + } + + /// + /// 通过KEY的数组下标设置元素。 + /// + /// 下标。 + /// TValue。 + public void SetValue(int index, TValue item) + { + Dictionary[KeyList[index]] = item; + } + + /// + /// 字典索引器。 + /// + /// TKey。 + public TValue this[TKey key] + { + get => Dictionary[key]; + set + { + if (!ContainsKey(key)) + { + Add(key, value); + } + else + { + Dictionary[key] = value; + } + } + } + + /// Removes all keys and values from the . + public void Clear() + { + KeyList.Clear(); + Dictionary.Clear(); + } + + /// Adds the specified key and value to the dictionary. + /// The key of the element to add. + /// The value of the element to add. The value can be for reference types. + public virtual void Add(TKey key, TValue item) + { + KeyList.Add(key); + Dictionary.Add(key, item); + } + + /// Gets the value associated with the specified key. + /// The key of the value to get. + /// When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. + public bool TryGetValue(TKey key, out TValue value) + { + return Dictionary.TryGetValue(key, out value); + } + + /// Determines whether the contains the specified key. + /// The key to locate in the + public bool ContainsKey(TKey key) + { + return Dictionary.ContainsKey(key); + } + + public TKey GetKey(int index) + { + return KeyList[index]; + } + + public bool Remove(TKey key) + { + return KeyList.Remove(key) && Dictionary.Remove(key); + } + } + + /// + /// 游戏框架顺序字典类。 + /// + /// 指定字典Key的元素类型。 + /// 指定字典Value的元素类型。 + public class GameFrameworkSortedDictionary : GameFrameworkDictionary + { + public override void Add(TKey key, TValue item) + { + base.Add(key, item); + KeyList.Sort(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkDictionary.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkDictionary.cs.meta new file mode 100644 index 00000000..74d41812 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkDictionary.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3df785fede30420dbfa6acb2ff48c166 +timeCreated: 1698296076 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedList.cs b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedList.cs new file mode 100644 index 00000000..75459255 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedList.cs @@ -0,0 +1,392 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace TEngine +{ + /// + /// 游戏框架链表类。 + /// + /// 指定链表的元素类型。 + public sealed class GameFrameworkLinkedList : ICollection, IEnumerable, ICollection, IEnumerable + { + private readonly LinkedList _linkedList; + private readonly Queue> _cachedNodes; + + /// + /// 初始化游戏框架链表类的新实例。 + /// + public GameFrameworkLinkedList() + { + _linkedList = new LinkedList(); + _cachedNodes = new Queue>(); + } + + /// + /// 获取链表中实际包含的结点数量。 + /// + public int Count => _linkedList.Count; + + /// + /// 获取链表结点缓存数量。 + /// + public int CachedNodeCount => _cachedNodes.Count; + + /// + /// 获取链表的第一个结点。 + /// + public LinkedListNode First => _linkedList.First; + + /// + /// 获取链表的最后一个结点。 + /// + public LinkedListNode Last => _linkedList.Last; + + /// + /// 获取一个值,该值指示 ICollection`1 是否为只读。 + /// + public bool IsReadOnly => ((ICollection)_linkedList).IsReadOnly; + + /// + /// 获取可用于同步对 ICollection 的访问的对象。 + /// + public object SyncRoot => ((ICollection)_linkedList).SyncRoot; + + /// + /// 获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。 + /// + public bool IsSynchronized => ((ICollection)_linkedList).IsSynchronized; + + /// + /// 在链表中指定的现有结点后添加包含指定值的新结点。 + /// + /// 指定的现有结点。 + /// 指定值。 + /// 包含指定值的新结点。 + public LinkedListNode AddAfter(LinkedListNode node, T value) + { + LinkedListNode newNode = AcquireNode(value); + _linkedList.AddAfter(node, newNode); + return newNode; + } + + /// + /// 在链表中指定的现有结点后添加指定的新结点。 + /// + /// 指定的现有结点。 + /// 指定的新结点。 + public void AddAfter(LinkedListNode node, LinkedListNode newNode) + { + _linkedList.AddAfter(node, newNode); + } + + /// + /// 在链表中指定的现有结点前添加包含指定值的新结点。 + /// + /// 指定的现有结点。 + /// 指定值。 + /// 包含指定值的新结点。 + public LinkedListNode AddBefore(LinkedListNode node, T value) + { + LinkedListNode newNode = AcquireNode(value); + _linkedList.AddBefore(node, newNode); + return newNode; + } + + /// + /// 在链表中指定的现有结点前添加指定的新结点。 + /// + /// 指定的现有结点。 + /// 指定的新结点。 + public void AddBefore(LinkedListNode node, LinkedListNode newNode) + { + _linkedList.AddBefore(node, newNode); + } + + /// + /// 在链表的开头处添加包含指定值的新结点。 + /// + /// 指定值。 + /// 包含指定值的新结点。 + public LinkedListNode AddFirst(T value) + { + LinkedListNode node = AcquireNode(value); + _linkedList.AddFirst(node); + return node; + } + + /// + /// 在链表的开头处添加指定的新结点。 + /// + /// 指定的新结点。 + public void AddFirst(LinkedListNode node) + { + _linkedList.AddFirst(node); + } + + /// + /// 在链表的结尾处添加包含指定值的新结点。 + /// + /// 指定值。 + /// 包含指定值的新结点。 + public LinkedListNode AddLast(T value) + { + LinkedListNode node = AcquireNode(value); + _linkedList.AddLast(node); + return node; + } + + /// + /// 在链表的结尾处添加指定的新结点。 + /// + /// 指定的新结点。 + public void AddLast(LinkedListNode node) + { + _linkedList.AddLast(node); + } + + /// + /// 从链表中移除所有结点。 + /// + public void Clear() + { + LinkedListNode current = _linkedList.First; + while (current != null) + { + ReleaseNode(current); + current = current.Next; + } + + _linkedList.Clear(); + } + + /// + /// 清除链表结点缓存。 + /// + public void ClearCachedNodes() + { + _cachedNodes.Clear(); + } + + /// + /// 确定某值是否在链表中。 + /// + /// 指定值。 + /// 某值是否在链表中。 + public bool Contains(T value) + { + return _linkedList.Contains(value); + } + + /// + /// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。 + /// + /// 一维数组,它是从链表复制的元素的目标。数组必须具有从零开始的索引。 + /// array 中从零开始的索引,从此处开始复制。 + public void CopyTo(T[] array, int index) + { + _linkedList.CopyTo(array, index); + } + + /// + /// 从特定的 ICollection 索引开始,将数组的元素复制到一个数组中。 + /// + /// 一维数组,它是从 ICollection 复制的元素的目标。数组必须具有从零开始的索引。 + /// array 中从零开始的索引,从此处开始复制。 + public void CopyTo(Array array, int index) + { + ((ICollection)_linkedList).CopyTo(array, index); + } + + /// + /// 查找包含指定值的第一个结点。 + /// + /// 要查找的指定值。 + /// 包含指定值的第一个结点。 + public LinkedListNode Find(T value) + { + return _linkedList.Find(value); + } + + /// + /// 查找包含指定值的最后一个结点。 + /// + /// 要查找的指定值。 + /// 包含指定值的最后一个结点。 + public LinkedListNode FindLast(T value) + { + return _linkedList.FindLast(value); + } + + /// + /// 从链表中移除指定值的第一个匹配项。 + /// + /// 指定值。 + /// 是否移除成功。 + public bool Remove(T value) + { + LinkedListNode node = _linkedList.Find(value); + if (node != null) + { + _linkedList.Remove(node); + ReleaseNode(node); + return true; + } + + return false; + } + + /// + /// 从链表中移除指定的结点。 + /// + /// 指定的结点。 + public void Remove(LinkedListNode node) + { + _linkedList.Remove(node); + ReleaseNode(node); + } + + /// + /// 移除位于链表开头处的结点。 + /// + public void RemoveFirst() + { + LinkedListNode first = _linkedList.First; + if (first == null) + { + throw new GameFrameworkException("First is invalid."); + } + + _linkedList.RemoveFirst(); + ReleaseNode(first); + } + + /// + /// 移除位于链表结尾处的结点。 + /// + public void RemoveLast() + { + LinkedListNode last = _linkedList.Last; + if (last == null) + { + throw new GameFrameworkException("Last is invalid."); + } + + _linkedList.RemoveLast(); + ReleaseNode(last); + } + + /// + /// 返回循环访问集合的枚举数。 + /// + /// 循环访问集合的枚举数。 + public Enumerator GetEnumerator() + { + return new Enumerator(_linkedList); + } + + private LinkedListNode AcquireNode(T value) + { + LinkedListNode node = null; + if (_cachedNodes.Count > 0) + { + node = _cachedNodes.Dequeue(); + node.Value = value; + } + else + { + node = new LinkedListNode(value); + } + + return node; + } + + private void ReleaseNode(LinkedListNode node) + { + node.Value = default(T); + _cachedNodes.Enqueue(node); + } + + /// + /// 将值添加到 ICollection`1 的结尾处。 + /// + /// 要添加的值。 + void ICollection.Add(T value) + { + AddLast(value); + } + + /// + /// 返回循环访问集合的枚举数。 + /// + /// 循环访问集合的枚举数。 + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// 返回循环访问集合的枚举数。 + /// + /// 循环访问集合的枚举数。 + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// 循环访问集合的枚举数。 + /// + [StructLayout(LayoutKind.Auto)] + public struct Enumerator : IEnumerator, IEnumerator + { + private LinkedList.Enumerator m_Enumerator; + + internal Enumerator(LinkedList linkedList) + { + if (linkedList == null) + { + throw new GameFrameworkException("Linked list is invalid."); + } + + m_Enumerator = linkedList.GetEnumerator(); + } + + /// + /// 获取当前结点。 + /// + public T Current => m_Enumerator.Current; + + /// + /// 获取当前的枚举数。 + /// + object IEnumerator.Current => m_Enumerator.Current; + + /// + /// 清理枚举数。 + /// + public void Dispose() + { + m_Enumerator.Dispose(); + } + + /// + /// 获取下一个结点。 + /// + /// 返回下一个结点。 + public bool MoveNext() + { + return m_Enumerator.MoveNext(); + } + + /// + /// 重置枚举数。 + /// + void IEnumerator.Reset() + { + ((IEnumerator)m_Enumerator).Reset(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedList.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedList.cs.meta new file mode 100644 index 00000000..83842970 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedList.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 91989cb9547740bfaa7b7ed8dbd4646a +timeCreated: 1680336403 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedListRange.cs b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedListRange.cs new file mode 100644 index 00000000..53295d96 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedListRange.cs @@ -0,0 +1,180 @@ +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace TEngine +{ + /// + /// 游戏框架链表范围。 + /// + /// 指定链表范围的元素类型。 + [StructLayout(LayoutKind.Auto)] + public readonly struct GameFrameworkLinkedListRange : IEnumerable, IEnumerable + { + private readonly LinkedListNode _first; + private readonly LinkedListNode _terminal; + + /// + /// 初始化游戏框架链表范围的新实例。 + /// + /// 链表范围的开始结点。 + /// 链表范围的终结标记结点。 + public GameFrameworkLinkedListRange(LinkedListNode first, LinkedListNode terminal) + { + if (first == null || terminal == null || first == terminal) + { + throw new GameFrameworkException("Range is invalid."); + } + + _first = first; + _terminal = terminal; + } + + /// + /// 获取链表范围是否有效。 + /// + public bool IsValid => _first != null && _terminal != null && _first != _terminal; + + /// + /// 获取链表范围的开始结点。 + /// + public LinkedListNode First => _first; + + /// + /// 获取链表范围的终结标记结点。 + /// + public LinkedListNode Terminal => _terminal; + + /// + /// 获取链表范围的结点数量。 + /// + public int Count + { + get + { + if (!IsValid) + { + return 0; + } + + int count = 0; + for (LinkedListNode current = _first; current != null && current != _terminal; current = current.Next) + { + count++; + } + + return count; + } + } + + /// + /// 检查是否包含指定值。 + /// + /// 要检查的值。 + /// 是否包含指定值。 + public bool Contains(T value) + { + for (LinkedListNode current = _first; current != null && current != _terminal; current = current.Next) + { + if (current.Value.Equals(value)) + { + return true; + } + } + + return false; + } + + /// + /// 返回循环访问集合的枚举数。 + /// + /// 循环访问集合的枚举数。 + public Enumerator GetEnumerator() + { + return new Enumerator(this); + } + + /// + /// 返回循环访问集合的枚举数。 + /// + /// 循环访问集合的枚举数。 + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// 返回循环访问集合的枚举数。 + /// + /// 循环访问集合的枚举数。 + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// 循环访问集合的枚举数。 + /// + [StructLayout(LayoutKind.Auto)] + public struct Enumerator : IEnumerator, IEnumerator + { + private readonly GameFrameworkLinkedListRange m_GameFrameworkLinkedListRange; + private LinkedListNode m_Current; + private T m_CurrentValue; + + internal Enumerator(GameFrameworkLinkedListRange range) + { + if (!range.IsValid) + { + throw new GameFrameworkException("Range is invalid."); + } + + m_GameFrameworkLinkedListRange = range; + m_Current = m_GameFrameworkLinkedListRange._first; + m_CurrentValue = default(T); + } + + /// + /// 获取当前结点。 + /// + public T Current => m_CurrentValue; + + /// + /// 获取当前的枚举数。 + /// + object IEnumerator.Current => m_CurrentValue; + + /// + /// 清理枚举数。 + /// + public void Dispose() + { + } + + /// + /// 获取下一个结点。 + /// + /// 返回下一个结点。 + public bool MoveNext() + { + if (m_Current == null || m_Current == m_GameFrameworkLinkedListRange._terminal) + { + return false; + } + + m_CurrentValue = m_Current.Value; + m_Current = m_Current.Next; + return true; + } + + /// + /// 重置枚举数。 + /// + void IEnumerator.Reset() + { + m_Current = m_GameFrameworkLinkedListRange._first; + m_CurrentValue = default(T); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedListRange.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedListRange.cs.meta new file mode 100644 index 00000000..f033cc9a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkLinkedListRange.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3c15a1f4b89d404b8ff77419386ff26a +timeCreated: 1680337062 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkMultiDictionary.cs b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkMultiDictionary.cs new file mode 100644 index 00000000..a7c5fba1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkMultiDictionary.cs @@ -0,0 +1,258 @@ +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace TEngine +{ + /// + /// 游戏框架多值字典类。 + /// + /// 指定多值字典的主键类型。 + /// 指定多值字典的值类型。 + public sealed class GameFrameworkMultiDictionary : IEnumerable>>, IEnumerable + { + private readonly GameFrameworkLinkedList _linkedList; + private readonly Dictionary> _dictionary; + + /// + /// 初始化游戏框架多值字典类的新实例。 + /// + public GameFrameworkMultiDictionary() + { + _linkedList = new GameFrameworkLinkedList(); + _dictionary = new Dictionary>(); + } + + /// + /// 获取多值字典中实际包含的主键数量。 + /// + public int Count => _dictionary.Count; + + /// + /// 获取多值字典中指定主键的范围。 + /// + /// 指定的主键。 + /// 指定主键的范围。 + public GameFrameworkLinkedListRange this[TKey key] + { + get + { + GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); + _dictionary.TryGetValue(key, out range); + return range; + } + } + + /// + /// 清理多值字典。 + /// + public void Clear() + { + _dictionary.Clear(); + _linkedList.Clear(); + } + + /// + /// 检查多值字典中是否包含指定主键。 + /// + /// 要检查的主键。 + /// 多值字典中是否包含指定主键。 + public bool Contains(TKey key) + { + return _dictionary.ContainsKey(key); + } + + /// + /// 检查多值字典中是否包含指定值。 + /// + /// 要检查的主键。 + /// 要检查的值。 + /// 多值字典中是否包含指定值。 + public bool Contains(TKey key, TValue value) + { + GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); + if (_dictionary.TryGetValue(key, out range)) + { + return range.Contains(value); + } + + return false; + } + + /// + /// 尝试获取多值字典中指定主键的范围。 + /// + /// 指定的主键。 + /// 指定主键的范围。 + /// 是否获取成功。 + public bool TryGetValue(TKey key, out GameFrameworkLinkedListRange range) + { + return _dictionary.TryGetValue(key, out range); + } + + /// + /// 向指定的主键增加指定的值。 + /// + /// 指定的主键。 + /// 指定的值。 + public void Add(TKey key, TValue value) + { + GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); + if (_dictionary.TryGetValue(key, out range)) + { + _linkedList.AddBefore(range.Terminal, value); + } + else + { + LinkedListNode first = _linkedList.AddLast(value); + LinkedListNode terminal = _linkedList.AddLast(default(TValue)); + _dictionary.Add(key, new GameFrameworkLinkedListRange(first, terminal)); + } + } + + /// + /// 从指定的主键中移除指定的值。 + /// + /// 指定的主键。 + /// 指定的值。 + /// 是否移除成功。 + public bool Remove(TKey key, TValue value) + { + GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); + if (_dictionary.TryGetValue(key, out range)) + { + for (LinkedListNode current = range.First; current != null && current != range.Terminal; current = current.Next) + { + if (current.Value.Equals(value)) + { + if (current == range.First) + { + LinkedListNode next = current.Next; + if (next == range.Terminal) + { + _linkedList.Remove(next); + _dictionary.Remove(key); + } + else + { + _dictionary[key] = new GameFrameworkLinkedListRange(next, range.Terminal); + } + } + + _linkedList.Remove(current); + return true; + } + } + } + + return false; + } + + /// + /// 从指定的主键中移除所有的值。 + /// + /// 指定的主键。 + /// 是否移除成功。 + public bool RemoveAll(TKey key) + { + GameFrameworkLinkedListRange range = default(GameFrameworkLinkedListRange); + if (_dictionary.TryGetValue(key, out range)) + { + _dictionary.Remove(key); + + LinkedListNode current = range.First; + while (current != null) + { + LinkedListNode next = current != range.Terminal ? current.Next : null; + _linkedList.Remove(current); + current = next; + } + + return true; + } + + return false; + } + + /// + /// 返回循环访问集合的枚举数。 + /// + /// 循环访问集合的枚举数。 + public Enumerator GetEnumerator() + { + return new Enumerator(_dictionary); + } + + /// + /// 返回循环访问集合的枚举数。 + /// + /// 循环访问集合的枚举数。 + IEnumerator>> IEnumerable>>.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// 返回循环访问集合的枚举数。 + /// + /// 循环访问集合的枚举数。 + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// 循环访问集合的枚举数。 + /// + [StructLayout(LayoutKind.Auto)] + public struct Enumerator : IEnumerator>>, IEnumerator + { + private Dictionary>.Enumerator m_Enumerator; + + internal Enumerator(Dictionary> dictionary) + { + if (dictionary == null) + { + throw new GameFrameworkException("Dictionary is invalid."); + } + + m_Enumerator = dictionary.GetEnumerator(); + } + + /// + /// 获取当前结点。 + /// + public KeyValuePair> Current => m_Enumerator.Current; + + /// + /// 获取当前的枚举数。 + /// + object IEnumerator.Current => m_Enumerator.Current; + + /// + /// 清理枚举数。 + /// + public void Dispose() + { + m_Enumerator.Dispose(); + } + + /// + /// 获取下一个结点。 + /// + /// 返回下一个结点。 + public bool MoveNext() + { + return m_Enumerator.MoveNext(); + } + + /// + /// 重置枚举数。 + /// + void IEnumerator.Reset() + { + ((IEnumerator>>)m_Enumerator).Reset(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkMultiDictionary.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkMultiDictionary.cs.meta new file mode 100644 index 00000000..340b2e56 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkMultiDictionary.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4f09e27ffe754d8894a4ced69a0f90b6 +timeCreated: 1680337042 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkSerializer.cs b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkSerializer.cs new file mode 100644 index 00000000..5b2fdb19 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkSerializer.cs @@ -0,0 +1,201 @@ +using System.Collections.Generic; +using System.IO; + +namespace TEngine +{ + /// + /// 游戏框架序列化器基类。 + /// + /// 要序列化的数据类型。 + public abstract class GameFrameworkSerializer + { + private readonly Dictionary _serializeCallbacks; + private readonly Dictionary _deserializeCallbacks; + private readonly Dictionary _tryGetValueCallbacks; + private byte _latestSerializeCallbackVersion; + + /// + /// 初始化游戏框架序列化器基类的新实例。 + /// + public GameFrameworkSerializer() + { + _serializeCallbacks = new Dictionary(); + _deserializeCallbacks = new Dictionary(); + _tryGetValueCallbacks = new Dictionary(); + _latestSerializeCallbackVersion = 0; + } + + /// + /// 序列化回调函数。 + /// + /// 目标流。 + /// 要序列化的数据。 + /// 是否序列化数据成功。 + public delegate bool SerializeCallback(Stream stream, T data); + + /// + /// 反序列化回调函数。 + /// + /// 指定流。 + /// 反序列化的数据。 + public delegate T DeserializeCallback(Stream stream); + + /// + /// 尝试从指定流获取指定键的值回调函数。 + /// + /// 指定流。 + /// 指定键。 + /// 指定键的值。 + /// 是否从指定流获取指定键的值成功。 + public delegate bool TryGetValueCallback(Stream stream, string key, out object value); + + /// + /// 注册序列化回调函数。 + /// + /// 序列化回调函数的版本。 + /// 序列化回调函数。 + public void RegisterSerializeCallback(byte version, SerializeCallback callback) + { + if (callback == null) + { + throw new GameFrameworkException("Serialize callback is invalid."); + } + + _serializeCallbacks[version] = callback; + if (version > _latestSerializeCallbackVersion) + { + _latestSerializeCallbackVersion = version; + } + } + + /// + /// 注册反序列化回调函数。 + /// + /// 反序列化回调函数的版本。 + /// 反序列化回调函数。 + public void RegisterDeserializeCallback(byte version, DeserializeCallback callback) + { + if (callback == null) + { + throw new GameFrameworkException("Deserialize callback is invalid."); + } + + _deserializeCallbacks[version] = callback; + } + + /// + /// 注册尝试从指定流获取指定键的值回调函数。 + /// + /// 尝试从指定流获取指定键的值回调函数的版本。 + /// 尝试从指定流获取指定键的值回调函数。 + public void RegisterTryGetValueCallback(byte version, TryGetValueCallback callback) + { + if (callback == null) + { + throw new GameFrameworkException("Try get value callback is invalid."); + } + + _tryGetValueCallbacks[version] = callback; + } + + /// + /// 序列化数据到目标流中。 + /// + /// 目标流。 + /// 要序列化的数据。 + /// 是否序列化数据成功。 + public bool Serialize(Stream stream, T data) + { + if (_serializeCallbacks.Count <= 0) + { + throw new GameFrameworkException("No serialize callback registered."); + } + + return Serialize(stream, data, _latestSerializeCallbackVersion); + } + + /// + /// 序列化数据到目标流中。 + /// + /// 目标流。 + /// 要序列化的数据。 + /// 序列化回调函数的版本。 + /// 是否序列化数据成功。 + public bool Serialize(Stream stream, T data, byte version) + { + byte[] header = GetHeader(); + stream.WriteByte(header[0]); + stream.WriteByte(header[1]); + stream.WriteByte(header[2]); + stream.WriteByte(version); + SerializeCallback callback = null; + if (!_serializeCallbacks.TryGetValue(version, out callback)) + { + throw new GameFrameworkException(Utility.Text.Format("Serialize callback '{0}' is not exist.", version)); + } + + return callback(stream, data); + } + + /// + /// 从指定流反序列化数据。 + /// + /// 指定流。 + /// 反序列化的数据。 + public T Deserialize(Stream stream) + { + byte[] header = GetHeader(); + byte header0 = (byte)stream.ReadByte(); + byte header1 = (byte)stream.ReadByte(); + byte header2 = (byte)stream.ReadByte(); + if (header0 != header[0] || header1 != header[1] || header2 != header[2]) + { + throw new GameFrameworkException(Utility.Text.Format("Header is invalid, need '{0}{1}{2}', current '{3}{4}{5}'.", (char)header[0], (char)header[1], (char)header[2], (char)header0, (char)header1, (char)header2)); + } + + byte version = (byte)stream.ReadByte(); + DeserializeCallback callback = null; + if (!_deserializeCallbacks.TryGetValue(version, out callback)) + { + throw new GameFrameworkException(Utility.Text.Format("Deserialize callback '{0}' is not exist.", version)); + } + + return callback(stream); + } + + /// + /// 尝试从指定流获取指定键的值。 + /// + /// 指定流。 + /// 指定键。 + /// 指定键的值。 + /// 是否从指定流获取指定键的值成功。 + public bool TryGetValue(Stream stream, string key, out object value) + { + value = null; + byte[] header = GetHeader(); + byte header0 = (byte)stream.ReadByte(); + byte header1 = (byte)stream.ReadByte(); + byte header2 = (byte)stream.ReadByte(); + if (header0 != header[0] || header1 != header[1] || header2 != header[2]) + { + return false; + } + + byte version = (byte)stream.ReadByte(); + TryGetValueCallback callback = null; + if (!_tryGetValueCallbacks.TryGetValue(version, out callback)) + { + return false; + } + + return callback(stream, key, out value); + } + + /// + /// 获取数据头标识。 + /// + /// 数据头标识。 + protected abstract byte[] GetHeader(); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkSerializer.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkSerializer.cs.meta new file mode 100644 index 00000000..6290c71b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/GameFrameworkSerializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1d21d1882be542d0b73cb85f7cfa226c +timeCreated: 1680494414 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/SerializableDictionary.cs b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/SerializableDictionary.cs new file mode 100644 index 00000000..8d998057 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/SerializableDictionary.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using UnityEngine; + +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) {} + } +} + +[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 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(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/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/SerializableDictionary.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/SerializableDictionary.cs.meta new file mode 100644 index 00000000..93209a3d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/SerializableDictionary.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e7f040e158e24f699e3c71d1b522dc55 +timeCreated: 1683820865 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/TypeNamePair.cs b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/TypeNamePair.cs new file mode 100644 index 00000000..d5129f29 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/TypeNamePair.cs @@ -0,0 +1,116 @@ +using System; +using System.Runtime.InteropServices; + +namespace TEngine +{ + /// + /// 类型和名称的组合值。 + /// + [StructLayout(LayoutKind.Auto)] + internal readonly struct TypeNamePair : IEquatable + { + private readonly Type _type; + private readonly string _name; + + /// + /// 初始化类型和名称的组合值的新实例。 + /// + /// 类型。 + public TypeNamePair(Type type) + : this(type, string.Empty) + { + } + + /// + /// 初始化类型和名称的组合值的新实例。 + /// + /// 类型。 + /// 名称。 + public TypeNamePair(Type type, string name) + { + if (type == null) + { + throw new GameFrameworkException("Type is invalid."); + } + + _type = type; + _name = name ?? string.Empty; + } + + /// + /// 获取类型。 + /// + public Type Type => _type; + + /// + /// 获取名称。 + /// + public string Name => _name; + + /// + /// 获取类型和名称的组合值字符串。 + /// + /// 类型和名称的组合值字符串。 + public override string ToString() + { + if (_type == null) + { + throw new GameFrameworkException("Type is invalid."); + } + + string typeName = _type.FullName; + return string.IsNullOrEmpty(_name) ? typeName : Utility.Text.Format("{0}.{1}", typeName, _name); + } + + /// + /// 获取对象的哈希值。 + /// + /// 对象的哈希值。 + public override int GetHashCode() + { + return _type.GetHashCode() ^ _name.GetHashCode(); + } + + /// + /// 比较对象是否与自身相等。 + /// + /// 要比较的对象。 + /// 被比较的对象是否与自身相等。 + public override bool Equals(object obj) + { + return obj is TypeNamePair && Equals((TypeNamePair)obj); + } + + /// + /// 比较对象是否与自身相等。 + /// + /// 要比较的对象。 + /// 被比较的对象是否与自身相等。 + public bool Equals(TypeNamePair value) + { + return _type == value._type && _name == value._name; + } + + /// + /// 判断两个对象是否相等。 + /// + /// 值 a。 + /// 值 b。 + /// 两个对象是否相等。 + public static bool operator ==(TypeNamePair a, TypeNamePair b) + { + return a.Equals(b); + } + + /// + /// 判断两个对象是否不相等。 + /// + /// 值 a。 + /// 值 b。 + /// 两个对象是否不相等。 + public static bool operator !=(TypeNamePair a, TypeNamePair b) + { + return !(a == b); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/TypeNamePair.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/TypeNamePair.cs.meta new file mode 100644 index 00000000..b0031d60 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/DataStruct/TypeNamePair.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f6fa0da056e31b4bb6d9a31b5da6af8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Exception.meta b/EintooAR/Assets/TEngine/Runtime/Core/Exception.meta new file mode 100644 index 00000000..53940131 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Exception.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3a23de77b0993b64e9c44e16646e1fa5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Exception/GameFrameworkException.cs b/EintooAR/Assets/TEngine/Runtime/Core/Exception/GameFrameworkException.cs new file mode 100644 index 00000000..8ed5b446 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Exception/GameFrameworkException.cs @@ -0,0 +1,49 @@ +using System; +using System.Runtime.Serialization; + +namespace TEngine +{ + /// + /// 游戏框架异常类。 + /// + [Serializable] + public class GameFrameworkException : Exception + { + /// + /// 初始化游戏框架异常类的新实例。 + /// + public GameFrameworkException() + : base() + { + } + + /// + /// 使用指定错误消息初始化游戏框架异常类的新实例。 + /// + /// 描述错误的消息。 + public GameFrameworkException(string message) + : base(message) + { + } + + /// + /// 使用指定错误消息和对作为此异常原因的内部异常的引用来初始化游戏框架异常类的新实例。 + /// + /// 解释异常原因的错误消息。 + /// 导致当前异常的异常。如果 innerException 参数不为空引用,则在处理内部异常的 catch 块中引发当前异常。 + public GameFrameworkException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// 用序列化数据初始化游戏框架异常类的新实例。 + /// + /// 存有有关所引发异常的序列化的对象数据。 + /// 包含有关源或目标的上下文信息。 + protected GameFrameworkException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Exception/GameFrameworkException.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Exception/GameFrameworkException.cs.meta new file mode 100644 index 00000000..604d1d41 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Exception/GameFrameworkException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a67d24dea0e24d14899d926af7e6a9f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent.meta new file mode 100644 index 00000000..34c11b21 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 72137068013c4be19577a69e100cba88 +timeCreated: 1694792042 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/ActorEventDispatcher.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/ActorEventDispatcher.cs new file mode 100644 index 00000000..08d4bab7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/ActorEventDispatcher.cs @@ -0,0 +1,640 @@ +using System; +using System.Collections.Generic; + +#region Class Documentation +/************************************************************************************************************ +Class Name: ActorEventDispatcher.cs 局部单位事件分发器。 +Type: Actor, Event +Example: + private ActorEventDispatcher _event; + + /// + /// 局部事件管理器。 + /// 只分发和监听这个Event内部的事件 + /// + public ActorEventDispatcher Event => _event ??= MemoryPool.Acquire(); + + // owner局部发送事件。 + owner.Event.Send(eventId,xxx); + + // owner监听自身事件并绑定持有对象为owner。 比如是组件的情况下。移除时调用RemoveAllListenerByOwner(owner)会根据持有对象(组件)移除。 + owner.Event.AddEventListener(eventId,xxx,owner); +************************************************************************************************************/ +#endregion + +namespace TEngine +{ + /// + /// 局部单位事件分发器。 + /// + public class ActorEventDispatcher : IMemory + { + /// + /// 所有事件。 + /// + private readonly Dictionary> _allEventListenerMap; + + /// + /// 用于标记一个事件是不是正在处理。 + /// + private readonly List _processEventList; + + /// + /// 用于标记一个事件是不是被移除。 + /// + private readonly List _delayDeleteEventList; + + public ActorEventDispatcher() + { + _processEventList = new List(); + _delayDeleteEventList = new List(); + _allEventListenerMap = new Dictionary>(); + } + + /// + /// 移除所有事件监听。 + /// + public void DestroyAllEventListener() + { + var itr = _allEventListenerMap.GetEnumerator(); + while (itr.MoveNext()) + { + var kv = itr.Current; + List list = kv.Value; + foreach (var eventRegInfo in list) + { + EventRegInfo.Release(eventRegInfo); + } + kv.Value.Clear(); + } + + _processEventList.Clear(); + _delayDeleteEventList.Clear(); + itr.Dispose(); + } + + /// + /// 延迟移除事件。 + /// + /// + private void AddDelayDelete(int eventId) + { + if (!_delayDeleteEventList.Contains(eventId)) + { + _delayDeleteEventList.Add(eventId); + Log.Info("delay delete eventId[{0}]", eventId); + } + } + + /// + /// 如果找到eventId对应的监听,删除所有标记为delete的监听。 + /// + /// 事件Id。 + private void CheckDelayDelete(int eventId) + { + if (_delayDeleteEventList.Contains(eventId)) + { + if (_allEventListenerMap.TryGetValue(eventId, out var listListener)) + { + for (int i = listListener.Count - 1; i >= 0 ; i--) + { + if (listListener[i].IsDeleted) + { + Log.Info("remove delay delete eventId[{0}]", eventId); + EventRegInfo.Release(listListener[i]); + listListener.RemoveAt(i); + } + } + } + + _delayDeleteEventList.Remove(eventId); + } + } + + /// + /// 发送事件。 + /// + /// 事件Id。 + public void SendEvent(int eventId) + { + if (_allEventListenerMap.TryGetValue(eventId, out var listListener)) + { + _processEventList.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEventList.Count; +#endif + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.IsDeleted) + { + continue; + } + + if (listListener[i].Callback is Action callBack) + { + callBack(); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEventList.Count); + Log.Assert(eventId == _processEventList[^1]); +#endif + _processEventList.RemoveAt(_processEventList.Count - 1); + + CheckDelayDelete(eventId); + } + } + + /// + /// 发送事件。 + /// + /// 事件Id。 + /// 事件参数。 + /// 事件参数类型1。 + public void SendEvent(int eventId, TArg1 arg1) + { + if (_allEventListenerMap.TryGetValue(eventId, out var listListener)) + { + _processEventList.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEventList.Count; +#endif + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.IsDeleted) + { + continue; + } + + if (listListener[i].Callback is Action callBack) + { + callBack(arg1); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEventList.Count); + Log.Assert(eventId == _processEventList[^1]); +#endif + + _processEventList.RemoveAt(_processEventList.Count - 1); + + CheckDelayDelete(eventId); + } + } + + /// + /// 发送事件。 + /// + /// 事件Id。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数类型1。 + /// 事件参数类型2。 + public void SendEvent(int eventId, TArg1 arg1, TArg2 arg2) + { + if (_allEventListenerMap.TryGetValue(eventId, out var listListener)) + { + _processEventList.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEventList.Count; +#endif + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.IsDeleted) + { + continue; + } + + if (listListener[i].Callback is Action callBack) + { + callBack(arg1, arg2); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEventList.Count); + Log.Assert(eventId == _processEventList[^1]); +#endif + _processEventList.RemoveAt(_processEventList.Count - 1); + + CheckDelayDelete(eventId); + } + } + + /// + /// 发送事件。 + /// + /// 事件Id。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数类型1。 + /// 事件参数类型2。 + /// 事件参数类型3。 + public void SendEvent(int eventId, TArg1 arg1, TArg2 arg2, TArg3 arg3) + { + if (_allEventListenerMap.TryGetValue(eventId, out var listListener)) + { + _processEventList.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEventList.Count; +#endif + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.IsDeleted) + { + continue; + } + + if (node.Callback is Action callBack) + { + callBack(arg1, arg2, arg3); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEventList.Count); + Log.Assert(eventId == _processEventList[^1]); +#endif + _processEventList.RemoveAt(_processEventList.Count - 1); + + CheckDelayDelete(eventId); + } + } + + /// + /// 发送事件。 + /// + /// 事件Id。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数类型1。 + /// 事件参数类型2。 + /// 事件参数类型3。 + /// 事件参数类型4。 + public void SendEvent(int eventId, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4) + { + if (_allEventListenerMap.TryGetValue(eventId, out var listListener)) + { + _processEventList.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEventList.Count; +#endif + + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.IsDeleted) + { + continue; + } + + if (listListener[i].Callback is Action callBack) + { + callBack(arg1, arg2, arg3, arg4); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEventList.Count); + Log.Assert(eventId == _processEventList[^1]); +#endif + _processEventList.RemoveAt(_processEventList.Count - 1); + + CheckDelayDelete(eventId); + } + } + + /// + /// 增加事件监听。 + /// + /// 事件Id。 + /// 事件回调。 + /// 持有者Tag。 + public void AddEventListener(int eventId, Action eventCallback, object owner) + { + AddEventListenerImp(eventId, eventCallback, owner); + } + + /// + /// 增加事件监听。 + /// + /// 事件Id。 + /// 事件回调。 + /// 持有者Tag。 + /// 事件参数类型1。 + public void AddEventListener(int eventId, Action eventCallback, object owner) + { + AddEventListenerImp(eventId, eventCallback, owner); + } + + /// + /// 增加事件监听。 + /// + /// 事件Id。 + /// 事件回调。 + /// 持有者Tag。 + /// 事件参数类型1。 + /// 事件参数类型2。 + public void AddEventListener(int eventId, Action eventCallback, object owner) + { + AddEventListenerImp(eventId, eventCallback, owner); + } + + /// + /// 增加事件监听。 + /// + /// 事件Id。 + /// 事件回调。 + /// 持有者Tag。 + /// 事件参数类型1。 + /// 事件参数类型2。 + /// 事件参数类型3。 + public void AddEventListener(int eventId, Action eventCallback, object owner) + { + AddEventListenerImp(eventId, eventCallback, owner); + } + + /// + /// 增加事件监听。 + /// + /// 事件Id。 + /// 事件回调。 + /// 持有者Tag。 + /// 事件参数类型1。 + /// 事件参数类型2。 + /// 事件参数类型3。 + /// 事件参数类型4。 + public void AddEventListener(int eventId, Action eventCallback, object owner) + { + AddEventListenerImp(eventId, eventCallback, owner); + } + + /// + /// 增加事件监听具体实现。 + /// + /// 事件Id。 + /// 事件回调。 + /// 持有者Tag。 + private void AddEventListenerImp(int eventId, Delegate listener, object owner) + { + if (!_allEventListenerMap.TryGetValue(eventId, out var listListener)) + { + listListener = new List(); + _allEventListenerMap.Add(eventId, listListener); + } + + var existNode = listListener.Find((node) => node.Callback == listener); + if (existNode != null) + { + if (existNode.IsDeleted) + { + existNode.IsDeleted = false; + Log.Warning("AddEvent hashId deleted, repeat add: {0}", eventId); + return; + } + + Log.Fatal("AddEvent hashId repeated: {0}", eventId); + return; + } + + listListener.Add(EventRegInfo.Alloc(listener, owner)); + } + + /// + /// 通过持有者Tag移除监听。 + /// + /// 持有者Tag。 + public void RemoveAllListenerByOwner(object owner) + { + var itr = _allEventListenerMap.GetEnumerator(); + while (itr.MoveNext()) + { + var kv = itr.Current; + var list = kv.Value; + + int eventId = kv.Key; + bool isProcessing = _processEventList.Contains(eventId); + bool delayDeleted = false; + + for (int i = list.Count - 1; i >= 0 ; i--) + { + var regInfo = list[i]; + if (regInfo.Owner == owner) + { + if (isProcessing) + { + regInfo.IsDeleted = true; + delayDeleted = true; + } + else + { + EventRegInfo.Release(list[i]); + list.RemoveAt(i); + } + } + } + + if (delayDeleted) + { + AddDelayDelete(eventId); + } + } + + itr.Dispose(); + } + + /// + /// 移除事件监听。 + /// + /// 事件Id。 + /// 消息回调。 + public void RemoveEventListener(int eventId, Action eventCallback) + { + RemoveEventListenerImp(eventId, eventCallback); + } + + /// + /// 移除事件监听。 + /// + /// 事件Id。 + /// 消息回调。 + /// 参数类型1。 + public void RemoveEventListener(int eventId, Action eventCallback) + { + RemoveEventListenerImp(eventId, eventCallback); + } + + /// + /// 移除事件监听。 + /// + /// 事件Id。 + /// 消息回调。 + /// 参数类型1。 + /// 参数类型2。 + public void RemoveEventListener(int eventId, Action eventCallback) + { + RemoveEventListenerImp(eventId, eventCallback); + } + + /// + /// 移除事件监听。 + /// + /// 事件Id。 + /// 消息回调。 + /// 参数类型1。 + /// 参数类型2。 + /// 参数类型3。 + public void RemoveEventListener(int eventId, Action eventCallback) + { + RemoveEventListenerImp(eventId, eventCallback); + } + + /// + /// 移除事件监听。 + /// + /// 事件Id。 + /// 消息回调。 + /// 参数类型1。 + /// 参数类型2。 + /// 参数类型3。 + /// 参数类型4。 + public void RemoveEventListener(int eventId, Action eventCallback) + { + RemoveEventListenerImp(eventId, eventCallback); + } + + /// + /// 删除监听,如果是正在处理的监听则标记为删除 + /// + /// 事件Id。 + /// 事件监听。 + protected void RemoveEventListenerImp(int eventId, Delegate listener) + { + if (_allEventListenerMap.TryGetValue(eventId, out var listListener)) + { + bool isProcessing = _processEventList.Contains(eventId); + if (!isProcessing) + { + listListener.RemoveAll(node => node.Callback == listener); + } + else + { + int listenCnt = listListener.Count; + for (int i = 0; i < listenCnt; i++) + { + var node = listListener[i]; + if (node.Callback == listener) + { + node.IsDeleted = true; + AddDelayDelete(eventId); + break; + } + } + } + } + } + + /// + /// 清除回收接口。 + /// + public void Clear() + { + DestroyAllEventListener(); + } + } + + /// + /// 事件注册信息。 + /// + public class EventRegInfo : IMemory + { + /// + /// 事件回调。 + /// + public Delegate Callback; + + /// + /// 事件持有者。 + /// + public object Owner; + + /// + /// 事件是否删除。 + /// + public bool IsDeleted; + + public EventRegInfo(Delegate callback, object owner) + { + this.Callback = callback; + Owner = owner; + IsDeleted = false; + } + + public EventRegInfo() { } + + public void Clear() + { + Callback = null; + Owner = null; + IsDeleted = false; + } + + public static EventRegInfo Alloc(Delegate callback, object owner) + { + EventRegInfo ret = MemoryPool.Acquire(); + ret.Callback = callback; + ret.Owner = owner; + ret.IsDeleted = false; + return ret; + } + + public static void Release(EventRegInfo eventRegInfo) + { + MemoryPool.Release(eventRegInfo); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/ActorEventDispatcher.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/ActorEventDispatcher.cs.meta new file mode 100644 index 00000000..13ce0f62 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/ActorEventDispatcher.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 222c2a26f3b14d42950d0e9a10b61b38 +timeCreated: 1673511406 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDelegateData.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDelegateData.cs new file mode 100644 index 00000000..564063f4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDelegateData.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 游戏事件数据类。 + /// + internal class EventDelegateData + { + private readonly int _eventType = 0; + private readonly List _listExist = new List(); + private readonly List _addList = new List(); + private readonly List _deleteList = new List(); + private bool _isExecute = false; + private bool _dirty = false; + + /// + /// 构造函数。 + /// + /// 事件类型。 + internal EventDelegateData(int eventType) + { + _eventType = eventType; + } + + /// + /// 添加注册委托。 + /// + /// 事件处理回调。 + /// 是否添加回调成功。 + internal bool AddHandler(Delegate handler) + { + + if (_listExist.Contains(handler)) + { + Log.Fatal("Repeated Add Handler"); + return false; + } + + if (_isExecute) + { + _dirty = true; + _addList.Add(handler); + } + else + { + _listExist.Add(handler); + } + + return true; + } + + /// + /// 移除反注册委托。 + /// + /// 事件处理回调。 + internal void RmvHandler(Delegate handler) + { + if (_isExecute) + { + _dirty = true; + _deleteList.Add(handler); + } + else + { + if (!_listExist.Remove(handler)) + { + Log.Fatal("Delete handle failed, not exist, EventId: {0}", RuntimeId.ToString(_eventType)); + } + } + } + + /// + /// 检测脏数据修正。 + /// + private void CheckModify() + { + _isExecute = false; + if (_dirty) + { + for (int i = 0; i < _addList.Count; i++) + { + _listExist.Add(_addList[i]); + } + + _addList.Clear(); + + for (int i = 0; i < _deleteList.Count; i++) + { + Log.Debug("RemoveEventListener: " + " " + _deleteList[i].Method.Name); + _listExist.Remove(_deleteList[i]); + } + + _deleteList.Clear(); + } + } + + /// + /// 回调调用。 + /// + public void Callback() + { + _isExecute = true; + for (var i = 0; i < _listExist.Count; i++) + { + var d = _listExist[i]; + if (d is Action action) + { + action(); + } + } + + CheckModify(); + } + + /// + /// 回调调用。 + /// + /// 事件参数1。 + /// 事件参数1类型。 + public void Callback(TArg1 arg1) + { + _isExecute = true; + for (var i = 0; i < _listExist.Count; i++) + { + var d = _listExist[i]; + if (d is Action action) + { + action(arg1); + } + } + + CheckModify(); + } + + /// + /// 回调调用。 + /// + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数1类型。 + /// 事件参数2类型。 + public void Callback(TArg1 arg1, TArg2 arg2) + { + _isExecute = true; + for (var i = 0; i < _listExist.Count; i++) + { + var d = _listExist[i]; + if (d is Action action) + { + action(arg1, arg2); + } + } + + CheckModify(); + } + + /// + /// 回调调用。 + /// + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + public void Callback(TArg1 arg1, TArg2 arg2, TArg3 arg3) + { + _isExecute = true; + for (var i = 0; i < _listExist.Count; i++) + { + var d = _listExist[i]; + if (d is Action action) + { + action(arg1, arg2, arg3); + } + } + + CheckModify(); + } + + /// + /// 回调调用。 + /// + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + public void Callback(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4) + { + _isExecute = true; + for (var i = 0; i < _listExist.Count; i++) + { + var d = _listExist[i]; + if (d is Action action) + { + action(arg1, arg2, arg3, arg4); + } + } + + CheckModify(); + } + + /// + /// 回调调用。 + /// + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数5。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + public void Callback(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5) + { + _isExecute = true; + for (var i = 0; i < _listExist.Count; i++) + { + var d = _listExist[i]; + if (d is Action action) + { + action(arg1, arg2, arg3, arg4, arg5); + } + } + + CheckModify(); + } + + /// + /// 回调调用。 + /// + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数5。 + /// 事件参数6。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + /// 事件参数6类型。 + public void Callback(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6) + { + _isExecute = true; + for (var i = 0; i < _listExist.Count; i++) + { + var d = _listExist[i]; + if (d is Action action) + { + action(arg1, arg2, arg3, arg4, arg5, arg6); + } + } + + CheckModify(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDelegateData.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDelegateData.cs.meta new file mode 100644 index 00000000..706c2971 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDelegateData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 904e3efd24e749b0ad47a3684f57a43f +timeCreated: 1694793024 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDispatcher.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDispatcher.cs new file mode 100644 index 00000000..04487f92 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDispatcher.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 封装消息的底层分发和注册。 + /// + public class EventDispatcher + { + /// + /// 事件Table。 + /// + private static readonly Dictionary _eventTable = new Dictionary(); + + /// + /// 清空事件表。 + /// + internal void ClearEventTable() + { + _eventTable.Clear(); + } + #region 事件管理接口 + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理委托。 + /// 是否添加成功。 + public bool AddEventListener(int eventType, Delegate handler) + { + if (!_eventTable.TryGetValue(eventType, out var data)) + { + data = new EventDelegateData(eventType); + _eventTable.Add(eventType, data); + } + + return data.AddHandler(handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理委托。 + public void RemoveEventListener(int eventType, Delegate handler) + { + if (_eventTable.TryGetValue(eventType, out var data)) + { + data.RmvHandler(handler); + } + } + + #endregion + + #region 事件分发接口 + + /// + /// 发送事件。 + /// + /// 事件类型。 + public void Send(int eventType) + { + if (_eventTable.TryGetValue(eventType, out var d)) + { + d.Callback(); + } + } + + /// + /// 发送事件。 + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数1类型。 + public void Send(int eventType, TArg1 arg1) + { + if (_eventTable.TryGetValue(eventType, out var d)) + { + d.Callback(arg1); + } + } + + /// + /// 发送事件。 + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数1类型。 + /// 事件参数2类型。 + public void Send(int eventType, TArg1 arg1, TArg2 arg2) + { + if (_eventTable.TryGetValue(eventType, out var d)) + { + d.Callback(arg1, arg2); + } + } + + /// + /// 发送事件。 + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + public void Send(int eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3) + { + if (_eventTable.TryGetValue(eventType, out var d)) + { + d.Callback(arg1, arg2, arg3); + } + } + + /// + /// 发送事件。 + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + public void Send(int eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4) + { + if (_eventTable.TryGetValue(eventType, out var d)) + { + d.Callback(arg1, arg2, arg3, arg4); + } + } + + /// + /// 发送事件。 + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数5。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + public void Send(int eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5) + { + if (_eventTable.TryGetValue(eventType, out var d)) + { + d.Callback(arg1, arg2, arg3, arg4, arg5); + } + } + + /// + /// 发送事件。 + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数5。 + /// 事件参数6。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + /// 事件参数6类型。 + public void Send(int eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6) + { + if (_eventTable.TryGetValue(eventType, out var d)) + { + d.Callback(arg1, arg2, arg3, arg4, arg5, arg6); + } + } + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDispatcher.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDispatcher.cs.meta new file mode 100644 index 00000000..c2282474 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventDispatcher.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ccd33d1eef8948bdba477efbcffd7c08 +timeCreated: 1680273952 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventInterfaceAttribute.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventInterfaceAttribute.cs new file mode 100644 index 00000000..e9f411b3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventInterfaceAttribute.cs @@ -0,0 +1,31 @@ +using System; + +namespace TEngine +{ + /// + /// 事件分组枚举。 + /// + public enum EEventGroup + { + /// + /// UI相关的交互。 + /// + GroupUI, + + /// + /// 逻辑层内部相关的交互。 + /// + GroupLogic, + } + + [System.AttributeUsage(System.AttributeTargets.Interface)] + public class EventInterfaceAttribute : Attribute + { + private EEventGroup _eGroup; + public EEventGroup EventGroup => _eGroup; + public EventInterfaceAttribute(EEventGroup group) + { + _eGroup = group; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventInterfaceAttribute.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventInterfaceAttribute.cs.meta new file mode 100644 index 00000000..c18daec7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventInterfaceAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cf6ccd1a939b4a219ceeb1e3053a4a93 +timeCreated: 1680273952 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventMgr.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventMgr.cs new file mode 100644 index 00000000..5ae3da19 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventMgr.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 事件管理器。 + /// + public class EventMgr + { + /// + /// 事件实体数据。 + /// + private class EventEntryData + { + public object InterfaceWrap; + }; + + /// + /// 总事件实体数据。 + /// + private readonly Dictionary _eventEntryMap = new Dictionary(); + + /// + /// 事件管理器获取接口。 + /// + /// 接口类型。 + /// 接口实例。 + public T GetInterface() + { + string typeName = typeof(T).FullName; + if (typeName != null && _eventEntryMap.TryGetValue(typeName, out var entry)) + { + return (T)entry.InterfaceWrap; + } + return default(T); + } + + /// + /// 注册wrap的函数。 + /// + /// Wrap接口类型。 + /// callerWrap接口名字。 + public void RegWrapInterface(T callerWrap) + { + string typeName = typeof(T).FullName; + var entry = new EventEntryData(); + entry.InterfaceWrap = callerWrap; + if (typeName != null) + { + _eventEntryMap.Add(typeName, entry); + } + } + + /// + /// 注册wrap的函数。 + /// + /// 类型名称。 + /// 调用接口名。 + public void RegWrapInterface(string typeName,object callerWrap) + { + var entry = new EventEntryData(); + entry.InterfaceWrap = callerWrap; + if (typeName != null) + { + _eventEntryMap[typeName] = entry; + } + } + + /// + /// 分发注册器。 + /// + public EventDispatcher Dispatcher { get; private set; } = new EventDispatcher(); + + /// + /// 清除事件。 + /// + public void Init() + { + _eventEntryMap.Clear(); + Dispatcher.ClearEventTable(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventMgr.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventMgr.cs.meta new file mode 100644 index 00000000..4e4571f2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/EventMgr.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1fa2a6a1b01543238f031ac70df4d0ee +timeCreated: 1680273952 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEvent.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEvent.cs new file mode 100644 index 00000000..541d21d2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEvent.cs @@ -0,0 +1,597 @@ +using System; + +namespace TEngine +{ + /// + /// 游戏全局事件类。 + /// + public static class GameEvent + { + /// + /// 全局事件管理器。 + /// + private static readonly EventMgr _eventMgr = new EventMgr(); + + public static EventMgr EventMgr => _eventMgr; + #region 细分的注册接口 + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件Handler。 + /// 是否监听成功。 + public static bool AddEventListener(int eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(eventType, handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// + public static bool AddEventListener(int eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(eventType, handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// + public static bool AddEventListener(int eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(eventType, handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// + public static bool AddEventListener(int eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(eventType, handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// + public static bool AddEventListener(int eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(eventType, handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + /// + public static bool AddEventListener(int eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(eventType, handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + /// 事件参数6类型。 + /// + public static bool AddEventListener(int eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(eventType, handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + public static void RemoveEventListener(int eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(eventType, handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + public static void RemoveEventListener(int eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(eventType, handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + public static void RemoveEventListener(int eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(eventType, handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + public static void RemoveEventListener(int eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(eventType, handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + public static void RemoveEventListener(int eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(eventType, handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + public static void RemoveEventListener(int eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(eventType, handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + public static void RemoveEventListener(int eventType, Delegate handler) + { + _eventMgr.Dispatcher.RemoveEventListener(eventType, handler); + } + + //----------------------------string Event----------------------------// + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// + public static bool AddEventListener(string eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// + public static bool AddEventListener(string eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// + public static bool AddEventListener(string eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// + public static bool AddEventListener(string eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// + public static bool AddEventListener(string eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 增加事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + /// + public static bool AddEventListener(string eventType, Action handler) + { + return _eventMgr.Dispatcher.AddEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + public static void RemoveEventListener(string eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + public static void RemoveEventListener(string eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + public static void RemoveEventListener(string eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + public static void RemoveEventListener(string eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + public static void RemoveEventListener(string eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + public static void RemoveEventListener(string eventType, Action handler) + { + _eventMgr.Dispatcher.RemoveEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + /// + /// 移除事件监听。 + /// + /// 事件类型。 + /// 事件处理回调。 + public static void RemoveEventListener(string eventType, Delegate handler) + { + _eventMgr.Dispatcher.RemoveEventListener(RuntimeId.ToRuntimeId(eventType), handler); + } + + #endregion + + #region 分发消息接口 + + public static TArg1 Get() + { + return _eventMgr.GetInterface(); + } + + /// + /// + /// + /// 事件类型。 + public static void Send(int eventType) + { + _eventMgr.Dispatcher.Send(eventType); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数1类型。 + public static void Send(int eventType, TArg1 arg1) + { + _eventMgr.Dispatcher.Send(eventType, arg1); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数1类型。 + /// 事件参数2类型。 + public static void Send(int eventType, TArg1 arg1, TArg2 arg2) + { + _eventMgr.Dispatcher.Send(eventType, arg1, arg2); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + public static void Send(int eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3) + { + _eventMgr.Dispatcher.Send(eventType, arg1, arg2, arg3); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + public static void Send(int eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4) + { + _eventMgr.Dispatcher.Send(eventType, arg1, arg2, arg3, arg4); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数5。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + public static void Send(int eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5) + { + _eventMgr.Dispatcher.Send(eventType, arg1, arg2, arg3, arg4, arg5); + } + + /// + /// + /// + /// 事件类型。 + /// 事件处理回调。 + public static void Send(int eventType, Delegate handler) + { + _eventMgr.Dispatcher.Send(eventType, handler); + } + + //-------------------------------string Send-------------------------------// + /// + /// + /// + /// 事件类型。 + public static void Send(string eventType) + { + _eventMgr.Dispatcher.Send(RuntimeId.ToRuntimeId(eventType)); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数1类型。 + public static void Send(string eventType, TArg1 arg1) + { + _eventMgr.Dispatcher.Send(RuntimeId.ToRuntimeId(eventType), arg1); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数1类型。 + /// 事件参数2类型。 + public static void Send(string eventType, TArg1 arg1, TArg2 arg2) + { + _eventMgr.Dispatcher.Send(RuntimeId.ToRuntimeId(eventType), arg1, arg2); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + public static void Send(string eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3) + { + _eventMgr.Dispatcher.Send(RuntimeId.ToRuntimeId(eventType), arg1, arg2, arg3); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + public static void Send(string eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4) + { + _eventMgr.Dispatcher.Send(RuntimeId.ToRuntimeId(eventType), arg1, arg2, arg3); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数5。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + public static void Send(string eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5) + { + _eventMgr.Dispatcher.Send(RuntimeId.ToRuntimeId(eventType), arg1, arg2, arg3, arg4, arg5); + } + + /// + /// + /// + /// 事件类型。 + /// 事件参数1。 + /// 事件参数2。 + /// 事件参数3。 + /// 事件参数4。 + /// 事件参数5。 + /// 事件参数6。 + /// 事件参数1类型。 + /// 事件参数2类型。 + /// 事件参数3类型。 + /// 事件参数4类型。 + /// 事件参数5类型。 + /// 事件参数6类型。 + public static void Send(int eventType, TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6) + { + _eventMgr.Dispatcher.Send(eventType, arg1, arg2, arg3, arg4, arg5, arg6); + } + + /// + /// + /// + /// 事件类型。 + /// 事件处理回调。 + public static void Send(string eventType, Delegate handler) + { + _eventMgr.Dispatcher.Send(RuntimeId.ToRuntimeId(eventType), handler); + } + + #endregion + + /// + /// 清除事件。 + /// + public static void Shutdown() + { + _eventMgr.Init(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEvent.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEvent.cs.meta new file mode 100644 index 00000000..908df5d8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEvent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d6b9be7cbb8a4a7780502d317c3b3372 +timeCreated: 1680273952 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs new file mode 100644 index 00000000..1d1525a7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 游戏事件管理器。 + /// + public class GameEventMgr : IMemory + { + private readonly List _listEventTypes; + private readonly List _listHandles; + private readonly bool _isInit = false; + + /// + /// 游戏事件管理器构造函数。 + /// + public GameEventMgr() + { + if (_isInit) + { + return; + } + + _isInit = true; + _listEventTypes = new List(); + _listHandles = new List(); + } + + /// + /// 清理内存对象回收入池。 + /// + public void Clear() + { + if (!_isInit) + { + return; + } + + for (int i = 0; i < _listEventTypes.Count; ++i) + { + var eventType = _listEventTypes[i]; + var handle = _listHandles[i]; + GameEvent.RemoveEventListener(eventType, handle); + } + + _listEventTypes.Clear(); + _listHandles.Clear(); + } + + private void AddEventImp(int eventType, Delegate handler) + { + _listEventTypes.Add(eventType); + _listHandles.Add(handler); + } + + #region UIEvent + + public void AddEvent(int eventType, Action handler) + { + if (GameEvent.AddEventListener(eventType, handler)) + { + AddEventImp(eventType, handler); + } + } + + public void AddEvent(int eventType, Action handler) + { + if (GameEvent.AddEventListener(eventType, handler)) + { + AddEventImp(eventType, handler); + } + } + + public void AddEvent(int eventType, Action handler) + { + if (GameEvent.AddEventListener(eventType, handler)) + { + AddEventImp(eventType, handler); + } + } + + public void AddEvent(int eventType, Action handler) + { + if (GameEvent.AddEventListener(eventType, handler)) + { + AddEventImp(eventType, handler); + } + } + + public void AddEvent(int eventType, Action handler) + { + if (GameEvent.AddEventListener(eventType, handler)) + { + AddEventImp(eventType, handler); + } + } + + public void AddEvent(int eventType, Action handler) + { + if (GameEvent.AddEventListener(eventType, handler)) + { + AddEventImp(eventType, handler); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs.meta new file mode 100644 index 00000000..3704cd00 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/GameEventMgr.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 09c516fcdf8d4b0196a2039ab847a094 +timeCreated: 1680273952 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/RuntimeId.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/RuntimeId.cs new file mode 100644 index 00000000..49ad0785 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/RuntimeId.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 运行时Id。 + /// 提供给事件分发的运行时Id。 + /// public static readonly int ExampleEventId = RuntimeId.ToRuntimeId("ExampleEvent.ExampleEventId"); + /// + public static class RuntimeId + { + /// + /// Key->字符串 | Value->RuntimeIdTable) + /// + private static readonly Dictionary _eventString2RuntimeMap = new Dictionary(); + + /// + /// Key->RuntimeId | Value->字符串 (Table) + /// + private static readonly Dictionary _eventRuntimeToStringMap = new Dictionary(); + + /// + /// 当前运行时Id。 + /// + private static int _currentRuntimeId = 0; + + /// + /// 字符串转RuntimeId。 + /// + /// 字符串Value。 + /// RuntimeId。 + public static int ToRuntimeId(string value) + { + if (_eventString2RuntimeMap.TryGetValue(value, out var runtimeId)) + { + return runtimeId; + } + + runtimeId = ++_currentRuntimeId; + _eventString2RuntimeMap[value] = runtimeId; + _eventRuntimeToStringMap[runtimeId] = value; + + return runtimeId; + } + + /// + /// RuntimeId转字符串。 + /// + /// RuntimeId。 + /// 字符串。 + public static string ToString(int runtimeId) + { + return _eventRuntimeToStringMap.TryGetValue(runtimeId, out var value) ? value : string.Empty; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/RuntimeId.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/RuntimeId.cs.meta new file mode 100644 index 00000000..f78fa3a9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameEvent/RuntimeId.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: af219e27c2e1424ea3823c0bc589301f +timeCreated: 1680273952 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings.meta new file mode 100644 index 00000000..d6537d92 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b023ed952b050f54eadee4e684c901a8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum.meta new file mode 100644 index 00000000..1008119a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 291e2761f1e84446b23bcc056c54ac38 +timeCreated: 1695126771 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/AppStageEnum.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/AppStageEnum.cs new file mode 100644 index 00000000..e085e746 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/AppStageEnum.cs @@ -0,0 +1,31 @@ +/// +/// App阶段标识枚举。 +/// +public enum AppStageEnum +{ + /// + /// 测试版本。 + /// + Debug = 1, + + /// + /// 前期版本。 + /// + Alpha = 2, + + /// + /// 中期版本。 + /// + Beta = 3, + + /// + /// 后期版本。 + /// 与发布版本差别不大。 + /// + Rc = 4, + + /// + /// 发布版本。 + /// + Release = 5 +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/AppStageEnum.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/AppStageEnum.cs.meta new file mode 100644 index 00000000..59a54c61 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/AppStageEnum.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 12048d69aa8141fdbbbc180ea58a56c9 +timeCreated: 1695126782 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/ServerTypeEnum.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/ServerTypeEnum.cs new file mode 100644 index 00000000..faad47c1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/ServerTypeEnum.cs @@ -0,0 +1,25 @@ +/// +/// 服务器类型枚举。 +/// +public enum ServerTypeEnum +{ + /// + /// 无。 + /// + None = 0, + + /// + /// 内网。 + /// + Intranet = 1, + + /// + /// 外网。 + /// + Extranet = 2, + + /// + /// 正式服。 + /// + Formal = 3 +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/ServerTypeEnum.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/ServerTypeEnum.cs.meta new file mode 100644 index 00000000..7369cead --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Enum/ServerTypeEnum.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 85ed8877983d4dee8f85c606429fb019 +timeCreated: 1695126852 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework.meta new file mode 100644 index 00000000..30e403d8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7aa28f74686948c98dfc0d5b4071d2cf +timeCreated: 1695126746 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework/FrameworkGlobalSettings.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework/FrameworkGlobalSettings.cs new file mode 100644 index 00000000..4414c0ba --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework/FrameworkGlobalSettings.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Serialization; +#if UNITY_EDITOR +// using Sirenix.OdinInspector; +using UnityEditor; +#endif + +/// +/// 资源存放地址。 +/// +[Serializable] +public class ResourcesArea +{ + [Tooltip("资源管理类型")] [SerializeField] private string m_ResAdminType = "Default"; + + /// + /// 资源管理类型。 + /// + public string ResAdminType => m_ResAdminType; + + [Tooltip("资源管理编号")] [SerializeField] private string m_ResAdminCode = "0"; + + /// + /// 资源管理编号。 + /// + public string ResAdminCode => m_ResAdminCode; + + [Tooltip("服务器类型")] [SerializeField] private ServerTypeEnum m_ServerType = ServerTypeEnum.Intranet; + + /// + /// 服务器类型。 + /// + public ServerTypeEnum ServerType => m_ServerType; + + [Tooltip("是否在构建资源的时候清理上传到服务端目录的老资源")] [SerializeField] + private bool m_CleanCommitPathRes = true; + + public bool CleanCommitPathRes => m_CleanCommitPathRes; + + [Tooltip("内网地址")] [SerializeField] private string m_InnerResourceSourceUrl = "http://127.0.0.1:8088"; + + public string InnerResourceSourceUrl => m_InnerResourceSourceUrl; + + [Tooltip("外网地址")] [SerializeField] private string m_ExtraResourceSourceUrl = "http://127.0.0.1:8088"; + + public string ExtraResourceSourceUrl => m_ExtraResourceSourceUrl; + + [Tooltip("正式地址")] [SerializeField] private string m_FormalResourceSourceUrl = "http://127.0.0.1:8088"; + + public string FormalResourceSourceUrl => m_FormalResourceSourceUrl; +} + +[Serializable] +public class ServerIpAndPort +{ + public string serverName; + public string ip; + public int port; +} + +[Serializable] +public class ServerChannelInfo +{ + public string channelName; + public string curUseServerName; + public List serverIpAndPorts; +} + +[Serializable] +public class FrameworkGlobalSettings +{ + [SerializeField] [Tooltip("脚本作者名")] private string m_ScriptAuthor = "Default"; + + public string ScriptAuthor => m_ScriptAuthor; + + [SerializeField] [Tooltip("版本")] private string m_ScriptVersion = "0.1"; + + public string ScriptVersion => m_ScriptVersion; + + [FormerlySerializedAs("mEAppStage")] [FormerlySerializedAs("m_AppStage")] [SerializeField] + private AppStageEnum mAppStageEnum = AppStageEnum.Debug; + + public AppStageEnum AppStageEnum => mAppStageEnum; + + [Header("Font")] [SerializeField] private string m_DefaultFont = "Arial"; + public string DefaultFont => m_DefaultFont; + + [Header("Resources")] [Tooltip("资源存放地")] [SerializeField] + private ResourcesArea m_ResourcesArea; + + public ResourcesArea ResourcesArea => m_ResourcesArea; + + [Header("SpriteCollection")] [SerializeField] + private string m_AtlasFolder = "Assets/AssetRaw/Atlas"; + + public string AtlasFolder => m_AtlasFolder; + + [Header("Hotfix")] + + public string HostServerURL = "http://127.0.0.1:8081"; + + public string FallbackHostServerURL = "http://127.0.0.1:8081"; + + public bool EnableUpdateData = false; + + public string WindowsUpdateDataUrl = "http://127.0.0.1"; + public string MacOSUpdateDataUrl = "http://127.0.0.1"; + public string IOSUpdateDataUrl = "http://127.0.0.1"; + public string AndroidUpdateDataUrl = "http://127.0.0.1"; + public string WebGLUpdateDataUrl = "http://127.0.0.1"; + [Header("Server")] [SerializeField] private string m_CurUseServerChannel; + + public string CurUseServerChannel => m_CurUseServerChannel; + + [SerializeField] private List m_ServerChannelInfos; + + public List ServerChannelInfos => m_ServerChannelInfos; + + [SerializeField] private string @namespace = "GameLogic"; + + public string NameSpace => @namespace; + + [SerializeField] private List scriptGenerateRule = new List() + { + new ScriptGenerateRuler("m_go", "GameObject"), + new ScriptGenerateRuler("m_item", "GameObject"), + new ScriptGenerateRuler("m_tf", "Transform"), + new ScriptGenerateRuler("m_rect", "RectTransform"), + new ScriptGenerateRuler("m_text", "Text"), + new ScriptGenerateRuler("m_richText", "RichTextItem"), + new ScriptGenerateRuler("m_btn", "Button"), + new ScriptGenerateRuler("m_img", "Image"), + new ScriptGenerateRuler("m_rimg", "RawImage"), + new ScriptGenerateRuler("m_scrollBar", "Scrollbar"), + new ScriptGenerateRuler("m_scroll", "ScrollRect"), + new ScriptGenerateRuler("m_input", "InputField"), + new ScriptGenerateRuler("m_grid", "GridLayoutGroup"), + new ScriptGenerateRuler("m_hlay", "HorizontalLayoutGroup"), + new ScriptGenerateRuler("m_vlay", "VerticalLayoutGroup"), + new ScriptGenerateRuler("m_red", "RedNoteBehaviour"), + new ScriptGenerateRuler("m_slider", "Slider"), + new ScriptGenerateRuler("m_group", "ToggleGroup"), + new ScriptGenerateRuler("m_curve", "AnimationCurve"), + new ScriptGenerateRuler("m_canvasGroup", "CanvasGroup"), +#if ENABLE_TEXTMESHPRO + new ScriptGenerateRuler("m_tmp","TextMeshProUGUI"), +#endif + }; + + public List ScriptGenerateRule => scriptGenerateRule; +} + +[Serializable] +public class ScriptGenerateRuler +{ + public string uiElementRegex; + public string componentName; + + public ScriptGenerateRuler(string uiElementRegex, string componentName) + { + this.uiElementRegex = uiElementRegex; + this.componentName = componentName; + } +} + +#if UNITY_EDITOR +[CustomPropertyDrawer(typeof(ScriptGenerateRuler))] +public class ScriptGenerateRulerDrawer : PropertyDrawer +{ + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUI.BeginProperty(position, label, property); + position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); + var indent = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + var uiElementRegexRect = new Rect(position.x, position.y, 120, position.height); + var componentNameRect = new Rect(position.x + 125, position.y, 150, position.height); + EditorGUI.PropertyField(uiElementRegexRect, property.FindPropertyRelative("uiElementRegex"), GUIContent.none); + EditorGUI.PropertyField(componentNameRect, property.FindPropertyRelative("componentName"), GUIContent.none); + EditorGUI.indentLevel = indent; + EditorGUI.EndProperty(); + } +} +#endif \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework/FrameworkGlobalSettings.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework/FrameworkGlobalSettings.cs.meta new file mode 100644 index 00000000..99a04fd3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/Framework/FrameworkGlobalSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3eb9df088d254feaa49d19bad18cec8b +timeCreated: 1678945935 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR.meta new file mode 100644 index 00000000..934c51ab --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8739e06541cb48baaaadc0680b48da2e +timeCreated: 1695126699 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR/HybridCLRCustomGlobalSettings.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR/HybridCLRCustomGlobalSettings.cs new file mode 100644 index 00000000..f32e60bf --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR/HybridCLRCustomGlobalSettings.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Serialization; + +/// +/// HybridCLRCustomGlobalSettings. +/// +[Serializable] +public class HybridCLRCustomGlobalSettings +{ + public bool Enable + { + get + { +#if ENABLE_HYBRIDCLR + return true; +#else + return false; +#endif + } + } + + [Header("Auto sync with [HybridCLRGlobalSettings]")] + [Tooltip("You should modify the file form file path [Assets/CustomHybridCLR/Settings/HybridCLRGlobalSettings.asset]")] + public List HotUpdateAssemblies = new List() { "GameBase.dll","DotNet.dll","GameProto.dll","BattleCore.Runtime.dll","GameLogic.dll"}; + + [Header("Need manual setting!")] public List AOTMetaAssemblies= new List() {"mscorlib.dll","System.dll","System.Core.dll" }; + + /// + /// Dll of main business logic assembly + /// + public string LogicMainDllName = "GameLogic.dll"; + + /// + /// 程序集文本资产打包Asset后缀名 + /// + public string AssemblyTextAssetExtension = ".bytes"; + + /// + /// 程序集文本资产资源目录 + /// + public string AssemblyTextAssetPath = "AssetRaw/DLL"; + + /// + /// Resources HybridCLRGlobalSettings Dir + /// + public string HybridCLRGlobalSettings = "Settings/HybridCLRGlobalSettings"; +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR/HybridCLRCustomGlobalSettings.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR/HybridCLRCustomGlobalSettings.cs.meta new file mode 100644 index 00000000..3ef0916e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/HybridCLR/HybridCLRCustomGlobalSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 88b6465202d847c08f39cf6200f0777b +timeCreated: 1678945935 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/SettingsUtils.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/SettingsUtils.cs new file mode 100644 index 00000000..a1897fe9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/SettingsUtils.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using System.IO; +using TEngine; +using UnityEngine; + +public static class SettingsUtils +{ + private static readonly string GlobalSettingsPath = $"TEngineGlobalSettings"; + private static TEngineSettings _globalSettings; + + public static TEngineSettings GlobalSettings + { + get + { + if (_globalSettings == null) + { + _globalSettings = GetSingletonAssetsByResources(GlobalSettingsPath); + } + + return _globalSettings; + } + } + + public static FrameworkGlobalSettings FrameworkGlobalSettings => GlobalSettings.FrameworkGlobalSettings; + + public static HybridCLRCustomGlobalSettings HybridCLRCustomGlobalSettings => GlobalSettings.BybridCLRCustomGlobalSettings; + + public static ResourcesArea ResourcesArea => GlobalSettings.FrameworkGlobalSettings.ResourcesArea; + + public static void SetHybridCLRHotUpdateAssemblies(List hotUpdateAssemblies) + { + HybridCLRCustomGlobalSettings.HotUpdateAssemblies.Clear(); + HybridCLRCustomGlobalSettings.HotUpdateAssemblies.AddRange(hotUpdateAssemblies); + } + + public static void SetHybridCLRAOTMetaAssemblies(List aOTMetaAssemblies) + { + HybridCLRCustomGlobalSettings.AOTMetaAssemblies.Clear(); + HybridCLRCustomGlobalSettings.AOTMetaAssemblies.AddRange(aOTMetaAssemblies); + } + + public static bool EnableUpdateData() + { + return FrameworkGlobalSettings.EnableUpdateData; + } + + public static string GetUpdateDataUrl() + { + string url = null; +#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN + url = FrameworkGlobalSettings.WindowsUpdateDataUrl; +#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX + url = FrameworkGlobalSettings.MacOSUpdateDataUrl; +#elif UNITY_IOS + url = FrameworkGlobalSettings.IOSUpdateDataUrl; +#elif UNITY_ANDROID + url = FrameworkGlobalSettings.AndroidUpdateDataUrl; +#elif UNITY_WEBGL + url = FrameworkGlobalSettings.WebGLUpdateDataUrl; +#endif + return url; + } + + public static string GetResDownLoadPath(string fileName = "") + { + return Path.Combine(CompleteDownLoadPath, $"{ResourcesArea.ResAdminType}_{ResourcesArea.ResAdminCode}", GetPlatformName(), fileName).Replace("\\", "/"); + } + + public static string CompleteDownLoadPath + { + get + { + string url = ""; + if (ResourcesArea.ServerType == ServerTypeEnum.Extranet) + { + url = ResourcesArea.ExtraResourceSourceUrl; + } + else if (ResourcesArea.ServerType == ServerTypeEnum.Formal) + { + url = ResourcesArea.FormalResourceSourceUrl; + } + else + { + url = ResourcesArea.InnerResourceSourceUrl; + } + + return url; + } + } + + private static ServerIpAndPort FindServerIpAndPort(string channelName = "") + { + if (string.IsNullOrEmpty(channelName)) + { + channelName = FrameworkGlobalSettings.CurUseServerChannel; + } + + foreach (var serverChannelInfo in FrameworkGlobalSettings.ServerChannelInfos) + { + if (serverChannelInfo.channelName.Equals(channelName)) + { + foreach (var serverIpAndPort in serverChannelInfo.serverIpAndPorts) + { + if (serverIpAndPort.serverName.Equals(serverChannelInfo.curUseServerName)) + { + return serverIpAndPort; + } + } + } + } + + return null; + } + + public static string GetServerIp(string channelName = "") + { + ServerIpAndPort serverIpAndPort = FindServerIpAndPort(channelName); + if (serverIpAndPort != null) + { + return serverIpAndPort.ip; + } + + return string.Empty; + } + + public static int GetServerPort(string channelName = "") + { + ServerIpAndPort serverIpAndPort = FindServerIpAndPort(channelName); + if (serverIpAndPort != null) + { + return serverIpAndPort.port; + } + + return 0; + } + + private static T GetSingletonAssetsByResources(string assetsPath) where T : ScriptableObject, new() + { + string assetType = typeof(T).Name; +#if UNITY_EDITOR + string[] globalAssetPaths = UnityEditor.AssetDatabase.FindAssets($"t:{assetType}"); + if (globalAssetPaths.Length > 1) + { + foreach (var assetPath in globalAssetPaths) + { + Debug.LogError($"Could not had Multiple {assetType}. Repeated Path: {UnityEditor.AssetDatabase.GUIDToAssetPath(assetPath)}"); + } + + throw new Exception($"Could not had Multiple {assetType}"); + } +#endif + T customGlobalSettings = Resources.Load(assetsPath); + if (customGlobalSettings == null) + { + Log.Error($"Could not found {assetType} asset,so auto create:{assetsPath}."); + return null; + } + + return customGlobalSettings; + } + + /// + /// 平台名字 + /// + /// + public static string GetPlatformName() + { +#if UNITY_ANDROID + return "Android"; +#elif UNITY_IOS + return "IOS"; +#elif UNITY_WEBGL + return "WebGL"; +#else + switch (Application.platform) + { + case RuntimePlatform.WindowsEditor: + return "Windows64"; + case RuntimePlatform.WindowsPlayer: + return "Windows64"; + + case RuntimePlatform.OSXEditor: + case RuntimePlatform.OSXPlayer: + return "MacOS"; + + case RuntimePlatform.IPhonePlayer: + return "IOS"; + + case RuntimePlatform.Android: + return "Android"; + case RuntimePlatform.WebGLPlayer: + return "WebGL"; + + case RuntimePlatform.PS5: + return "PS5"; + default: + throw new NotSupportedException($"Platform '{Application.platform.ToString()}' is not supported."); + } +#endif + } + + public static List GetScriptGenerateRule() + { + return FrameworkGlobalSettings.ScriptGenerateRule; + } + + public static string GetUINameSpace() + { + return FrameworkGlobalSettings.NameSpace; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/SettingsUtils.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/SettingsUtils.cs.meta new file mode 100644 index 00000000..78cd012d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/SettingsUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2d3f7587c538425a8d6e26147f9a6bbd +timeCreated: 1695127165 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/TEngineSettings.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/TEngineSettings.cs new file mode 100644 index 00000000..99db444c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/TEngineSettings.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "TEngineGlobalSettings", menuName = "TEngine/TEngineSettings")] +public class TEngineSettings : ScriptableObject +{ + [Header("Framework")] [SerializeField] private FrameworkGlobalSettings m_FrameworkGlobalSettings; + + public FrameworkGlobalSettings FrameworkGlobalSettings => m_FrameworkGlobalSettings; + + [Header("HybridCLR")] [SerializeField] private HybridCLRCustomGlobalSettings m_HybridCLRCustomGlobalSettings; + + public HybridCLRCustomGlobalSettings BybridCLRCustomGlobalSettings => m_HybridCLRCustomGlobalSettings; + + public void Set(FrameworkGlobalSettings globalSettings,HybridCLRCustomGlobalSettings hybridClrCustomGlobalSettings) + { + m_FrameworkGlobalSettings = globalSettings; + m_HybridCLRCustomGlobalSettings = hybridClrCustomGlobalSettings; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/TEngineSettings.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/TEngineSettings.cs.meta new file mode 100644 index 00000000..72d70af4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameSettings/TEngineSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 29ba4d7c4a4b4c018116005145021a90 +timeCreated: 1695126657 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameTime.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameTime.meta new file mode 100644 index 00000000..9a0106ba --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameTime.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 34ecdc499ac4431eb8bd2fcafca32ba1 +timeCreated: 1694855450 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameTime/GameTime.cs b/EintooAR/Assets/TEngine/Runtime/Core/GameTime/GameTime.cs new file mode 100644 index 00000000..a39b73dc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameTime/GameTime.cs @@ -0,0 +1,55 @@ +using UnityEngine; +// ReSharper disable InconsistentNaming +namespace TEngine +{ + /// + /// 游戏时间。 + /// 提供从Unity获取时间信息的接口。 + /// + public static class GameTime + { + /// + /// 此帧开始时的时间(只读)。 + /// + public static float time; + + /// + /// 从上一帧到当前帧的间隔(秒)(只读)。 + /// + public static float deltaTime; + + /// + /// timeScale从上一帧到当前帧的独立时间间隔(以秒为单位)(只读)。 + /// + public static float unscaledDeltaTime; + + /// + /// 执行物理和其他固定帧速率更新的时间间隔(以秒为单位)。 + /// 如MonoBehavior的MonoBehaviour.FixedUpdate。 + /// + public static float fixedDeltaTime; + + /// + /// 自游戏开始以来的总帧数(只读)。 + /// + public static float frameCount; + + /// + /// timeScale此帧的独立时间(只读)。这是自游戏开始以来的时间(以秒为单位)。 + /// + public static float unscaledTime; + + /// + /// 采样一帧的时间。 + /// + public static void StartFrame() + { + time = Time.time; + deltaTime = Time.deltaTime; + unscaledDeltaTime = Time.unscaledDeltaTime; + fixedDeltaTime = Time.fixedDeltaTime; + frameCount = Time.frameCount; + unscaledTime = Time.unscaledTime; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/GameTime/GameTime.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/GameTime/GameTime.cs.meta new file mode 100644 index 00000000..1fce9b3d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/GameTime/GameTime.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8b8ef95462cc493fbbc3250e6992a818 +timeCreated: 1694855463 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Log.meta b/EintooAR/Assets/TEngine/Runtime/Core/Log.meta new file mode 100644 index 00000000..00618ba7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Log.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 832eed9eba420b14a9d4f0775f444c22 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.ILogHelper.cs b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.ILogHelper.cs new file mode 100644 index 00000000..2b7a3864 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.ILogHelper.cs @@ -0,0 +1,18 @@ +namespace TEngine +{ + public static partial class GameFrameworkLog + { + /// + /// 游戏框架日志辅助器接口。 + /// + public interface ILogHelper + { + /// + /// 记录日志。 + /// + /// 游戏框架日志等级。 + /// 日志内容。 + void Log(GameFrameworkLogLevel level, object message); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.ILogHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.ILogHelper.cs.meta new file mode 100644 index 00000000..f94d43f4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.ILogHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 742233e5df6aba34098af0b7ddbda8ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.cs b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.cs new file mode 100644 index 00000000..9fdff066 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.cs @@ -0,0 +1,2639 @@ +namespace TEngine +{ + /// + /// 游戏框架日志类。 + /// + public static partial class GameFrameworkLog + { + private static ILogHelper s_LogHelper = new DefaultLogHelper(); + + /// + /// 设置游戏框架日志辅助器。 + /// + /// 要设置的游戏框架日志辅助器。 + public static void SetLogHelper(ILogHelper logHelper) + { + s_LogHelper = logHelper; + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志内容。 + public static void Debug(object message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, message); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志内容。 + public static void Debug(string message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, message); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + public static void Debug(string format, T arg) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + public static void Debug(string format, T1 arg1, T2 arg2) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志内容。 + public static void Info(object message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, message); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志内容。 + public static void Info(string message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, message); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + public static void Info(string format, T arg) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + public static void Info(string format, T1 arg1, T2 arg2) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志内容。 + public static void Warning(object message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, message); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志内容。 + public static void Warning(string message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, message); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + public static void Warning(string format, T arg) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + public static void Warning(string format, T1 arg1, T2 arg2) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Warning, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志内容。 + public static void Error(object message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, message); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志内容。 + public static void Error(string message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, message); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + public static void Error(string format, T arg) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + public static void Error(string format, T1 arg1, T2 arg2) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Error, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志内容。 + public static void Fatal(object message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, message); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志内容。 + public static void Fatal(string message) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, message); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + public static void Fatal(string format, T arg) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + public static void Fatal(string format, T1 arg1, T2 arg2) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + if (s_LogHelper == null) + { + return; + } + + s_LogHelper.Log(GameFrameworkLogLevel.Fatal, Utility.Text.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16)); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.cs.meta new file mode 100644 index 00000000..00cce98b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08656a09d0b681e44b7f14da94cdd3a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLogLevel.cs b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLogLevel.cs new file mode 100644 index 00000000..83459ca0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLogLevel.cs @@ -0,0 +1,33 @@ +namespace TEngine +{ + /// + /// 游戏框架日志等级。 + /// + public enum GameFrameworkLogLevel : byte + { + /// + /// 调试。 + /// + Debug = 0, + + /// + /// 信息。 + /// + Info, + + /// + /// 警告。 + /// + Warning, + + /// + /// 错误。 + /// + Error, + + /// + /// 严重错误。 + /// + Fatal + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLogLevel.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLogLevel.cs.meta new file mode 100644 index 00000000..6ffb151c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Log/GameFrameworkLogLevel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e30a51c0f37958144940a6e7fc39d661 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Log/Log.cs b/EintooAR/Assets/TEngine/Runtime/Core/Log/Log.cs new file mode 100644 index 00000000..75edcb04 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Log/Log.cs @@ -0,0 +1,2780 @@ +using System.Diagnostics; + +namespace TEngine +{ + /// + /// 日志工具集。 + /// + public static class Log + { + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(object message) + { + GameFrameworkLog.Debug(message); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string message) + { + GameFrameworkLog.Debug(message); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T arg) + { + GameFrameworkLog.Debug(format, arg); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2) + { + GameFrameworkLog.Debug(format, arg1, arg2); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10, T11 arg11) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10, T11 arg11, T12 arg12) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, + T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); + } + + /// + /// 打印调试级别日志,用于记录调试类日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + /// 仅在带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_DEBUG_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + public static void Debug(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, + T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + GameFrameworkLog.Debug(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(object message) + { + GameFrameworkLog.Info(message); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string message) + { + GameFrameworkLog.Info(message); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T arg) + { + GameFrameworkLog.Info(format, arg); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2) + { + GameFrameworkLog.Info(format, arg1, arg2); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10, T11 arg11) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10, T11 arg11, T12 arg12) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, + T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); + } + + /// + /// 打印信息级别日志,用于记录程序正常运行日志信息。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + /// 仅在带有 ENABLE_LOG、ENABLE_INFO_LOG、ENABLE_DEBUG_AND_ABOVE_LOG 或 ENABLE_INFO_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_INFO_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + public static void Info(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, + T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + GameFrameworkLog.Info(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(object message) + { + GameFrameworkLog.Warning(message); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string message) + { + GameFrameworkLog.Warning(message); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T arg) + { + GameFrameworkLog.Warning(format, arg); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2) + { + GameFrameworkLog.Warning(format, arg1, arg2); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10, T11 arg11) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, + T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, + T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); + } + + /// + /// 打印警告级别日志,建议在发生局部功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + /// 仅在带有 ENABLE_LOG、ENABLE_WARNING_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG 或 ENABLE_WARNING_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_WARNING_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + public static void Warning(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, + T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + GameFrameworkLog.Warning(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(object message) + { + GameFrameworkLog.Error(message); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string message) + { + GameFrameworkLog.Error(message); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T arg) + { + GameFrameworkLog.Error(format, arg); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2) + { + GameFrameworkLog.Error(format, arg1, arg2); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10, T11 arg11) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10, T11 arg11, T12 arg12) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, + T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); + } + + /// + /// 打印错误级别日志,建议在发生功能逻辑错误,但尚不会导致游戏崩溃或异常时使用。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + /// 仅在带有 ENABLE_LOG、ENABLE_ERROR_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG 或 ENABLE_ERROR_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_ERROR_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + public static void Error(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, + T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + GameFrameworkLog.Error(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(object message) + { + GameFrameworkLog.Fatal(message); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志内容。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string message) + { + GameFrameworkLog.Fatal(message); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数的类型。 + /// 日志格式。 + /// 日志参数。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T arg) + { + GameFrameworkLog.Fatal(format, arg); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2) + { + GameFrameworkLog.Fatal(format, arg1, arg2); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10, T11 arg11) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, + T10 arg10, T11 arg11, T12 arg12) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, + T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, + T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); + } + + /// + /// 打印严重错误级别日志,建议在发生严重错误,可能导致游戏崩溃或异常时使用,此时应尝试重启进程或重建游戏框架。 + /// + /// 日志参数 1 的类型。 + /// 日志参数 2 的类型。 + /// 日志参数 3 的类型。 + /// 日志参数 4 的类型。 + /// 日志参数 5 的类型。 + /// 日志参数 6 的类型。 + /// 日志参数 7 的类型。 + /// 日志参数 8 的类型。 + /// 日志参数 9 的类型。 + /// 日志参数 10 的类型。 + /// 日志参数 11 的类型。 + /// 日志参数 12 的类型。 + /// 日志参数 13 的类型。 + /// 日志参数 14 的类型。 + /// 日志参数 15 的类型。 + /// 日志参数 16 的类型。 + /// 日志格式。 + /// 日志参数 1。 + /// 日志参数 2。 + /// 日志参数 3。 + /// 日志参数 4。 + /// 日志参数 5。 + /// 日志参数 6。 + /// 日志参数 7。 + /// 日志参数 8。 + /// 日志参数 9。 + /// 日志参数 10。 + /// 日志参数 11。 + /// 日志参数 12。 + /// 日志参数 13。 + /// 日志参数 14。 + /// 日志参数 15。 + /// 日志参数 16。 + /// 仅在带有 ENABLE_LOG、ENABLE_FATAL_LOG、ENABLE_DEBUG_AND_ABOVE_LOG、ENABLE_INFO_AND_ABOVE_LOG、ENABLE_WARNING_AND_ABOVE_LOG、ENABLE_ERROR_AND_ABOVE_LOG 或 ENABLE_FATAL_AND_ABOVE_LOG 预编译选项时生效。 + [Conditional("ENABLE_LOG")] + [Conditional("ENABLE_FATAL_LOG")] + [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")] + [Conditional("ENABLE_INFO_AND_ABOVE_LOG")] + [Conditional("ENABLE_WARNING_AND_ABOVE_LOG")] + [Conditional("ENABLE_ERROR_AND_ABOVE_LOG")] + [Conditional("ENABLE_FATAL_AND_ABOVE_LOG")] + public static void Fatal(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, + T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + GameFrameworkLog.Fatal(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + } + + /// + /// 断言严重错误级别日志,建议在发生严重错误。 + /// + /// 条件。 + [Conditional("ENABLE_LOG")] + public static void Assert(bool condition) + { + if (!condition) + { + string message = Utility.Text.Format("{0}\n{1}", "Assert Failed", System.Environment.StackTrace); + Fatal(message); + } + } + + /// + /// 断言严重错误级别日志,建议在发生严重错误。 + /// + /// 条件。 + /// 断言输出字符串。 + [Conditional("ENABLE_LOG")] + public static void Assert(bool condition, string retStr) + { + if (!condition) + { + string message = Utility.Text.Format("{0}\n{1}", "Assert Failed" + retStr, System.Environment.StackTrace); + Fatal(message); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Log/Log.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Log/Log.cs.meta new file mode 100644 index 00000000..baeb654b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Log/Log.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e9d579404484cb40b5049f1307a6139 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool.meta b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool.meta new file mode 100644 index 00000000..4c07ef0f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 80d6660a8c5d4cf7ab57646d832e503e +timeCreated: 1694791678 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/IMemory.cs b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/IMemory.cs new file mode 100644 index 00000000..71659386 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/IMemory.cs @@ -0,0 +1,13 @@ +namespace TEngine +{ + /// + /// 内存对象Interface。 + /// + public interface IMemory + { + /// + /// 清理内存对象回收入池。 + /// + void Clear(); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/IMemory.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/IMemory.cs.meta new file mode 100644 index 00000000..0385e9bb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/IMemory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 29d6300317e70b24381120ac8f5b0a92 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs new file mode 100644 index 00000000..aba4bcf0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + public static partial class MemoryPool + { + /// + /// 内存池收集器。 + /// + private sealed class MemoryCollection + { + private readonly Queue _memories; + private readonly Type _memoryType; + private int _usingMemoryCount; + private int _acquireMemoryCount; + private int _releaseMemoryCount; + private int _addMemoryCount; + private int _removeMemoryCount; + + public MemoryCollection(Type memoryType) + { + _memories = new Queue(); + _memoryType = memoryType; + _usingMemoryCount = 0; + _acquireMemoryCount = 0; + _releaseMemoryCount = 0; + _addMemoryCount = 0; + _removeMemoryCount = 0; + } + + public Type MemoryType => _memoryType; + + public int UnusedMemoryCount => _memories.Count; + + public int UsingMemoryCount => _usingMemoryCount; + + public int AcquireMemoryCount => _acquireMemoryCount; + + public int ReleaseMemoryCount => _releaseMemoryCount; + + public int AddMemoryCount => _addMemoryCount; + + public int RemoveMemoryCount => _removeMemoryCount; + + public T Acquire() where T : class, IMemory, new() + { + if (typeof(T) != _memoryType) + { + throw new Exception("Type is invalid."); + } + + _usingMemoryCount++; + _acquireMemoryCount++; + lock (_memories) + { + if (_memories.Count > 0) + { + return (T)_memories.Dequeue(); + } + } + + _addMemoryCount++; + return new T(); + } + + public IMemory Acquire() + { + _usingMemoryCount++; + _acquireMemoryCount++; + lock (_memories) + { + if (_memories.Count > 0) + { + return _memories.Dequeue(); + } + } + + _addMemoryCount++; + return (IMemory)Activator.CreateInstance(_memoryType); + } + + public void Release(IMemory memory) + { + memory.Clear(); + lock (_memories) + { + if (_enableStrictCheck && _memories.Contains(memory)) + { + throw new Exception("The memory has been released."); + } + + _memories.Enqueue(memory); + } + + _releaseMemoryCount++; + _usingMemoryCount--; + } + + public void Add(int count) where T : class, IMemory, new() + { + if (typeof(T) != _memoryType) + { + throw new Exception("Type is invalid."); + } + + lock (_memories) + { + _addMemoryCount += count; + while (count-- > 0) + { + _memories.Enqueue(new T()); + } + } + } + + public void Add(int count) + { + lock (_memories) + { + _addMemoryCount += count; + while (count-- > 0) + { + _memories.Enqueue((IMemory)Activator.CreateInstance(_memoryType)); + } + } + } + + public void Remove(int count) + { + lock (_memories) + { + if (count > _memories.Count) + { + count = _memories.Count; + } + + _removeMemoryCount += count; + while (count-- > 0) + { + _memories.Dequeue(); + } + } + } + + public void RemoveAll() + { + lock (_memories) + { + _removeMemoryCount += _memories.Count; + _memories.Clear(); + } + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs.meta new file mode 100644 index 00000000..3cab765f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.MemoryCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e4ec5f33991c55f41bceefbdb8089ae2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.cs b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.cs new file mode 100644 index 00000000..a6c5204a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 内存池。 + /// + public static partial class MemoryPool + { + private static readonly Dictionary _memoryCollections = new Dictionary(); + private static bool _enableStrictCheck = false; + + /// + /// 获取或设置是否开启强制检查。 + /// + public static bool EnableStrictCheck + { + get => _enableStrictCheck; + set => _enableStrictCheck = value; + } + + /// + /// 获取内存池的数量。 + /// + // ReSharper disable once InconsistentlySynchronizedField + public static int Count => _memoryCollections.Count; + + /// + /// 获取所有内存池的信息。 + /// + /// 所有内存池的信息。 + public static MemoryPoolInfo[] GetAllMemoryPoolInfos() + { + int index = 0; + MemoryPoolInfo[] results = null; + + lock (_memoryCollections) + { + results = new MemoryPoolInfo[_memoryCollections.Count]; + foreach (KeyValuePair memoryCollection in _memoryCollections) + { + results[index++] = new MemoryPoolInfo(memoryCollection.Key, memoryCollection.Value.UnusedMemoryCount, memoryCollection.Value.UsingMemoryCount, memoryCollection.Value.AcquireMemoryCount, memoryCollection.Value.ReleaseMemoryCount, memoryCollection.Value.AddMemoryCount, memoryCollection.Value.RemoveMemoryCount); + } + } + + return results; + } + + /// + /// 清除所有内存池。 + /// + public static void ClearAll() + { + lock (_memoryCollections) + { + foreach (KeyValuePair memoryCollection in _memoryCollections) + { + memoryCollection.Value.RemoveAll(); + } + + _memoryCollections.Clear(); + } + } + + /// + /// 从内存池获取内存对象。 + /// + /// 内存对象类型。 + /// 内存对象。 + public static T Acquire() where T : class, IMemory, new() + { + return GetMemoryCollection(typeof(T)).Acquire(); + } + + /// + /// 从内存池获取内存对象。 + /// + /// 内存对象类型。 + /// 内存对象。 + public static IMemory Acquire(Type memoryType) + { + InternalCheckMemoryType(memoryType); + return GetMemoryCollection(memoryType).Acquire(); + } + + /// + /// 将内存对象归还内存池。 + /// + /// 内存对象。 + public static void Release(IMemory memory) + { + if (memory == null) + { + throw new Exception("Memory is invalid."); + } + + Type memoryType = memory.GetType(); + InternalCheckMemoryType(memoryType); + GetMemoryCollection(memoryType).Release(memory); + } + + /// + /// 向内存池中追加指定数量的内存对象。 + /// + /// 内存对象类型。 + /// 追加数量。 + public static void Add(int count) where T : class, IMemory, new() + { + GetMemoryCollection(typeof(T)).Add(count); + } + + /// + /// 向内存池中追加指定数量的内存对象。 + /// + /// 内存对象类型。 + /// 追加数量。 + public static void Add(Type memoryType, int count) + { + InternalCheckMemoryType(memoryType); + GetMemoryCollection(memoryType).Add(count); + } + + /// + /// 从内存池中移除指定数量的内存对象。 + /// + /// 内存对象类型。 + /// 移除数量。 + public static void Remove(int count) where T : class, IMemory + { + GetMemoryCollection(typeof(T)).Remove(count); + } + + /// + /// 从内存池中移除指定数量的内存对象。 + /// + /// 内存对象类型。 + /// 移除数量。 + public static void Remove(Type memoryType, int count) + { + InternalCheckMemoryType(memoryType); + GetMemoryCollection(memoryType).Remove(count); + } + + /// + /// 从内存池中移除所有的内存对象。 + /// + /// 内存对象类型。 + public static void RemoveAll() where T : class, IMemory + { + GetMemoryCollection(typeof(T)).RemoveAll(); + } + + /// + /// 从内存池中移除所有的内存对象。 + /// + /// 内存对象类型。 + public static void RemoveAll(Type memoryType) + { + InternalCheckMemoryType(memoryType); + GetMemoryCollection(memoryType).RemoveAll(); + } + + private static void InternalCheckMemoryType(Type memoryType) + { + if (!_enableStrictCheck) + { + return; + } + + if (memoryType == null) + { + throw new Exception("Memory type is invalid."); + } + + if (!memoryType.IsClass || memoryType.IsAbstract) + { + throw new Exception("Memory type is not a non-abstract class type."); + } + + if (!typeof(IMemory).IsAssignableFrom(memoryType)) + { + throw new Exception(string.Format("Memory type '{0}' is invalid.", memoryType.FullName)); + } + } + + private static MemoryCollection GetMemoryCollection(Type memoryType) + { + if (memoryType == null) + { + throw new Exception("MemoryType is invalid."); + } + + MemoryCollection memoryCollection = null; + lock (_memoryCollections) + { + if (!_memoryCollections.TryGetValue(memoryType, out memoryCollection)) + { + memoryCollection = new MemoryCollection(memoryType); + _memoryCollections.Add(memoryType, memoryCollection); + } + } + + return memoryCollection; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.cs.meta new file mode 100644 index 00000000..422a9106 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f253bd3093bf78d45ad11b73c134e9ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolExtension.cs b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolExtension.cs new file mode 100644 index 00000000..18619890 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolExtension.cs @@ -0,0 +1,57 @@ +using System; + +namespace TEngine +{ + /// + /// 内存池对象基类。 + /// + public abstract class MemoryObject : IMemory + { + /// + /// 清理内存对象回收入池。 + /// + public virtual void Clear() + { + } + + /// + /// 从内存池中初始化。 + /// + public abstract void InitFromPool(); + + /// + /// 回收到内存池。 + /// + public abstract void RecycleToPool(); + } + + public static partial class MemoryPool + { + /// + /// 从内存池获取内存对象。 + /// + /// 内存对象类型。 + /// 内存对象。 + public static T Alloc() where T : MemoryObject, new() + { + T memory = Acquire(); + memory.InitFromPool(); + return memory; + } + + /// + /// 将内存对象归还内存池。 + /// + /// 内存对象。 + public static void Dealloc(MemoryObject memory) + { + if (memory == null) + { + throw new Exception("Memory is invalid."); + } + + memory.RecycleToPool(); + Release(memory); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolExtension.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolExtension.cs.meta new file mode 100644 index 00000000..2d4491f4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolExtension.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ad13ef73c22340058c4420733a22b580 +timeCreated: 1701273442 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolInfo.cs b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolInfo.cs new file mode 100644 index 00000000..4eda20ec --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolInfo.cs @@ -0,0 +1,118 @@ +using System; +using System.Runtime.InteropServices; + +namespace TEngine +{ + /// + /// 内存池信息。 + /// + [StructLayout(LayoutKind.Auto)] + public struct MemoryPoolInfo + { + private readonly Type _type; + private readonly int _unusedMemoryCount; + private readonly int _usingMemoryCount; + private readonly int _acquireMemoryCount; + private readonly int _releaseMemoryCount; + private readonly int _addMemoryCount; + private readonly int _removeMemoryCount; + + /// + /// 初始化内存池信息的新实例。 + /// + /// 内存池类型。 + /// 未使用内存对象数量。 + /// 正在使用内存对象数量。 + /// 获取内存对象数量。 + /// 归还内存对象数量。 + /// 增加内存对象数量。 + /// 移除内存对象数量。 + public MemoryPoolInfo(Type type, int unusedMemoryCount, int usingMemoryCount, int acquireMemoryCount, int releaseMemoryCount, int addMemoryCount, int removeMemoryCount) + { + _type = type; + _unusedMemoryCount = unusedMemoryCount; + _usingMemoryCount = usingMemoryCount; + _acquireMemoryCount = acquireMemoryCount; + _releaseMemoryCount = releaseMemoryCount; + _addMemoryCount = addMemoryCount; + _removeMemoryCount = removeMemoryCount; + } + + /// + /// 获取内存池类型。 + /// + public Type Type + { + get + { + return _type; + } + } + + /// + /// 获取未使用内存对象数量。 + /// + public int UnusedMemoryCount + { + get + { + return _unusedMemoryCount; + } + } + + /// + /// 获取正在使用内存对象数量。 + /// + public int UsingMemoryCount + { + get + { + return _usingMemoryCount; + } + } + + /// + /// 获取获取内存对象数量。 + /// + public int AcquireMemoryCount + { + get + { + return _acquireMemoryCount; + } + } + + /// + /// 获取归还内存对象数量。 + /// + public int ReleaseMemoryCount + { + get + { + return _releaseMemoryCount; + } + } + + /// + /// 获取增加内存对象数量。 + /// + public int AddMemoryCount + { + get + { + return _addMemoryCount; + } + } + + /// + /// 获取移除内存对象数量。 + /// + public int RemoveMemoryCount + { + get + { + return _removeMemoryCount; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolInfo.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolInfo.cs.meta new file mode 100644 index 00000000..f91a6b4b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 444aa83c59c8f0445894e785975b5463 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolModule.cs b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolModule.cs new file mode 100644 index 00000000..5fff75c9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolModule.cs @@ -0,0 +1,77 @@ +using UnityEngine; + +namespace TEngine +{ + /// + /// 内存强制检查类型。 + /// + public enum MemoryStrictCheckType : byte + { + /// + /// 总是启用。 + /// + AlwaysEnable = 0, + + /// + /// 仅在开发模式时启用。 + /// + OnlyEnableWhenDevelopment, + + /// + /// 仅在编辑器中启用。 + /// + OnlyEnableInEditor, + + /// + /// 总是禁用。 + /// + AlwaysDisable, + } + + /// + /// 内存池模块。 + /// + [DisallowMultipleComponent] + public sealed class MemoryPoolModule : Module + { + [SerializeField] private MemoryStrictCheckType m_EnableStrictCheck = MemoryStrictCheckType.AlwaysEnable; + + /// + /// 获取或设置是否开启强制检查。 + /// + public bool EnableStrictCheck + { + get => MemoryPool.EnableStrictCheck; + set + { + MemoryPool.EnableStrictCheck = value; + if (value) + { + Log.Info("Strict checking is enabled for the Memory Pool. It will drastically affect the performance."); + } + } + } + + private void Start() + { + switch (m_EnableStrictCheck) + { + case MemoryStrictCheckType.AlwaysEnable: + EnableStrictCheck = true; + break; + + case MemoryStrictCheckType.OnlyEnableWhenDevelopment: + EnableStrictCheck = Debug.isDebugBuild; + break; + + case MemoryStrictCheckType.OnlyEnableInEditor: + EnableStrictCheck = Application.isEditor; + break; + + default: + EnableStrictCheck = false; + break; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolModule.cs.meta new file mode 100644 index 00000000..dd7ae564 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/MemoryPool/MemoryPoolModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61474d279eb27214d9178822796f3b88 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Profiler.meta b/EintooAR/Assets/TEngine/Runtime/Core/Profiler.meta new file mode 100644 index 00000000..1208b606 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Profiler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3dae26f360146b240a1d999a58e65a7b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Profiler/TProfiler.cs b/EintooAR/Assets/TEngine/Runtime/Core/Profiler/TProfiler.cs new file mode 100644 index 00000000..005601cc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Profiler/TProfiler.cs @@ -0,0 +1,88 @@ +using System.Diagnostics; +using UnityEngine.Profiling; + +namespace TEngine +{ + /// + /// 游戏框架Profiler分析器类。 + /// + public class TProfiler + { + private static int _profileLevel = -1; + private static int _currLevel = 0; + private static int _sampleLevel = 0; + + /// + /// 设置分析器等级。 + /// + /// 调试器等级。 + public static void SetProfileLevel(int level) + { + _profileLevel = level; + } + + /// + /// 开始使用自定义采样分析一段代码。 + /// + /// 用于在Profiler窗口中标识样本的字符串。 + [Conditional("FIRST_PROFILER")] + public static void BeginFirstSample(string name) + { + _currLevel++; + if (_profileLevel >= 0 && _currLevel > _profileLevel) + { + return; + } + + _sampleLevel++; + Profiler.BeginSample(name); + } + + /// + /// 结束本次自定义采样分析。 + /// + [Conditional("FIRST_PROFILER")] + public static void EndFirstSample() + { + if (_currLevel <= _sampleLevel) + { + Profiler.EndSample(); + _sampleLevel--; + } + + _currLevel--; + } + + /// + /// 开始使用自定义采样分析一段代码。 + /// + /// 用于在Profiler窗口中标识样本的字符串。 + [Conditional("T_PROFILER")] + public static void BeginSample(string name) + { + _currLevel++; + if (_profileLevel >= 0 && _currLevel > _profileLevel) + { + return; + } + + _sampleLevel++; + Profiler.BeginSample(name); + } + + /// + /// 结束本次自定义采样分析。 + /// + [Conditional("T_PROFILER")] + public static void EndSample() + { + if (_currLevel <= _sampleLevel) + { + Profiler.EndSample(); + _sampleLevel--; + } + + _currLevel--; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Profiler/TProfiler.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Profiler/TProfiler.cs.meta new file mode 100644 index 00000000..def6af17 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Profiler/TProfiler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c443b02a74962b049b6a0089e4bae977 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility.meta new file mode 100644 index 00000000..d45c2ef6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e4d3608b6f0243458edec3a2c27b541 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper.meta new file mode 100644 index 00000000..ccc45d3d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a4ecf1e10007411b84fe04317325b608 +timeCreated: 1694791135 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultJsonHelper.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultJsonHelper.cs new file mode 100644 index 00000000..3f7bc811 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultJsonHelper.cs @@ -0,0 +1,40 @@ +namespace TEngine +{ + /// + /// 默认 JSON 函数集辅助器。 + /// + public class DefaultJsonHelper : Utility.Json.IJsonHelper + { + /// + /// 将对象序列化为 JSON 字符串。 + /// + /// 要序列化的对象。 + /// 序列化后的 JSON 字符串。 + public string ToJson(object obj) + { + return Newtonsoft.Json.JsonConvert.SerializeObject(obj); + } + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public T ToObject(string json) + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(json); + } + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public object ToObject(System.Type objectType, string json) + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(json, objectType); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultJsonHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultJsonHelper.cs.meta new file mode 100644 index 00000000..af5fe173 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultJsonHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d3f060a2b0994a2ca03656a24d296f19 +timeCreated: 1694791167 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultLogHelper.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultLogHelper.cs new file mode 100644 index 00000000..9d95549b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultLogHelper.cs @@ -0,0 +1,166 @@ +using System; +using System.Diagnostics; +using System.Text; +using Debug = UnityEngine.Debug; + +namespace TEngine +{ + /// + /// 默认游戏框架日志辅助。 + /// + public class DefaultLogHelper : GameFrameworkLog.ILogHelper + { + private enum ELogLevel + { + Info, + Debug, + Assert, + Warning, + Error, + Exception, + } + + private const ELogLevel FilterLevel = ELogLevel.Info; + private static readonly StringBuilder _stringBuilder = new StringBuilder(1024); + + /// + /// 打印游戏日志。 + /// + /// 游戏框架日志等级。 + /// 日志信息。 + /// 游戏框架异常类。 + public void Log(GameFrameworkLogLevel level, object message) + { + switch (level) + { + case GameFrameworkLogLevel.Debug: + LogImp(ELogLevel.Debug, Utility.Text.Format("{0}", message)); + break; + + case GameFrameworkLogLevel.Info: + LogImp(ELogLevel.Info, message.ToString()); + break; + + case GameFrameworkLogLevel.Warning: + LogImp(ELogLevel.Warning, message.ToString()); + break; + + case GameFrameworkLogLevel.Error: + LogImp(ELogLevel.Error, message.ToString()); + break; + + case GameFrameworkLogLevel.Fatal: + LogImp(ELogLevel.Exception, message.ToString()); + break; + + default: + throw new GameFrameworkException(message.ToString()); + } + } + + /// + /// 获取日志格式。 + /// + /// 日志级别。 + /// 日志字符。 + /// 是否使用颜色。 + /// StringBuilder。 + private static StringBuilder GetFormatString(ELogLevel eLogLevel, string logString, bool bColor) + { + _stringBuilder.Clear(); + switch (eLogLevel) + { + case ELogLevel.Debug: + _stringBuilder.AppendFormat( + bColor + ? "[Debug] ► - {0}" + : "[Debug] ► - {0}", + logString); + break; + case ELogLevel.Info: + _stringBuilder.AppendFormat( + bColor + ? "[INFO] ► - {0}" + : "[INFO] ► - {0}", + logString); + break; + case ELogLevel.Assert: + _stringBuilder.AppendFormat( + bColor + ? "[ASSERT] ► - {0}" + : "[ASSERT] ► - {0}", + logString); + break; + case ELogLevel.Warning: + _stringBuilder.AppendFormat( + bColor + ? "[WARNING] ► - {0}" + : "[WARNING] ► - {0}", + logString); + break; + case ELogLevel.Error: + _stringBuilder.AppendFormat( + bColor + ? "[ERROR] ► - {0}" + : "[ERROR] ► - {0}", + logString); + break; + case ELogLevel.Exception: + _stringBuilder.AppendFormat( + bColor + ? "[EXCEPTION] ► - {0}" + : "[EXCEPTION] ► - {0}", + logString); + break; + } + + return _stringBuilder; + } + + private static void LogImp(ELogLevel type, string logString) + { + if (type < FilterLevel) + { + return; + } + + StringBuilder infoBuilder = GetFormatString(type, logString, true); + string logStr = infoBuilder.ToString(); + + //获取C#堆栈,Warning以上级别日志才获取堆栈 + if (type == ELogLevel.Error || type == ELogLevel.Warning || type == ELogLevel.Exception) + { + StackFrame[] stackFrames = new StackTrace().GetFrames(); + // ReSharper disable once PossibleNullReferenceException + for (int i = 0; i < stackFrames.Length; i++) + { + StackFrame frame = stackFrames[i]; + // ReSharper disable once PossibleNullReferenceException + string declaringTypeName = frame.GetMethod().DeclaringType.FullName; + string methodName = stackFrames[i].GetMethod().Name; + + infoBuilder.AppendFormat("[{0}::{1}\n", declaringTypeName, methodName); + } + } + + switch (type) + { + case ELogLevel.Info: + case ELogLevel.Debug: + Debug.Log(logStr); + break; + case ELogLevel.Warning: + Debug.LogWarning(logStr); + break; + case ELogLevel.Assert: + Debug.LogAssertion(logStr); + break; + case ELogLevel.Error: + Debug.LogError(logStr); + break; + case ELogLevel.Exception: + throw new Exception(logStr); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultLogHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultLogHelper.cs.meta new file mode 100644 index 00000000..d412e252 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultLogHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d1c8c8d1b08988469817ae1e309cc37 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultTextHelper.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultTextHelper.cs new file mode 100644 index 00000000..5866f453 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultTextHelper.cs @@ -0,0 +1,584 @@ +using System; +using System.Text; + +namespace TEngine +{ + /// + /// 默认字符辅助器。 + /// + public class DefaultTextHelper : Utility.Text.ITextHelper + { + private const int StringBuilderCapacity = 1024; + + [ThreadStatic] + private static StringBuilder s_CachedStringBuilder = null; + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数的类型。 + /// 字符串格式。 + /// 字符串参数。 + /// 格式化后的字符串。 + public string Format(string format, T arg) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串参数 14 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 字符串参数 14。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串参数 14 的类型。 + /// 字符串参数 15 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 字符串参数 14。 + /// 字符串参数 15。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); + return s_CachedStringBuilder.ToString(); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串参数 14 的类型。 + /// 字符串参数 15 的类型。 + /// 字符串参数 16 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 字符串参数 14。 + /// 字符串参数 15。 + /// 字符串参数 16。 + /// 格式化后的字符串。 + public string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + CheckCachedStringBuilder(); + s_CachedStringBuilder.Length = 0; + s_CachedStringBuilder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + return s_CachedStringBuilder.ToString(); + } + + private static void CheckCachedStringBuilder() + { + if (s_CachedStringBuilder == null) + { + s_CachedStringBuilder = new StringBuilder(StringBuilderCapacity); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultTextHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultTextHelper.cs.meta new file mode 100644 index 00000000..c04a4e0c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultTextHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 05aa28bc5bdc428cb7fb97c1ad52e49d +timeCreated: 1694845147 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultVersionHelper.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultVersionHelper.cs new file mode 100644 index 00000000..f987220f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultVersionHelper.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +namespace TEngine +{ + /// + /// 默认版本号辅助器。 + /// + public class DefaultVersionHelper : Version.IVersionHelper + { + /// + /// 获取游戏版本号。 + /// + public string GameVersion => Application.version; + + /// + /// 获取内部游戏版本号。 + /// + public string InternalGameVersion => string.Empty; + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultVersionHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultVersionHelper.cs.meta new file mode 100644 index 00000000..4bd6e0f9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/DefaultVersionHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 88b85088957e4a548f38a7d23ff53c7a +timeCreated: 1694845147 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/UnityJsonHelper.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/UnityJsonHelper.cs new file mode 100644 index 00000000..65be6ba9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/UnityJsonHelper.cs @@ -0,0 +1,43 @@ +using System; +using UnityEngine; + +namespace TEngine +{ + /// + /// 默认 JSON 函数集辅助器。 + /// + public class UnityJsonHelper : Utility.Json.IJsonHelper + { + /// + /// 将对象序列化为 JSON 字符串。 + /// + /// 要序列化的对象。 + /// 序列化后的 JSON 字符串。 + public string ToJson(object obj) + { + return JsonUtility.ToJson(obj); + } + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public T ToObject(string json) + { + return JsonUtility.FromJson(json); + } + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public object ToObject(Type objectType, string json) + { + return JsonUtility.FromJson(json, objectType); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/UnityJsonHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/UnityJsonHelper.cs.meta new file mode 100644 index 00000000..23e2640c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/DefaultHelper/UnityJsonHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9d4cb332a5024ccab3c206ff0f5ba284 +timeCreated: 1694791167 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Assembly.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Assembly.cs new file mode 100644 index 00000000..4aed2c7b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Assembly.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 程序集相关的实用函数。 + /// + public static class Assembly + { + private static readonly System.Reflection.Assembly[] _assemblies = null; + private static readonly Dictionary _cachedTypes = new Dictionary(StringComparer.Ordinal); + + static Assembly() + { + _assemblies = AppDomain.CurrentDomain.GetAssemblies(); + } + + /// + /// 获取已加载的程序集。 + /// + /// 已加载的程序集。 + public static System.Reflection.Assembly[] GetAssemblies() + { + return _assemblies; + } + + /// + /// 获取已加载的程序集中的所有类型。 + /// + /// 已加载的程序集中的所有类型。 + public static Type[] GetTypes() + { + List results = new List(); + foreach (System.Reflection.Assembly assembly in _assemblies) + { + results.AddRange(assembly.GetTypes()); + } + + return results.ToArray(); + } + + /// + /// 获取已加载的程序集中的所有类型。 + /// + /// 已加载的程序集中的所有类型。 + public static void GetTypes(List results) + { + if (results == null) + { + throw new GameFrameworkException("Results is invalid."); + } + + results.Clear(); + foreach (System.Reflection.Assembly assembly in _assemblies) + { + results.AddRange(assembly.GetTypes()); + } + } + + /// + /// 获取已加载的程序集中的指定类型。 + /// + /// 要获取的类型名。 + /// 已加载的程序集中的指定类型。 + public static Type GetType(string typeName) + { + if (string.IsNullOrEmpty(typeName)) + { + throw new GameFrameworkException("Type name is invalid."); + } + + Type type = null; + if (_cachedTypes.TryGetValue(typeName, out type)) + { + return type; + } + + type = Type.GetType(typeName); + if (type != null) + { + _cachedTypes.Add(typeName, type); + return type; + } + + foreach (System.Reflection.Assembly assembly in _assemblies) + { + type = Type.GetType(Text.Format("{0}, {1}", typeName, assembly.FullName)); + if (type != null) + { + _cachedTypes.Add(typeName, type); + return type; + } + } + + return null; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Assembly.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Assembly.cs.meta new file mode 100644 index 00000000..d0eb7856 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Assembly.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a52873b2498491c91be2c1dd048b403 +timeCreated: 1694791388 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Converter.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Converter.cs new file mode 100644 index 00000000..57c864fb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Converter.cs @@ -0,0 +1,835 @@ +using System; +using System.Text; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 类型转换相关的实用函数。 + /// + public static class Converter + { + private const float InchesToCentimeters = 2.54f; // 1 inch = 2.54 cm + private const float CentimetersToInches = 1f / InchesToCentimeters; // 1 cm = 0.3937 inches + + /// + /// 获取数据在此计算机结构中存储时的字节顺序。 + /// + public static bool IsLittleEndian => BitConverter.IsLittleEndian; + + /// + /// 获取或设置屏幕每英寸点数。 + /// + public static float ScreenDpi + { + get; + set; + } + + /// + /// 将像素转换为厘米。 + /// + /// 像素。 + /// 厘米。 + public static float GetCentimetersFromPixels(float pixels) + { + if (ScreenDpi <= 0) + { + throw new GameFrameworkException("You must set screen DPI first."); + } + + return InchesToCentimeters * pixels / ScreenDpi; + } + + /// + /// 将厘米转换为像素。 + /// + /// 厘米。 + /// 像素。 + public static float GetPixelsFromCentimeters(float centimeters) + { + if (ScreenDpi <= 0) + { + throw new GameFrameworkException("You must set screen DPI first."); + } + + return CentimetersToInches * centimeters * ScreenDpi; + } + + /// + /// 将像素转换为英寸。 + /// + /// 像素。 + /// 英寸。 + public static float GetInchesFromPixels(float pixels) + { + if (ScreenDpi <= 0) + { + throw new GameFrameworkException("You must set screen DPI first."); + } + + return pixels / ScreenDpi; + } + + /// + /// 将英寸转换为像素。 + /// + /// 英寸。 + /// 像素。 + public static float GetPixelsFromInches(float inches) + { + if (ScreenDpi <= 0) + { + throw new GameFrameworkException("You must set screen DPI first."); + } + + return inches * ScreenDpi; + } + + /// + /// 以字节数组的形式获取指定的布尔值。 + /// + /// 要转换的布尔值。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(bool value) + { + byte[] buffer = new byte[1]; + GetBytes(value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的布尔值。 + /// + /// 要转换的布尔值。 + /// 用于存放结果的字节数组。 + public static void GetBytes(bool value, byte[] buffer) + { + GetBytes(value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的布尔值。 + /// + /// 要转换的布尔值。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(bool value, byte[] buffer, int startIndex) + { + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0 || startIndex + 1 > buffer.Length) + { + throw new GameFrameworkException("Start index is invalid."); + } + + buffer[startIndex] = value ? (byte)1 : (byte)0; + } + + /// + /// 返回由字节数组中首字节转换来的布尔值。 + /// + /// 字节数组。 + /// 如果 value 中的首字节非零,则为 true,否则为 false。 + public static bool GetBoolean(byte[] value) + { + return BitConverter.ToBoolean(value, 0); + } + + /// + /// 返回由字节数组中指定位置的一个字节转换来的布尔值。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 如果 value 中指定位置的字节非零,则为 true,否则为 false。 + public static bool GetBoolean(byte[] value, int startIndex) + { + return BitConverter.ToBoolean(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 Unicode 字符值。 + /// + /// 要转换的字符。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(char value) + { + byte[] buffer = new byte[2]; + GetBytes((short)value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 Unicode 字符值。 + /// + /// 要转换的字符。 + /// 用于存放结果的字节数组。 + public static void GetBytes(char value, byte[] buffer) + { + GetBytes((short)value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 Unicode 字符值。 + /// + /// 要转换的字符。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(char value, byte[] buffer, int startIndex) + { + GetBytes((short)value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前两个字节转换来的 Unicode 字符。 + /// + /// 字节数组。 + /// 由两个字节构成的字符。 + public static char GetChar(byte[] value) + { + return BitConverter.ToChar(value, 0); + } + + /// + /// 返回由字节数组中指定位置的两个字节转换来的 Unicode 字符。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由两个字节构成的字符。 + public static char GetChar(byte[] value, int startIndex) + { + return BitConverter.ToChar(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 16 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(short value) + { + byte[] buffer = new byte[2]; + GetBytes(value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 16 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(short value, byte[] buffer) + { + GetBytes(value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 16 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(short value, byte[] buffer, int startIndex) + { + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0 || startIndex + 2 > buffer.Length) + { + throw new GameFrameworkException("Start index is invalid."); + } + + fixed (byte* valueRef = buffer) + { + *(short*)(valueRef + startIndex) = value; + } + } + + /// + /// 返回由字节数组中前两个字节转换来的 16 位有符号整数。 + /// + /// 字节数组。 + /// 由两个字节构成的 16 位有符号整数。 + public static short GetInt16(byte[] value) + { + return BitConverter.ToInt16(value, 0); + } + + /// + /// 返回由字节数组中指定位置的两个字节转换来的 16 位有符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由两个字节构成的 16 位有符号整数。 + public static short GetInt16(byte[] value, int startIndex) + { + return BitConverter.ToInt16(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 16 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(ushort value) + { + byte[] buffer = new byte[2]; + GetBytes((short)value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 16 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(ushort value, byte[] buffer) + { + GetBytes((short)value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 16 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(ushort value, byte[] buffer, int startIndex) + { + GetBytes((short)value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前两个字节转换来的 16 位无符号整数。 + /// + /// 字节数组。 + /// 由两个字节构成的 16 位无符号整数。 + public static ushort GetUInt16(byte[] value) + { + return BitConverter.ToUInt16(value, 0); + } + + /// + /// 返回由字节数组中指定位置的两个字节转换来的 16 位无符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由两个字节构成的 16 位无符号整数。 + public static ushort GetUInt16(byte[] value, int startIndex) + { + return BitConverter.ToUInt16(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 32 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(int value) + { + byte[] buffer = new byte[4]; + GetBytes(value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 32 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(int value, byte[] buffer) + { + GetBytes(value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 32 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(int value, byte[] buffer, int startIndex) + { + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0 || startIndex + 4 > buffer.Length) + { + throw new GameFrameworkException("Start index is invalid."); + } + + fixed (byte* valueRef = buffer) + { + *(int*)(valueRef + startIndex) = value; + } + } + + /// + /// 返回由字节数组中前四个字节转换来的 32 位有符号整数。 + /// + /// 字节数组。 + /// 由四个字节构成的 32 位有符号整数。 + public static int GetInt32(byte[] value) + { + return BitConverter.ToInt32(value, 0); + } + + /// + /// 返回由字节数组中指定位置的四个字节转换来的 32 位有符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由四个字节构成的 32 位有符号整数。 + public static int GetInt32(byte[] value, int startIndex) + { + return BitConverter.ToInt32(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 32 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(uint value) + { + byte[] buffer = new byte[4]; + GetBytes((int)value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 32 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(uint value, byte[] buffer) + { + GetBytes((int)value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 32 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(uint value, byte[] buffer, int startIndex) + { + GetBytes((int)value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前四个字节转换来的 32 位无符号整数。 + /// + /// 字节数组。 + /// 由四个字节构成的 32 位无符号整数。 + public static uint GetUInt32(byte[] value) + { + return BitConverter.ToUInt32(value, 0); + } + + /// + /// 返回由字节数组中指定位置的四个字节转换来的 32 位无符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由四个字节构成的 32 位无符号整数。 + public static uint GetUInt32(byte[] value, int startIndex) + { + return BitConverter.ToUInt32(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 64 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(long value) + { + byte[] buffer = new byte[8]; + GetBytes(value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 64 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(long value, byte[] buffer) + { + GetBytes(value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 64 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(long value, byte[] buffer, int startIndex) + { + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0 || startIndex + 8 > buffer.Length) + { + throw new GameFrameworkException("Start index is invalid."); + } + + fixed (byte* valueRef = buffer) + { + *(long*)(valueRef + startIndex) = value; + } + } + + /// + /// 返回由字节数组中前八个字节转换来的 64 位有符号整数。 + /// + /// 字节数组。 + /// 由八个字节构成的 64 位有符号整数。 + public static long GetInt64(byte[] value) + { + return BitConverter.ToInt64(value, 0); + } + + /// + /// 返回由字节数组中指定位置的八个字节转换来的 64 位有符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由八个字节构成的 64 位有符号整数。 + public static long GetInt64(byte[] value, int startIndex) + { + return BitConverter.ToInt64(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 64 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(ulong value) + { + byte[] buffer = new byte[8]; + GetBytes((long)value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 64 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(ulong value, byte[] buffer) + { + GetBytes((long)value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 64 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(ulong value, byte[] buffer, int startIndex) + { + GetBytes((long)value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前八个字节转换来的 64 位无符号整数。 + /// + /// 字节数组。 + /// 由八个字节构成的 64 位无符号整数。 + public static ulong GetUInt64(byte[] value) + { + return BitConverter.ToUInt64(value, 0); + } + + /// + /// 返回由字节数组中指定位置的八个字节转换来的 64 位无符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由八个字节构成的 64 位无符号整数。 + public static ulong GetUInt64(byte[] value, int startIndex) + { + return BitConverter.ToUInt64(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的单精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static unsafe byte[] GetBytes(float value) + { + byte[] buffer = new byte[4]; + GetBytes(*(int*)&value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的单精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static unsafe void GetBytes(float value, byte[] buffer) + { + GetBytes(*(int*)&value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的单精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(float value, byte[] buffer, int startIndex) + { + GetBytes(*(int*)&value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前四个字节转换来的单精度浮点数。 + /// + /// 字节数组。 + /// 由四个字节构成的单精度浮点数。 + public static float GetSingle(byte[] value) + { + return BitConverter.ToSingle(value, 0); + } + + /// + /// 返回由字节数组中指定位置的四个字节转换来的单精度浮点数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由四个字节构成的单精度浮点数。 + public static float GetSingle(byte[] value, int startIndex) + { + return BitConverter.ToSingle(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的双精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static unsafe byte[] GetBytes(double value) + { + byte[] buffer = new byte[8]; + GetBytes(*(long*)&value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的双精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static unsafe void GetBytes(double value, byte[] buffer) + { + GetBytes(*(long*)&value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的双精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(double value, byte[] buffer, int startIndex) + { + GetBytes(*(long*)&value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前八个字节转换来的双精度浮点数。 + /// + /// 字节数组。 + /// 由八个字节构成的双精度浮点数。 + public static double GetDouble(byte[] value) + { + return BitConverter.ToDouble(value, 0); + } + + /// + /// 返回由字节数组中指定位置的八个字节转换来的双精度浮点数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由八个字节构成的双精度浮点数。 + public static double GetDouble(byte[] value, int startIndex) + { + return BitConverter.ToDouble(value, startIndex); + } + + /// + /// 以字节数组的形式获取 UTF-8 编码的字符串。 + /// + /// 要转换的字符串。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(string value) + { + return GetBytes(value, Encoding.UTF8); + } + + /// + /// 以字节数组的形式获取 UTF-8 编码的字符串。 + /// + /// 要转换的字符串。 + /// 用于存放结果的字节数组。 + /// buffer 内实际填充了多少字节。 + public static int GetBytes(string value, byte[] buffer) + { + return GetBytes(value, Encoding.UTF8, buffer, 0); + } + + /// + /// 以字节数组的形式获取 UTF-8 编码的字符串。 + /// + /// 要转换的字符串。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + /// buffer 内实际填充了多少字节。 + public static int GetBytes(string value, byte[] buffer, int startIndex) + { + return GetBytes(value, Encoding.UTF8, buffer, startIndex); + } + + /// + /// 以字节数组的形式获取指定编码的字符串。 + /// + /// 要转换的字符串。 + /// 要使用的编码。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(string value, Encoding encoding) + { + if (value == null) + { + throw new GameFrameworkException("Value is invalid."); + } + + if (encoding == null) + { + throw new GameFrameworkException("Encoding is invalid."); + } + + return encoding.GetBytes(value); + } + + /// + /// 以字节数组的形式获取指定编码的字符串。 + /// + /// 要转换的字符串。 + /// 要使用的编码。 + /// 用于存放结果的字节数组。 + /// buffer 内实际填充了多少字节。 + public static int GetBytes(string value, Encoding encoding, byte[] buffer) + { + return GetBytes(value, encoding, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定编码的字符串。 + /// + /// 要转换的字符串。 + /// 要使用的编码。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + /// buffer 内实际填充了多少字节。 + public static int GetBytes(string value, Encoding encoding, byte[] buffer, int startIndex) + { + if (value == null) + { + throw new GameFrameworkException("Value is invalid."); + } + + if (encoding == null) + { + throw new GameFrameworkException("Encoding is invalid."); + } + + return encoding.GetBytes(value, 0, value.Length, buffer, startIndex); + } + + /// + /// 返回由字节数组使用 UTF-8 编码转换成的字符串。 + /// + /// 字节数组。 + /// 转换后的字符串。 + public static string GetString(byte[] value) + { + return GetString(value, Encoding.UTF8); + } + + /// + /// 返回由字节数组使用指定编码转换成的字符串。 + /// + /// 字节数组。 + /// 要使用的编码。 + /// 转换后的字符串。 + public static string GetString(byte[] value, Encoding encoding) + { + if (value == null) + { + throw new GameFrameworkException("Value is invalid."); + } + + if (encoding == null) + { + throw new GameFrameworkException("Encoding is invalid."); + } + + return encoding.GetString(value); + } + + /// + /// 返回由字节数组使用 UTF-8 编码转换成的字符串。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 长度。 + /// 转换后的字符串。 + public static string GetString(byte[] value, int startIndex, int length) + { + return GetString(value, startIndex, length, Encoding.UTF8); + } + + /// + /// 返回由字节数组使用指定编码转换成的字符串。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 长度。 + /// 要使用的编码。 + /// 转换后的字符串。 + public static string GetString(byte[] value, int startIndex, int length, Encoding encoding) + { + if (value == null) + { + throw new GameFrameworkException("Value is invalid."); + } + + if (encoding == null) + { + throw new GameFrameworkException("Encoding is invalid."); + } + + return encoding.GetString(value, startIndex, length); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Converter.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Converter.cs.meta new file mode 100644 index 00000000..4b084009 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Converter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c72e4b760471471db54e091f978079c7 +timeCreated: 1694840353 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Encryption.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Encryption.cs new file mode 100644 index 00000000..5063057c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Encryption.cs @@ -0,0 +1,127 @@ +using System; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 加密解密相关的实用函数。 + /// + public static class Encryption + { + internal const int QuickEncryptLength = 220; + + /// + /// 将 bytes 使用 code 做异或运算的快速版本。 + /// + /// 原始二进制流。 + /// 异或二进制流。 + /// 异或后的二进制流。 + public static byte[] GetQuickXorBytes(byte[] bytes, byte[] code) + { + return GetXorBytes(bytes, 0, QuickEncryptLength, code); + } + + /// + /// 将 bytes 使用 code 做异或运算的快速版本。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。 + /// + /// 原始及异或后的二进制流。 + /// 异或二进制流。 + public static void GetQuickSelfXorBytes(byte[] bytes, byte[] code) + { + GetSelfXorBytes(bytes, 0, QuickEncryptLength, code); + } + + /// + /// 将 bytes 使用 code 做异或运算。 + /// + /// 原始二进制流。 + /// 异或二进制流。 + /// 异或后的二进制流。 + public static byte[] GetXorBytes(byte[] bytes, byte[] code) + { + if (bytes == null) + { + return null; + } + + return GetXorBytes(bytes, 0, bytes.Length, code); + } + + /// + /// 将 bytes 使用 code 做异或运算。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。 + /// + /// 原始及异或后的二进制流。 + /// 异或二进制流。 + public static void GetSelfXorBytes(byte[] bytes, byte[] code) + { + if (bytes == null) + { + return; + } + + GetSelfXorBytes(bytes, 0, bytes.Length, code); + } + + /// + /// 将 bytes 使用 code 做异或运算。 + /// + /// 原始二进制流。 + /// 异或计算的开始位置。 + /// 异或计算长度,若小于 0,则计算整个二进制流。 + /// 异或二进制流。 + /// 异或后的二进制流。 + public static byte[] GetXorBytes(byte[] bytes, int startIndex, int length, byte[] code) + { + if (bytes == null) + { + return null; + } + + int bytesLength = bytes.Length; + byte[] results = new byte[bytesLength]; + Array.Copy(bytes, 0, results, 0, bytesLength); + GetSelfXorBytes(results, startIndex, length, code); + return results; + } + + /// + /// 将 bytes 使用 code 做异或运算。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。 + /// + /// 原始及异或后的二进制流。 + /// 异或计算的开始位置。 + /// 异或计算长度。 + /// 异或二进制流。 + public static void GetSelfXorBytes(byte[] bytes, int startIndex, int length, byte[] code) + { + if (bytes == null) + { + return; + } + + if (code == null) + { + throw new GameFrameworkException("Code is invalid."); + } + + int codeLength = code.Length; + if (codeLength <= 0) + { + throw new GameFrameworkException("Code length is invalid."); + } + + if (startIndex < 0 || length < 0 || startIndex + length > bytes.Length) + { + throw new GameFrameworkException("Start index or length is invalid."); + } + + int codeIndex = startIndex % codeLength; + for (int i = startIndex; i < length; i++) + { + bytes[i] ^= code[codeIndex++]; + codeIndex %= codeLength; + } + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Encryption.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Encryption.cs.meta new file mode 100644 index 00000000..d4709aea --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Encryption.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5760733526714e7e82212e868bfd5bd1 +timeCreated: 1695116062 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.File.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.File.cs new file mode 100644 index 00000000..756d042a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.File.cs @@ -0,0 +1,234 @@ +using System; +using System.IO; +using System.Text; +#if UNITY_EDITOR +using UnityEditor; +#endif +using UnityEngine; + +namespace TEngine +{ + /// + /// Unity平台路径类型。 + /// + public enum UnityPlatformPathType : int + { + dataPath = 0, + streamingAssetsPath, + persistentDataPath, + temporaryCachePath, + } + + public static partial class Utility + { + /// + /// 文件相关的实用函数。 + /// + public static class File + { + public static bool CreateFile(string filePath, bool isCreateDir = true) + { + if (!System.IO.File.Exists(filePath)) + { + string dir = System.IO.Path.GetDirectoryName(filePath); + if (!Directory.Exists(dir)) + { + if (isCreateDir) + { + Directory.CreateDirectory(dir); + } + else + { + Log.Error("文件夹不存在 Path=" + dir); + return false; + } + } + + System.IO.File.Create(filePath); + } + + return true; + } + + public static bool CreateFile(string filePath, string info, bool isCreateDir = true) + { + StreamWriter sw; + FileInfo t = new FileInfo(filePath); + if (!t.Exists) + { + string dir = System.IO.Path.GetDirectoryName(filePath); + if (!Directory.Exists(dir)) + { + if (isCreateDir) + { + Directory.CreateDirectory(dir); + } + else + { +#if UNITY_EDITOR + EditorUtility.DisplayDialog("Tips", "文件夹不存在", "CANCEL"); +#endif + Log.Error("文件夹不存在 Path=" + dir); + return false; + } + } + + sw = t.CreateText(); + } + else + { + sw = t.AppendText(); + } + + sw.WriteLine(info); + sw.Close(); + sw.Dispose(); + return true; + } + + public static string GetPersistentDataPlatformPath(string filePath) + { + filePath = +#if UNITY_ANDROID && !UNITY_EDITOR + Application.dataPath + "!assets" + "/" + filePath; +#else + Application.streamingAssetsPath + "/" + filePath; +#endif + return filePath; + } + + public static string GetPath(string path) + { + return path.Replace("\\", "/"); + } + + public static string Md5ByPathName(string pathName) + { + try + { + FileStream file = new FileStream(pathName, FileMode.Open); + System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); + byte[] retVal = md5.ComputeHash(file); + file.Close(); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < retVal.Length; i++) + { + sb.Append(retVal[i].ToString("x2")); + } + + return sb.ToString(); + } + catch (Exception ex) + { + Log.Error("to md5 fail,error:" + ex.Message); + return "Error"; + } + } + + public static string GetLengthString(long length) + { + if (length < 1024) + { + return $"{length.ToString()} Bytes"; + } + + if (length < 1024 * 1024) + { + return $"{(length / 1024f):F2} KB"; + } + + return length < 1024 * 1024 * 1024 ? $"{(length / 1024f / 1024f):F2} MB" : $"{(length / 1024f / 1024f / 1024f):F2} GB"; + } + + public static string GetByteLengthString(long byteLength) + { + if (byteLength < 1024L) // 2 ^ 10 + { + return Utility.Text.Format("{0} Bytes", byteLength.ToString()); + } + + if (byteLength < 1048576L) // 2 ^ 20 + { + return Utility.Text.Format("{0} KB", (byteLength / 1024f).ToString("F2")); + } + + if (byteLength < 1073741824L) // 2 ^ 30 + { + return Utility.Text.Format("{0} MB", (byteLength / 1048576f).ToString("F2")); + } + + if (byteLength < 1099511627776L) // 2 ^ 40 + { + return Utility.Text.Format("{0} GB", (byteLength / 1073741824f).ToString("F2")); + } + + if (byteLength < 1125899906842624L) // 2 ^ 50 + { + return Utility.Text.Format("{0} TB", (byteLength / 1099511627776f).ToString("F2")); + } + + if (byteLength < 1152921504606846976L) // 2 ^ 60 + { + return Utility.Text.Format("{0} PB", (byteLength / 1125899906842624f).ToString("F2")); + } + + return Utility.Text.Format("{0} EB", (byteLength / 1152921504606846976f).ToString("F2")); + } + + public static string BinToUtf8(byte[] total) + { + byte[] result = total; + if (total[0] == 0xef && total[1] == 0xbb && total[2] == 0xbf) + { + // utf8文件的前三个字节为特殊占位符,要跳过 + result = new byte[total.Length - 3]; + System.Array.Copy(total, 3, result, 0, total.Length - 3); + } + + string utf8string = System.Text.Encoding.UTF8.GetString(result); + return utf8string; + } + + /// + /// 数据格式转换 + /// + /// 数据 + /// + public static string FormatData(long data) + { + string result = ""; + if (data < 0) + data = 0; + + if (data > 1024 * 1024) + { + result = ((int)(data / (1024 * 1024))).ToString() + "MB"; + } + else if (data > 1024) + { + result = ((int)(data / 1024)).ToString() + "KB"; + } + else + { + result = data + "B"; + } + + return result; + } + + /// + /// 获取文件大小 + /// + /// 文件路径 + /// + public static long GetFileSize(string path) + { + using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + return file.Length; + } + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.File.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.File.cs.meta new file mode 100644 index 00000000..2fa676db --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.File.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a1d1aee75b54fbd925f34bd70f09840 +timeCreated: 1695138211 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Http.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Http.cs new file mode 100644 index 00000000..5d250551 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Http.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Cysharp.Threading.Tasks; +using UnityEngine; +using UnityEngine.Networking; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// Http 相关的实用函数。 + /// + public static partial class Http + { + /// + /// GET请求与获取结果。 + /// + /// 网络URL。 + /// 超时时间。 + /// 请求结果。 + public static async UniTask Get(string url, float timeout = 5f) + { + var cts = new CancellationTokenSource(); + cts.CancelAfterSlim(TimeSpan.FromSeconds(timeout)); + + using UnityWebRequest unityWebRequest = UnityWebRequest.Get(url); + return await SendWebRequest(unityWebRequest, cts); + } + + /// + /// Post请求与获取结果. + /// + /// 网络URL。 + /// Post数据。 + /// 超时时间。 + /// 请求结果。 + public static async UniTask Post(string url, string postData, float timeout = 5f) + { + var cts = new CancellationTokenSource(); + cts.CancelAfterSlim(TimeSpan.FromSeconds(timeout)); + + using UnityWebRequest unityWebRequest = UnityWebRequest.PostWwwForm(url, postData); + return await SendWebRequest(unityWebRequest, cts); + } + + /// + /// Post请求与获取结果. + /// + /// 网络URL。 + /// Post数据。 + /// 超时时间。 + /// 请求结果。 + public static async UniTask Post(string url, Dictionary formFields, float timeout = 5f) + { + var cts = new CancellationTokenSource(); + cts.CancelAfterSlim(TimeSpan.FromSeconds(timeout)); + + using UnityWebRequest unityWebRequest = UnityWebRequest.Post(url, formFields); + return await SendWebRequest(unityWebRequest, cts); + } + + /// + /// Post请求与获取结果. + /// + /// 网络URL。 + /// Post数据。 + /// 超时时间。 + /// 请求结果。 + public static async UniTask Post(string url, WWWForm formData, float timeout = 5f) + { + var cts = new CancellationTokenSource(); + cts.CancelAfterSlim(TimeSpan.FromSeconds(timeout)); + + using UnityWebRequest unityWebRequest = UnityWebRequest.Post(url, formData); + return await SendWebRequest(unityWebRequest, cts); + } + + /// + /// 抛出网络请求。 + /// + /// UnityWebRequest。 + /// CancellationTokenSource。 + /// 请求结果。 + public static async UniTask SendWebRequest(UnityWebRequest unityWebRequest, CancellationTokenSource cts) + { + try + { + var (isCanceled, _) = await unityWebRequest.SendWebRequest().WithCancellation(cts.Token).SuppressCancellationThrow(); + if (isCanceled) + { + Log.Warning($"HttpPost {unityWebRequest.url} be canceled!"); + unityWebRequest.Dispose(); + return string.Empty; + } + } + catch (OperationCanceledException ex) + { + if (ex.CancellationToken == cts.Token) + { + Log.Warning("HttpPost Timeout"); + unityWebRequest.Dispose(); + return string.Empty; + } + } + + string ret = unityWebRequest.downloadHandler.text; + unityWebRequest.Dispose(); + return ret; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Http.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Http.cs.meta new file mode 100644 index 00000000..e919dbd4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Http.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2fb4e969cbf246df87978a62bcb479c0 +timeCreated: 1694797084 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.IJsonHelper.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.IJsonHelper.cs new file mode 100644 index 00000000..06c2bfd7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.IJsonHelper.cs @@ -0,0 +1,39 @@ +using System; + +namespace TEngine +{ + public static partial class Utility + { + public static partial class Json + { + /// + /// JSON 辅助器接口。 + /// + public interface IJsonHelper + { + /// + /// 将对象序列化为 JSON 字符串。 + /// + /// 要序列化的对象。 + /// 序列化后的 JSON 字符串。 + string ToJson(object obj); + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + T ToObject(string json); + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + object ToObject(Type objectType, string json); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.IJsonHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.IJsonHelper.cs.meta new file mode 100644 index 00000000..9cdcf8c0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.IJsonHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15ae91aaf3fa53b4c87c71128d24b6a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.cs new file mode 100644 index 00000000..1a47e236 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.cs @@ -0,0 +1,112 @@ +using System; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// JSON 相关的实用函数。 + /// + public static partial class Json + { + private static IJsonHelper _jsonHelper = new DefaultJsonHelper(); + + /// + /// 设置 JSON 辅助器。 + /// + /// 要设置的 JSON 辅助器。 + public static void SetJsonHelper(IJsonHelper jsonHelper) + { + _jsonHelper = jsonHelper; + } + + /// + /// 将对象序列化为 JSON 字符串。 + /// + /// 要序列化的对象。 + /// 序列化后的 JSON 字符串。 + public static string ToJson(object obj) + { + if (_jsonHelper == null) + { + throw new GameFrameworkException("JSON helper is invalid."); + } + + try + { + return _jsonHelper.ToJson(obj); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not convert to JSON with exception '{0}'.", exception), exception); + } + } + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public static T ToObject(string json) + { + if (_jsonHelper == null) + { + throw new GameFrameworkException("JSON helper is invalid."); + } + + try + { + return _jsonHelper.ToObject(json); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not convert to object with exception '{0}'.", exception), exception); + } + } + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public static object ToObject(Type objectType, string json) + { + if (_jsonHelper == null) + { + throw new GameFrameworkException("JSON helper is invalid."); + } + + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + try + { + return _jsonHelper.ToObject(objectType, json); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not convert to object with exception '{0}'.", exception), exception); + } + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.cs.meta new file mode 100644 index 00000000..a0e778a5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Json.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2753220619efc4d45b5091b299db206c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Marshal.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Marshal.cs new file mode 100644 index 00000000..cbfd7fa8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Marshal.cs @@ -0,0 +1,228 @@ +using System; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// Marshal 相关的实用函数。 + /// + /// 非托管内存相关的实用函数。 + public static class Marshal + { + private const int BlockSize = 1024 * 4; + private static IntPtr _cachedHGlobalPtr = IntPtr.Zero; + private static int _cachedHGlobalSize = 0; + + /// + /// 获取缓存的从进程的非托管内存中分配的内存的大小。 + /// + public static int CachedHGlobalSize => _cachedHGlobalSize; + + /// + /// 确保从进程的非托管内存中分配足够大小的内存并缓存。 + /// + /// 要确保从进程的非托管内存中分配内存的大小。 + public static void EnsureCachedHGlobalSize(int ensureSize) + { + if (ensureSize < 0) + { + throw new GameFrameworkException("Ensure size is invalid."); + } + + if (_cachedHGlobalPtr == IntPtr.Zero || _cachedHGlobalSize < ensureSize) + { + FreeCachedHGlobal(); + int size = (ensureSize - 1 + BlockSize) / BlockSize * BlockSize; + _cachedHGlobalPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size); + _cachedHGlobalSize = size; + } + } + + /// + /// 释放缓存的从进程的非托管内存中分配的内存。 + /// + public static void FreeCachedHGlobal() + { + if (_cachedHGlobalPtr != IntPtr.Zero) + { + System.Runtime.InteropServices.Marshal.FreeHGlobal(_cachedHGlobalPtr); + _cachedHGlobalPtr = IntPtr.Zero; + _cachedHGlobalSize = 0; + } + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 存储转换结果的二进制流。 + public static byte[] StructureToBytes(T structure) + { + return StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T))); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 要转换的对象的大小。 + /// 存储转换结果的二进制流。 + internal static byte[] StructureToBytes(T structure, int structureSize) + { + if (structureSize < 0) + { + throw new GameFrameworkException("Structure size is invalid."); + } + + EnsureCachedHGlobalSize(structureSize); + System.Runtime.InteropServices.Marshal.StructureToPtr(structure, _cachedHGlobalPtr, true); + byte[] result = new byte[structureSize]; + System.Runtime.InteropServices.Marshal.Copy(_cachedHGlobalPtr, result, 0, structureSize); + return result; + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 存储转换结果的二进制流。 + public static void StructureToBytes(T structure, byte[] result) + { + StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, 0); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 要转换的对象的大小。 + /// 存储转换结果的二进制流。 + internal static void StructureToBytes(T structure, int structureSize, byte[] result) + { + StructureToBytes(structure, structureSize, result, 0); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 存储转换结果的二进制流。 + /// 写入存储转换结果的二进制流的起始位置。 + public static void StructureToBytes(T structure, byte[] result, int startIndex) + { + StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, startIndex); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 要转换的对象的大小。 + /// 存储转换结果的二进制流。 + /// 写入存储转换结果的二进制流的起始位置。 + internal static void StructureToBytes(T structure, int structureSize, byte[] result, int startIndex) + { + if (structureSize < 0) + { + throw new GameFrameworkException("Structure size is invalid."); + } + + if (result == null) + { + throw new GameFrameworkException("Result is invalid."); + } + + if (startIndex < 0) + { + throw new GameFrameworkException("Start index is invalid."); + } + + if (startIndex + structureSize > result.Length) + { + throw new GameFrameworkException("Result length is not enough."); + } + + EnsureCachedHGlobalSize(structureSize); + System.Runtime.InteropServices.Marshal.StructureToPtr(structure, _cachedHGlobalPtr, true); + System.Runtime.InteropServices.Marshal.Copy(_cachedHGlobalPtr, result, startIndex, structureSize); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的二进制流。 + /// 存储转换结果的对象。 + public static T BytesToStructure(byte[] buffer) + { + return BytesToStructure(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, 0); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的二进制流。 + /// 读取要转换的二进制流的起始位置。 + /// 存储转换结果的对象。 + public static T BytesToStructure(byte[] buffer, int startIndex) + { + return BytesToStructure(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, startIndex); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象的大小。 + /// 要转换的二进制流。 + /// 存储转换结果的对象。 + internal static T BytesToStructure(int structureSize, byte[] buffer) + { + return BytesToStructure(structureSize, buffer, 0); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象的大小。 + /// 要转换的二进制流。 + /// 读取要转换的二进制流的起始位置。 + /// 存储转换结果的对象。 + internal static T BytesToStructure(int structureSize, byte[] buffer, int startIndex) + { + if (structureSize < 0) + { + throw new GameFrameworkException("Structure size is invalid."); + } + + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0) + { + throw new GameFrameworkException("Start index is invalid."); + } + + if (startIndex + structureSize > buffer.Length) + { + throw new GameFrameworkException("Buffer length is not enough."); + } + + EnsureCachedHGlobalSize(structureSize); + System.Runtime.InteropServices.Marshal.Copy(buffer, startIndex, _cachedHGlobalPtr, structureSize); + return (T)System.Runtime.InteropServices.Marshal.PtrToStructure(_cachedHGlobalPtr, typeof(T)); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Marshal.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Marshal.cs.meta new file mode 100644 index 00000000..20068711 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Marshal.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bcbe713970be4330aa4a53b1f808da2f +timeCreated: 1694797084 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Path.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Path.cs new file mode 100644 index 00000000..f14e2094 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Path.cs @@ -0,0 +1,93 @@ +using System.IO; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 路径相关的实用函数。 + /// + public static class Path + { + /// + /// 获取规范的路径。 + /// + /// 要规范的路径。 + /// 规范的路径。 + public static string GetRegularPath(string path) + { + if (path == null) + { + return null; + } + + return path.Replace('\\', '/'); + } + + /// + /// 获取远程格式的路径(带有file:// 或 http:// 前缀)。 + /// + /// 原始路径。 + /// 远程格式路径。 + public static string GetRemotePath(string path) + { + string regularPath = GetRegularPath(path); + if (regularPath == null) + { + return null; + } + + return regularPath.Contains("://") ? regularPath : ("file:///" + regularPath).Replace("file:////", "file:///"); + } + + /// + /// 移除空文件夹。 + /// + /// 要处理的文件夹名称。 + /// 是否移除空文件夹成功。 + public static bool RemoveEmptyDirectory(string directoryName) + { + if (string.IsNullOrEmpty(directoryName)) + { + throw new GameFrameworkException("Directory name is invalid."); + } + + try + { + if (!Directory.Exists(directoryName)) + { + return false; + } + + // 不使用 SearchOption.AllDirectories,以便于在可能产生异常的环境下删除尽可能多的目录 + string[] subDirectoryNames = Directory.GetDirectories(directoryName, "*"); + int subDirectoryCount = subDirectoryNames.Length; + foreach (string subDirectoryName in subDirectoryNames) + { + if (RemoveEmptyDirectory(subDirectoryName)) + { + subDirectoryCount--; + } + } + + if (subDirectoryCount > 0) + { + return false; + } + + if (Directory.GetFiles(directoryName, "*").Length > 0) + { + return false; + } + + Directory.Delete(directoryName); + return true; + } + catch + { + return false; + } + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Path.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Path.cs.meta new file mode 100644 index 00000000..131f23a8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Path.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2ea89e6a2e8940c6ba38bcb93fd55881 +timeCreated: 1695115852 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Reflection.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Reflection.cs new file mode 100644 index 00000000..3fb0743e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Reflection.cs @@ -0,0 +1,358 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 反射相关的实用函数。 + /// + public static class Reflection + { + /// + /// 执行方法。 + /// + /// 目标对象。 + /// 方法名。 + /// 方法参数。 + /// 返回值。 + public static object InvokeMethod(object obj, string methodName, object[] parameters = null) + { + if (obj == null) + throw new NullReferenceException($"Obj is invalid !"); + if (string.IsNullOrEmpty(methodName)) + { + throw new ArgumentNullException($"MethodName is invalid !"); + } + + Type type = obj.GetType(); + if (type == null) + { + throw new ArgumentNullException($"Type is invalid !"); + } + + if (type.BaseType == null) + { + throw new ArgumentNullException($"BaseType is invalid !"); + } + + var method = type.BaseType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); + if (method == null) + { + throw new NullReferenceException($"Type : {type} can not find method : {methodName} !"); + } + + return method.Invoke(obj, parameters); + } + + /// + /// 执行方法. + /// + /// 方法所在的type。 + /// 目标对象。 + /// 方法名。 + /// 方法参数。 + /// 返回值。 + public static object InvokeMethod(Type type, object obj, string methodName, object[] parameters = null) + { + if (type == null) + { + throw new ArgumentNullException($"Type is invalid !"); + } + + if (obj == null) + { + throw new NullReferenceException($"Obj is invalid !"); + } + + if (string.IsNullOrEmpty(methodName)) + { + throw new ArgumentNullException($"MethodName is invalid !"); + } + + var method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); + if (method == null) + { + throw new NullReferenceException($"Type : {type} can not find method : {methodName} !"); + } + + return method.Invoke(obj, parameters); + } + + /// + /// 设置对象属性值。 + /// + /// 目标对象。 + /// 属性名。 + /// 属性值。 + public static void SetPropertyValue(object obj, string propertyName, object newValue) + { + if (obj == null) + { + throw new NullReferenceException($"Obj is invalid !"); + } + + if (string.IsNullOrEmpty(propertyName)) + { + throw new ArgumentNullException($"PropertyName is invalid !"); + } + + Type type = obj.GetType(); + PropertyInfo prop = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); + if (prop == null) + { + throw new NullReferenceException($"Type : {type} can not find prop: {propertyName} !"); + } + + prop.SetValue(obj, newValue, null); + } + + /// + /// 设置对象属性值。 + /// 使用此方法为对象属性进行赋值时,若Type类型赋予正确,则可赋值非public类型的属性值. + /// + /// 属性可写的类Type。 + /// 目标对象。 + /// 属性名。 + /// 属性值。 + public static void SetPropertyValue(Type type, object obj, string propertyName, object value) + { + if (type == null) + { + throw new ArgumentNullException($"Type is invalid !"); + } + + if (obj == null) + { + throw new NullReferenceException($"Obj is invalid !"); + } + + if (string.IsNullOrEmpty(propertyName)) + { + throw new ArgumentNullException($"PropertyName is invalid !"); + } + + PropertyInfo prop = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); + if (prop == null) + { + throw new NullReferenceException($"Type : {type} can not find prop: {propertyName} !"); + } + + prop.SetValue(obj, value, null); + } + + /// + /// 设置对象字段值。 + /// + /// 字段可赋值所在类Type。 + /// 目标对象。 + /// 字段名。 + /// 字段值。 + public static void SetFieldValue(Type type, object obj, string fieldName, object value) + { + if (type == null) + { + throw new ArgumentNullException($"Type is invalid !"); + } + + if (string.IsNullOrEmpty(fieldName)) + { + throw new ArgumentNullException($"FieldName is invalid !"); + } + + var field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); + if (field == null) + { + throw new NullReferenceException($"Type : {type} can not find field: {fieldName} !"); + } + + field.SetValue(obj, value); + } + + /// + /// 设置对象字段值。 + /// + /// 目标对象。 + /// 字段名。 + /// 字段值。 + public static void SetFieldValue(object obj, string fieldName, object value) + { + if (obj == null) + { + throw new NullReferenceException("Obj is invalid !"); + } + + if (string.IsNullOrEmpty(fieldName)) + { + throw new ArgumentNullException($"FieldName is invalid !"); + } + + Type type = obj.GetType(); + var field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); + if (field == null) + { + throw new NullReferenceException($"Type : {type} can not find field: {fieldName} !"); + } + + field.SetValue(obj, value); + } + + /// + /// 获取对象的属性值。 + /// + /// 目标对象。 + /// 属性名。 + /// 属性值。 + public static object GetPropertyValue(object obj, string propertyName) + { + if (obj == null) + { + throw new NullReferenceException("Obj is invalid !"); + } + + if (string.IsNullOrEmpty(propertyName)) + { + throw new ArgumentNullException($"PropertyName is invalid !"); + } + + Type type = obj.GetType(); + var property = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); + if (property == null) + { + throw new NullReferenceException($"Type : {type} can not find property: {propertyName} !"); + } + + return property.GetValue(obj); + } + + /// + /// 获取非实例对象属性。 + /// + /// 类型。 + /// 属性名。 + /// 属性值。 + public static object GetNonInstancePropertyValue(Type type, string propertyName) + { + var property = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic); + if (property == null) + { + throw new NullReferenceException($"Type : {type} can not find property: {propertyName} !"); + } + + return property.GetValue(propertyName); + } + + /// + /// 获取属性。 + /// + /// 类型。 + /// 属性名。 + /// 属性信息 + public static PropertyInfo GetProperty(Type type, string propertyName) + { + var property = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); + if (property == null) + { + throw new NullReferenceException($"Type : {type} can not find property: {propertyName} !"); + } + + return property; + } + + /// + /// 获取对象字段值。 + /// + /// 目标对象。 + /// 字段名。 + /// 字段值 + public static object GetFieldValue(object obj, string fieldName) + { + if (obj == null) + { + throw new NullReferenceException("Obj is invalid !"); + } + + if (string.IsNullOrEmpty(fieldName)) + { + throw new ArgumentNullException($"FieldName is invalid !"); + } + + Type type = obj.GetType(); + var field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); + if (field == null) + { + throw new NullReferenceException($"Type : {type} can not find field: {fieldName} !"); + } + + return field.GetValue(obj); + } + + /// + /// 获取类Type类型中的所有字段名. + /// + /// type类型。 + /// 名称数组。 + public static string[] GetTypeAllFields() + { + return GetTypeAllFields(typeof(T)); + } + + /// + /// 获取类Type类型中的所有字段名. + /// + /// type类型。 + /// 名称数组。 + public static string[] GetTypeAllFields(Type type) + { + var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static); + return fields.Select(f => f.Name).ToArray(); + } + + /// + /// 获取Type类型中所有属性字段名。 + /// + /// type类型。 + /// 名称数组。 + public static string[] GetTypeAllProperties() + { + return GetTypeAllProperties(typeof(T)); + } + + /// + /// 获取Type类型中所有属性字段名. + /// + /// type类型。 + /// 名称数组。 + public static string[] GetTypeAllProperties(Type type) + { + var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static); + return properties.Select(f => f.Name).ToArray(); + } + + /// + /// 获取Type类型中所有字段名称与字段类型的映射。 + /// + /// type类型。 + /// 名称与类型的映射。 + public static IDictionary GetTypeFieldsNameAndTypeMapping(Type type) + { + var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static); + return fields.ToDictionary(f => f.Name, t => t.FieldType); + } + + /// + /// 获取Type类型中所有属性名称与字段类型的映射。 + /// + /// type类型。 + /// 名称与类型的映射。 + public static IDictionary GetTypePropertyNameAndTypeMapping(Type type) + { + var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static); + return properties.ToDictionary(f => f.Name, t => t.PropertyType); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Reflection.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Reflection.cs.meta new file mode 100644 index 00000000..550b04be --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Reflection.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fd25c50add6b4a5fada05afd31373133 +timeCreated: 1694853539 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.ITextHelper.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.ITextHelper.cs new file mode 100644 index 00000000..fc2b9a69 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.ITextHelper.cs @@ -0,0 +1,398 @@ +namespace TEngine +{ + public static partial class Utility + { + public static partial class Text + { + /// + /// 字符辅助器接口。 + /// + public interface ITextHelper + { + /// + /// 获取格式化字符串。 + /// + /// 字符串参数的类型。 + /// 字符串格式。 + /// 字符串参数。 + /// 格式化后的字符串。 + string Format(string format, T arg); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串参数 14 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 字符串参数 14。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串参数 14 的类型。 + /// 字符串参数 15 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 字符串参数 14。 + /// 字符串参数 15。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串参数 14 的类型。 + /// 字符串参数 15 的类型。 + /// 字符串参数 16 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 字符串参数 14。 + /// 字符串参数 15。 + /// 字符串参数 16。 + /// 格式化后的字符串。 + string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.ITextHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.ITextHelper.cs.meta new file mode 100644 index 00000000..1aa76fc4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.ITextHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d121fde38e41ffe48a7f761404700911 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.cs new file mode 100644 index 00000000..388fcb37 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.cs @@ -0,0 +1,614 @@ +namespace TEngine +{ + public static partial class Utility + { + /// + /// 字符相关的实用函数。 + /// + public static partial class Text + { + private static ITextHelper _textHelper = null; + + /// + /// 设置字符辅助器。 + /// + /// 要设置的字符辅助器。 + public static void SetTextHelper(ITextHelper textHelper) + { + _textHelper = textHelper; + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数的类型。 + /// 字符串格式。 + /// 字符串参数。 + /// 格式化后的字符串。 + public static string Format(string format, T arg) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg); + } + + return _textHelper.Format(format, arg); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2); + } + + return _textHelper.Format(format, arg1, arg2); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3); + } + + return _textHelper.Format(format, arg1, arg2, arg3); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串参数 14 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 字符串参数 14。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串参数 14 的类型。 + /// 字符串参数 15 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 字符串参数 14。 + /// 字符串参数 15。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); + } + + /// + /// 获取格式化字符串。 + /// + /// 字符串参数 1 的类型。 + /// 字符串参数 2 的类型。 + /// 字符串参数 3 的类型。 + /// 字符串参数 4 的类型。 + /// 字符串参数 5 的类型。 + /// 字符串参数 6 的类型。 + /// 字符串参数 7 的类型。 + /// 字符串参数 8 的类型。 + /// 字符串参数 9 的类型。 + /// 字符串参数 10 的类型。 + /// 字符串参数 11 的类型。 + /// 字符串参数 12 的类型。 + /// 字符串参数 13 的类型。 + /// 字符串参数 14 的类型。 + /// 字符串参数 15 的类型。 + /// 字符串参数 16 的类型。 + /// 字符串格式。 + /// 字符串参数 1。 + /// 字符串参数 2。 + /// 字符串参数 3。 + /// 字符串参数 4。 + /// 字符串参数 5。 + /// 字符串参数 6。 + /// 字符串参数 7。 + /// 字符串参数 8。 + /// 字符串参数 9。 + /// 字符串参数 10。 + /// 字符串参数 11。 + /// 字符串参数 12。 + /// 字符串参数 13。 + /// 字符串参数 14。 + /// 字符串参数 15。 + /// 字符串参数 16。 + /// 格式化后的字符串。 + public static string Format(string format, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16) + { + if (format == null) + { + throw new GameFrameworkException("Format is invalid."); + } + + if (_textHelper == null) + { + return string.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + } + + return _textHelper.Format(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.cs.meta new file mode 100644 index 00000000..7b8c841b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Text.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d27a67521c3581546a10eee3c4021d04 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Unity.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Unity.cs new file mode 100644 index 00000000..83427579 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Unity.cs @@ -0,0 +1,408 @@ +using System.Collections; +using Cysharp.Threading.Tasks; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Internal; +using Object = UnityEngine.Object; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// Unity相关的实用函数。 + /// + public static partial class Unity + { + private static GameObject _entity; + private static MainBehaviour _behaviour; + + #region 控制协程Coroutine + + public static Coroutine StartCoroutine(string methodName) + { + if (string.IsNullOrEmpty(methodName)) + { + return null; + } + + _MakeEntity(); + return _behaviour.StartCoroutine(methodName); + } + + public static Coroutine StartCoroutine(IEnumerator routine) + { + if (routine == null) + { + return null; + } + + _MakeEntity(); + return _behaviour.StartCoroutine(routine); + } + + public static Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value) + { + if (string.IsNullOrEmpty(methodName)) + { + return null; + } + + _MakeEntity(); + return _behaviour.StartCoroutine(methodName, value); + } + + public static void StopCoroutine(string methodName) + { + if (string.IsNullOrEmpty(methodName)) + { + return; + } + + if (_entity != null) + { + _behaviour.StopCoroutine(methodName); + } + } + + public static void StopCoroutine(IEnumerator routine) + { + if (routine == null) + { + return; + } + + if (_entity != null) + { + _behaviour.StopCoroutine(routine); + } + } + + public static void StopCoroutine(Coroutine routine) + { + if (routine == null) + return; + + if (_entity != null) + { + _behaviour.StopCoroutine(routine); + routine = null; + } + } + + public static void StopAllCoroutines() + { + if (_entity != null) + { + _behaviour.StopAllCoroutines(); + } + } + + #endregion + + #region 注入UnityUpdate/FixedUpdate/LateUpdate + + /// + /// 为给外部提供的 添加帧更新事件。 + /// + /// + public static void AddUpdateListener(UnityAction fun) + { + _MakeEntity(); + AddUpdateListenerImp(fun).Forget(); + } + + private static async UniTaskVoid AddUpdateListenerImp(UnityAction fun) + { + await UniTask.Yield(/*PlayerLoopTiming.LastPreUpdate*/); + _behaviour.AddUpdateListener(fun); + } + + /// + /// 为给外部提供的 添加物理帧更新事件。 + /// + /// + public static void AddFixedUpdateListener(UnityAction fun) + { + _MakeEntity(); + AddFixedUpdateListenerImp(fun).Forget(); + } + + private static async UniTaskVoid AddFixedUpdateListenerImp(UnityAction fun) + { + await UniTask.Yield(PlayerLoopTiming.LastEarlyUpdate); + _behaviour.AddFixedUpdateListener(fun); + } + + /// + /// 为给外部提供的 添加Late帧更新事件。 + /// + /// + public static void AddLateUpdateListener(UnityAction fun) + { + _MakeEntity(); + AddLateUpdateListenerImp(fun).Forget(); + } + + private static async UniTaskVoid AddLateUpdateListenerImp(UnityAction fun) + { + await UniTask.Yield(/*PlayerLoopTiming.LastPreLateUpdate*/); + _behaviour.AddLateUpdateListener(fun); + } + + /// + /// 移除帧更新事件。 + /// + /// + public static void RemoveUpdateListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveUpdateListener(fun); + } + + /// + /// 移除物理帧更新事件。 + /// + /// + public static void RemoveFixedUpdateListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveFixedUpdateListener(fun); + } + + /// + /// 移除Late帧更新事件。 + /// + /// + public static void RemoveLateUpdateListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveLateUpdateListener(fun); + } + + #endregion + + #region Unity Events 注入 + /// + /// 为给外部提供的Destroy注册事件。 + /// + /// + public static void AddDestroyListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.AddDestroyListener(fun); + } + + /// + /// 为给外部提供的Destroy反注册事件。 + /// + /// + public static void RemoveDestroyListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveDestroyListener(fun); + } + + /// + /// 为给外部提供的OnDrawGizmos注册事件。 + /// + /// + public static void AddOnDrawGizmosListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.AddOnDrawGizmosListener(fun); + } + + /// + /// 为给外部提供的OnDrawGizmos反注册事件。 + /// + /// + public static void RemoveOnDrawGizmosListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveOnDrawGizmosListener(fun); + } + + /// + /// 为给外部提供的OnApplicationPause注册事件。 + /// + /// + public static void AddOnApplicationPauseListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.AddOnApplicationPauseListener(fun); + } + + /// + /// 为给外部提供的OnApplicationPause反注册事件。 + /// + /// + public static void RemoveOnApplicationPauseListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveOnApplicationPauseListener(fun); + } + #endregion + + private static void _MakeEntity() + { + if (_entity != null) + { + return; + } + + _entity = new GameObject("[Unity.Utility]"); + _entity.SetActive(true); + _entity.transform.SetParent(GameModule.Base.transform); + + UnityEngine.Assertions.Assert.IsFalse(_behaviour); + _behaviour = _entity.AddComponent(); + } + + /// + /// 释放Behaviour生命周期。 + /// + public static void Shutdown() + { + if (_behaviour != null) + { + _behaviour.Shutdown(); + } + if (_entity != null) + { + Object.Destroy(_entity); + } + _entity = null; + } + + private class MainBehaviour : MonoBehaviour + { + private event UnityAction UpdateEvent; + private event UnityAction FixedUpdateEvent; + private event UnityAction LateUpdateEvent; + private event UnityAction DestroyEvent; + private event UnityAction OnDrawGizmosEvent; + private event UnityAction OnApplicationPauseEvent; + + void Update() + { + if (UpdateEvent != null) + { + UpdateEvent(); + } + } + + void FixedUpdate() + { + if (FixedUpdateEvent != null) + { + FixedUpdateEvent(); + } + } + + void LateUpdate() + { + if (LateUpdateEvent != null) + { + LateUpdateEvent(); + } + } + + private void OnDestroy() + { + if (DestroyEvent != null) + { + DestroyEvent(); + } + } + + private void OnDrawGizmos() + { + if (OnDrawGizmosEvent != null) + { + OnDrawGizmosEvent(); + } + } + + private void OnApplicationPause(bool pauseStatus) + { + if (OnApplicationPauseEvent != null) + { + OnApplicationPauseEvent(pauseStatus); + } + } + + public void AddLateUpdateListener(UnityAction fun) + { + LateUpdateEvent += fun; + } + + public void RemoveLateUpdateListener(UnityAction fun) + { + LateUpdateEvent -= fun; + } + + public void AddFixedUpdateListener(UnityAction fun) + { + FixedUpdateEvent += fun; + } + + public void RemoveFixedUpdateListener(UnityAction fun) + { + FixedUpdateEvent -= fun; + } + + public void AddUpdateListener(UnityAction fun) + { + UpdateEvent += fun; + } + + public void RemoveUpdateListener(UnityAction fun) + { + UpdateEvent -= fun; + } + + public void AddDestroyListener(UnityAction fun) + { + DestroyEvent += fun; + } + + public void RemoveDestroyListener(UnityAction fun) + { + DestroyEvent -= fun; + } + + public void AddOnDrawGizmosListener(UnityAction fun) + { + OnDrawGizmosEvent += fun; + } + + public void RemoveOnDrawGizmosListener(UnityAction fun) + { + OnDrawGizmosEvent -= fun; + } + + public void AddOnApplicationPauseListener(UnityAction fun) + { + OnApplicationPauseEvent += fun; + } + + public void RemoveOnApplicationPauseListener(UnityAction fun) + { + OnApplicationPauseEvent -= fun; + } + + internal void Shutdown() + { + DestroyEvent?.Invoke(); + UpdateEvent = null; + FixedUpdateEvent = null; + LateUpdateEvent = null; + OnDrawGizmosEvent = null; + DestroyEvent = null; + OnApplicationPauseEvent = null; + } + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Unity.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Unity.cs.meta new file mode 100644 index 00000000..9e2652e8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.Unity.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2500c34bc1bf4d13a7a801b575a75580 +timeCreated: 1694840114 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.cs b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.cs new file mode 100644 index 00000000..2b2b9b49 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.cs @@ -0,0 +1,9 @@ +namespace TEngine +{ + /// + /// 实用函数集。 + /// + public static partial class Utility + { + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.cs.meta new file mode 100644 index 00000000..6db8ea9a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Utility/Utility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30f0f885635b2b54d9693cd0291a1503 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Version.meta b/EintooAR/Assets/TEngine/Runtime/Core/Version.meta new file mode 100644 index 00000000..d22f74df --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Version.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d0dc2a1b8d634ce284057b3498abfeba +timeCreated: 1694843598 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.IVersionHelper.cs b/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.IVersionHelper.cs new file mode 100644 index 00000000..d6bf3688 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.IVersionHelper.cs @@ -0,0 +1,27 @@ +namespace TEngine +{ + public static partial class Version + { + /// + /// 版本号辅助器接口。 + /// + public interface IVersionHelper + { + /// + /// 获取游戏版本号。 + /// + string GameVersion + { + get; + } + + /// + /// 获取内部游戏版本号。 + /// + string InternalGameVersion + { + get; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.IVersionHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.IVersionHelper.cs.meta new file mode 100644 index 00000000..727feb19 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.IVersionHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 80f76c740d32479986a4a4eb04a8a9da +timeCreated: 1680338288 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.cs b/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.cs new file mode 100644 index 00000000..9c773b63 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.cs @@ -0,0 +1,58 @@ +namespace TEngine +{ + /// + /// 版本号类。 + /// + public static partial class Version + { + private const string GameFrameworkVersionString = "2024.03.18"; + + private static IVersionHelper s_VersionHelper = null; + + /// + /// 获取游戏框架版本号。 + /// + public static string GameFrameworkVersion => GameFrameworkVersionString; + + /// + /// 获取游戏版本号。 + /// + public static string GameVersion + { + get + { + if (s_VersionHelper == null) + { + return string.Empty; + } + + return s_VersionHelper.GameVersion; + } + } + + /// + /// 获取内部游戏版本号。 + /// + public static string InternalGameVersion + { + get + { + if (s_VersionHelper == null) + { + return string.Empty; + } + + return s_VersionHelper.InternalGameVersion; + } + } + + /// + /// 设置版本号辅助器。 + /// + /// 要设置的版本号辅助器。 + public static void SetVersionHelper(IVersionHelper versionHelper) + { + s_VersionHelper = versionHelper; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.cs.meta b/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.cs.meta new file mode 100644 index 00000000..bb4ccca5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Core/Version/Version.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 145aad75d48e46af9099829684014934 +timeCreated: 1680338287 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension.meta b/EintooAR/Assets/TEngine/Runtime/Extension.meta new file mode 100644 index 00000000..bf69db6d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 870f0ece6ed843de9cb4a5f6628856aa +timeCreated: 1694831438 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/BinaryExtension.cs b/EintooAR/Assets/TEngine/Runtime/Extension/BinaryExtension.cs new file mode 100644 index 00000000..7cc5a053 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/BinaryExtension.cs @@ -0,0 +1,187 @@ +using System; +using System.IO; + +namespace TEngine +{ + /// + /// 对 BinaryReader 和 BinaryWriter 的扩展方法。 + /// + public static class BinaryExtension + { + private static readonly byte[] s_CachedBytes = new byte[byte.MaxValue + 1]; + + /// + /// 从二进制流读取编码后的 32 位有符号整数。 + /// + /// 要读取的二进制流。 + /// 读取的 32 位有符号整数。 + public static int Read7BitEncodedInt32(this BinaryReader binaryReader) + { + int value = 0; + int shift = 0; + byte b; + do + { + if (shift >= 35) + { + throw new GameFrameworkException("7 bit encoded int is invalid."); + } + + b = binaryReader.ReadByte(); + value |= (b & 0x7f) << shift; + shift += 7; + } while ((b & 0x80) != 0); + + return value; + } + + /// + /// 向二进制流写入编码后的 32 位有符号整数。 + /// + /// 要写入的二进制流。 + /// 要写入的 32 位有符号整数。 + public static void Write7BitEncodedInt32(this BinaryWriter binaryWriter, int value) + { + uint num = (uint)value; + while (num >= 0x80) + { + binaryWriter.Write((byte)(num | 0x80)); + num >>= 7; + } + + binaryWriter.Write((byte)num); + } + + /// + /// 从二进制流读取编码后的 32 位无符号整数。 + /// + /// 要读取的二进制流。 + /// 读取的 32 位无符号整数。 + public static uint Read7BitEncodedUInt32(this BinaryReader binaryReader) + { + return (uint)Read7BitEncodedInt32(binaryReader); + } + + /// + /// 向二进制流写入编码后的 32 位无符号整数。 + /// + /// 要写入的二进制流。 + /// 要写入的 32 位无符号整数。 + public static void Write7BitEncodedUInt32(this BinaryWriter binaryWriter, uint value) + { + Write7BitEncodedInt32(binaryWriter, (int)value); + } + + /// + /// 从二进制流读取编码后的 64 位有符号整数。 + /// + /// 要读取的二进制流。 + /// 读取的 64 位有符号整数。 + public static long Read7BitEncodedInt64(this BinaryReader binaryReader) + { + long value = 0L; + int shift = 0; + byte b; + do + { + if (shift >= 70) + { + throw new GameFrameworkException("7 bit encoded int is invalid."); + } + + b = binaryReader.ReadByte(); + value |= (b & 0x7fL) << shift; + shift += 7; + } while ((b & 0x80) != 0); + + return value; + } + + /// + /// 向二进制流写入编码后的 64 位有符号整数。 + /// + /// 要写入的二进制流。 + /// 要写入的 64 位有符号整数。 + public static void Write7BitEncodedInt64(this BinaryWriter binaryWriter, long value) + { + ulong num = (ulong)value; + while (num >= 0x80) + { + binaryWriter.Write((byte)(num | 0x80)); + num >>= 7; + } + + binaryWriter.Write((byte)num); + } + + /// + /// 从二进制流读取编码后的 64 位无符号整数。 + /// + /// 要读取的二进制流。 + /// 读取的 64 位无符号整数。 + public static ulong Read7BitEncodedUInt64(this BinaryReader binaryReader) + { + return (ulong)Read7BitEncodedInt64(binaryReader); + } + + /// + /// 向二进制流写入编码后的 64 位无符号整数。 + /// + /// 要写入的二进制流。 + /// 要写入的 64 位无符号整数。 + public static void Write7BitEncodedUInt64(this BinaryWriter binaryWriter, ulong value) + { + Write7BitEncodedInt64(binaryWriter, (long)value); + } + + /// + /// 从二进制流读取加密字符串。 + /// + /// 要读取的二进制流。 + /// 密钥数组。 + /// 读取的字符串。 + public static string ReadEncryptedString(this BinaryReader binaryReader, byte[] encryptBytes) + { + byte length = binaryReader.ReadByte(); + if (length <= 0) + { + return null; + } + + for (byte i = 0; i < length; i++) + { + s_CachedBytes[i] = binaryReader.ReadByte(); + } + + Utility.Encryption.GetSelfXorBytes(s_CachedBytes, 0, length, encryptBytes); + string value = Utility.Converter.GetString(s_CachedBytes, 0, length); + Array.Clear(s_CachedBytes, 0, length); + return value; + } + + /// + /// 向二进制流写入加密字符串。 + /// + /// 要写入的二进制流。 + /// 要写入的字符串。 + /// 密钥数组。 + public static void WriteEncryptedString(this BinaryWriter binaryWriter, string value, byte[] encryptBytes) + { + if (string.IsNullOrEmpty(value)) + { + binaryWriter.Write((byte)0); + return; + } + + int length = Utility.Converter.GetBytes(value, s_CachedBytes); + if (length > byte.MaxValue) + { + throw new GameFrameworkException(Utility.Text.Format("String '{0}' is too long.", value)); + } + + Utility.Encryption.GetSelfXorBytes(s_CachedBytes, encryptBytes); + binaryWriter.Write((byte)length); + binaryWriter.Write(s_CachedBytes, 0, length); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/BinaryExtension.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/BinaryExtension.cs.meta new file mode 100644 index 00000000..90267940 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/BinaryExtension.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 034e8544d0ba43899e181df5adb1faff +timeCreated: 1695116017 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/StringBuilderCache.cs b/EintooAR/Assets/TEngine/Runtime/Extension/StringBuilderCache.cs new file mode 100644 index 00000000..fd6fbfc8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/StringBuilderCache.cs @@ -0,0 +1,59 @@ +using System; +using System.Text; + +namespace TEngine +{ + /// + /// 字符串构建器缓存。 + /// 常用于临时构筑。 + /// + public static class StringBuilderCache + { + [ThreadStatic] private static StringBuilder _cacheStringBuilder; + + private const int MaxBuilderSize = 512; + + /// + /// 获取缓存中的字符串构建器。 + /// + /// 字符串构建器容量。 + /// 字符串构建器。 + public static StringBuilder Acquire(int capacity = 256) + { + StringBuilder stringBuilder = _cacheStringBuilder; + + if (stringBuilder != null && stringBuilder.Capacity >= capacity) + { + _cacheStringBuilder = null; + stringBuilder.Clear(); + return stringBuilder; + } + + return new StringBuilder(capacity); + } + + /// + /// 获取文本并释放字符串构建器。 + /// + /// 字符串构建器。 + /// 文本实例。 + public static string GetStringAndRelease(StringBuilder stringBuilder) + { + string result = stringBuilder.ToString(); + Release(stringBuilder); + return result; + } + + /// + /// 释放字符串构建器。 + /// + /// 字符串构建器。 + public static void Release(StringBuilder stringBuilder) + { + if (stringBuilder.Capacity <= MaxBuilderSize) + { + _cacheStringBuilder = stringBuilder; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/StringBuilderCache.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/StringBuilderCache.cs.meta new file mode 100644 index 00000000..fb1b9d76 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/StringBuilderCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 382d9106b3df69e438db0d8aa4865ab5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension.meta new file mode 100644 index 00000000..2e1fee31 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6511169026ed9d48bc6e35cfc5f12d0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/EmptyGraph.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/EmptyGraph.cs new file mode 100644 index 00000000..e0aeb6d3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/EmptyGraph.cs @@ -0,0 +1,18 @@ +using UnityEngine.UI; + +public class EmptyGraph : Graphic +{ + public bool m_debug = false; + + protected override void OnPopulateMesh(VertexHelper vbo) + { + vbo.Clear(); + +#if UNITY_EDITOR + if (m_debug) + { + base.OnPopulateMesh(vbo); + } +#endif + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/EmptyGraph.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/EmptyGraph.cs.meta new file mode 100644 index 00000000..2f7aa575 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/EmptyGraph.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a9993284c2980e4cbbd565111bc17e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend.meta new file mode 100644 index 00000000..4a3a3b0b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 132d75994d564f239bd5cec2c237c0ee +timeCreated: 1673948810 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/DragHandler.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/DragHandler.cs new file mode 100644 index 00000000..8014b966 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/DragHandler.cs @@ -0,0 +1,117 @@ +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; + +namespace TEngine +{ + public class DragHandler : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler + { + private OnDragEvent _onDrag; + private OnDragEvent _onBeginDrag; + private OnDragEvent _onEndDrag; + private bool _isOnDrag = false; + private RectTransform _rect; + + private void Start() + { + _rect = (transform.parent) ? transform.parent.GetComponent() : null; + } + + public OnDragEvent onDrag + { + get + { + if (_onDrag == null) + { + _onDrag = new OnDragEvent(); + } + return _onDrag; + } + } + + public OnDragEvent onBeginDrag + { + get + { + if (_onBeginDrag == null) + { + _onBeginDrag = new OnDragEvent(); + } + return _onBeginDrag; + } + } + + public OnDragEvent onEndDrag + { + get + { + if (_onEndDrag == null) + { + _onEndDrag = new OnDragEvent(); + } + return _onEndDrag; + } + } + + public static DragHandler Get(GameObject go) + { + DragHandler listener = go.GetComponent(); + if (listener == null) listener = go.AddComponent(); + return listener; + } + + public void OnDrag(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left) return; + _isOnDrag = true; + if (onDrag != null) + { + Vector3 position = new Vector3(eventData.position.x, eventData.position.y, 0); + if (_rect) + { + RectTransformUtility.ScreenPointToWorldPointInRectangle(_rect, eventData.position, eventData.pressEventCamera, out position); + position.z = 0; + } + onDrag.Invoke(position, eventData); + } + } + + public void OnBeginDrag(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left) return; + _isOnDrag = true; + if (onBeginDrag != null) + { + Vector3 position = new Vector3(eventData.position.x, eventData.position.y, 0); + if (_rect) + { + RectTransformUtility.ScreenPointToWorldPointInRectangle(_rect, eventData.position, eventData.pressEventCamera, out position); + //position.z = eventData.pressEventCamera.transform.position.z; + position.z = 0; + } + onBeginDrag.Invoke(position, eventData); + } + } + + public void OnEndDrag(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left || !_isOnDrag) return; + if (onEndDrag != null) + { + Vector3 position = new Vector3(eventData.position.x, eventData.position.y, 0); + if (_rect) + { + RectTransformUtility.ScreenPointToWorldPointInRectangle(_rect, eventData.position, eventData.pressEventCamera, out position); + position.z = 0; + } + onEndDrag.Invoke(position, eventData); + } + _isOnDrag = false; + } + } + + public class OnDragEvent : UnityEvent + { + + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/DragHandler.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/DragHandler.cs.meta new file mode 100644 index 00000000..5bea506c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/DragHandler.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 11e8b4fd60224df8b40c720667926c51 +timeCreated: 1673948810 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/EventTriggerListener.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/EventTriggerListener.cs new file mode 100644 index 00000000..63268a80 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/EventTriggerListener.cs @@ -0,0 +1,180 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.Serialization; + +namespace TEngine +{ + public class EventTriggerListener : EventTrigger + { + public delegate void VoidDelegate(GameObject go); + public delegate void EventDelegate(GameObject go, PointerEventData ev); + [FormerlySerializedAs("onClick")] + public VoidDelegate OnClick; + [FormerlySerializedAs("onDown")] + public EventDelegate OnDown; + [FormerlySerializedAs("v")] + public EventDelegate OnExit; + [FormerlySerializedAs("onUp")] + public EventDelegate OnUp; + [FormerlySerializedAs("onSelect")] + public VoidDelegate OnSelectEvent; + [FormerlySerializedAs("onUpdateSelect")] + public VoidDelegate OnUpdateSelect; + [FormerlySerializedAs("onDragBegin")] + public EventDelegate OnDragBegin; + [FormerlySerializedAs("onDrag")] + public EventDelegate OnDragEvent; + [FormerlySerializedAs("onDragEnd")] + public EventDelegate OnDragEnd; + [FormerlySerializedAs("onEnter")] + public EventDelegate OnEnter; + [FormerlySerializedAs("onDrop")] + public EventDelegate OnDropEvent; + + public delegate void ClickEffectDelegate(); + public static EventTriggerListener Get(GameObject go, float time = -1, bool play_ani = true, float scale = 1) + { + if (!go) + { + Log.Warning("EventTriggerListener.Get, GameObject is null!!"); + } + EventTriggerListener listener = go.GetComponent(); + + if (listener == null) + listener = go.AddComponent(); + return listener; + } + + private bool _IsValidTrigger() + { + return true; + } + + public override void OnPointerClick(PointerEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + + if (Input.touchCount > 1) + { + return; + } + OnClick?.Invoke(gameObject); + } + + public override void OnPointerDown(PointerEventData event_data) + { + if (!this._IsValidTrigger()) + { + return; + } + OnDown?.Invoke(gameObject, event_data); + } + + public override void OnPointerEnter(PointerEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + OnEnter?.Invoke(gameObject, event_data); + } + + public override void OnPointerExit(PointerEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + + OnExit?.Invoke(gameObject, event_data); + } + + public override void OnPointerUp(PointerEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + + OnUp?.Invoke(gameObject, event_data); + } + + public override void OnSelect(BaseEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + + OnSelectEvent?.Invoke(gameObject); + } + + public override void OnUpdateSelected(BaseEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + + OnUpdateSelect?.Invoke(gameObject); + } + + public override void OnBeginDrag(PointerEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + + OnDragBegin?.Invoke(gameObject, event_data); + } + + public override void OnDrag(PointerEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + + OnDragEvent?.Invoke(gameObject, event_data); + } + + public override void OnEndDrag(PointerEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + + OnDragEnd?.Invoke(gameObject, event_data); + } + + public override void OnDrop(PointerEventData event_data) + { + if (!_IsValidTrigger()) + { + return; + } + + OnDropEvent?.Invoke(gameObject, event_data); + } + + private void OnDestroy() + { + OnClick = null; + OnDown = null; + OnExit = null; + OnUp = null; + OnSelectEvent = null; + OnDragBegin = null; + OnDragEvent = null; + OnDragEnd = null; + OnEnter = null; + OnDropEvent = null; + OnDragEnd = null; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/EventTriggerListener.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/EventTriggerListener.cs.meta new file mode 100644 index 00000000..f026990a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/EventTriggerListener.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 82dee44fc47d40eca1d6896ae8d8fa44 +timeCreated: 1673948810 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/ImageBackGroundStretch.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/ImageBackGroundStretch.cs new file mode 100644 index 00000000..f71a86ec --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/ImageBackGroundStretch.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace TEngine +{ + /// + /// 背景图片等比拉伸。 + /// + public class ImageBackGroundStretch : MonoBehaviour + { + public float standardAspectValue = 9 / 16f; + + protected virtual void Start() + { + DoImageStretch(standardAspectValue); + } + + private void DoImageStretch(float standardAspect) + { + float deviceAspect = Screen.width / (float)Screen.height; + if (standardAspect > deviceAspect) + { + float scale = standardAspect / deviceAspect; + transform.localScale = new Vector3(scale, scale, 1f); + } + else if (standardAspect < deviceAspect) + { + float scale = deviceAspect / standardAspect; + transform.localScale = new Vector3(scale, scale, 1f); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/ImageBackGroundStretch.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/ImageBackGroundStretch.cs.meta new file mode 100644 index 00000000..6e6caf47 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/ImageBackGroundStretch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4e6e63472f81d39499f4bf79b27eaf44 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/PointerLongPress.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/PointerLongPress.cs new file mode 100644 index 00000000..33a28681 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/PointerLongPress.cs @@ -0,0 +1,154 @@ +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; + +namespace TEngine +{ + public class PointerLongPress : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler, IPointerClickHandler + { + public float durationThreshold = 1.0f; //触发长按的时间阈值 + public float startSpeed = 3; //开始速度 + public float addSpeed = 2; //加速度 + public float maxValue = 25; //最大值 + public float callIntervalTime = 0.05f; //调用间隔时间,时间为0只触发一次长按点击回调 + + private bool _isPointerDown = false; + private bool _longPressTriggered = false; + private bool _isGreaterMaxValue = false; //是否已经大于最大值 + private float _curTime = 0; + private float _curCallTime = 0; + + private OnLongPressEvent _onLongPress; + private UnityEvent _onClick; + + public UnityEvent onClick + { + get + { + if (_onClick == null) + { + _onClick = new UnityEvent(); + } + return _onClick; + } + } + + public OnLongPressEvent onLongPress + { + get + { + if (_onLongPress == null) + { + _onLongPress = new OnLongPressEvent(); + } + return _onLongPress; + } + } + + public static PointerLongPress Get(GameObject go) + { + PointerLongPress listener = go.GetComponent(); + if (listener == null) listener = go.AddComponent(); + return listener; + } + + public void SetLongPressParam(float durationThreshold, float startSpeed, float maxValue, float addSpeed, float callIntervalTime) + { + this.durationThreshold = durationThreshold; + this.startSpeed = startSpeed; + this.maxValue = maxValue; + this.addSpeed = addSpeed; + this.callIntervalTime = callIntervalTime; + } + + private void Update() + { + if (_isPointerDown) + { + if (!_longPressTriggered) + { + _curTime += GameTime.deltaTime; + if (_curTime >= durationThreshold) + { + _longPressTriggered = true; + _isGreaterMaxValue = false; + _curTime = 0; + _curCallTime = 0; + if (callIntervalTime <= 0) + { + onLongPress?.Invoke(0); + } + } + } + else if (callIntervalTime > 0) + { + _curTime += GameTime.deltaTime; + _curCallTime += GameTime.deltaTime; + if (_curCallTime >= callIntervalTime) + { + float value = 0; + if (_isGreaterMaxValue) + { + value = maxValue; + } + else + { + float curSpeed = (startSpeed + startSpeed + addSpeed * _curTime) * 0.5f; + value = curSpeed * _curTime; + if (value >= maxValue) + { + _isGreaterMaxValue = true; + value = maxValue; + } + } + + //TLogger.LogInfo("value:" + value + ",长按持续时间:" + _curTime); + _curCallTime = 0; + onLongPress?.Invoke(Mathf.FloorToInt(value)); + } + } + } + } + + private void OnEnable() + { + _isPointerDown = false; + _longPressTriggered = false; + _curTime = 0; + } + + public void OnPointerDown(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left) return; + _curTime = 0; + _isPointerDown = true; + _longPressTriggered = false; + } + + public void OnPointerUp(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left) return; + _isPointerDown = false; + } + + public void OnPointerExit(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left) return; + _isPointerDown = false; + } + + public void OnPointerClick(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left) return; + if (!_longPressTriggered) + { + onClick.Invoke(); + } + } + } + + public class OnLongPressEvent : UnityEvent + { + + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/PointerLongPress.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/PointerLongPress.cs.meta new file mode 100644 index 00000000..268f45e7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/PointerLongPress.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 65a01507196e4cd4b08fbebeb3228346 +timeCreated: 1673948810 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/SafeTop.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/SafeTop.cs new file mode 100644 index 00000000..edc737b6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/SafeTop.cs @@ -0,0 +1,36 @@ +using UnityEngine; +using TEngine; + +namespace TEngine +{ + public class SafeTop : MonoBehaviour + { + void Start() + { + var topRect = gameObject.transform as RectTransform; + CheckNotch(true); + if (topRect != null) + { + var anchoredPosition = topRect.anchoredPosition; + anchoredPosition = new Vector2(anchoredPosition.x, anchoredPosition.y - _notchHeight); + topRect.anchoredPosition = anchoredPosition; + } + } + + private static float _notchHeight; + + public static void CheckNotch(bool applyEditorNotch = true) + { +#if UNITY_EDITOR + _notchHeight = applyEditorNotch ? Screen.safeArea.y > 0f ? Screen.safeArea.y : Screen.currentResolution.height - Screen.safeArea.height : 0f; + if (_notchHeight < 0) + { + _notchHeight = 0; + } +#else + _notchHeight = Screen.safeArea.y > 0f ? Screen.safeArea.y : Screen.currentResolution.height - Screen.currentResolution.height; +#endif + Debug.Log($"CheckNotch :{_notchHeight}"); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/SafeTop.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/SafeTop.cs.meta new file mode 100644 index 00000000..cf1849a6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/SafeTop.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c0a563c3e931db74f94f9991270a2dee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/UIButtonScale.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/UIButtonScale.cs new file mode 100644 index 00000000..db2718ad --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/UIButtonScale.cs @@ -0,0 +1,150 @@ +#if USE_DOTWEEN +using DG.Tweening; +using UnityEngine; +using UnityEngine.EventSystems; + +[DisallowMultipleComponent] +public class UIButtonScale : MonoBehaviour, + IPointerUpHandler, + IPointerDownHandler, + IPointerEnterHandler, + IPointerExitHandler +{ + public GameObject tweenTarget; + public Vector3 pressedScale = new Vector3(0.95f, 0.95f, 0.95f); + public float duration = 0.1f; + public bool needRemoveAllTween = true; + private Vector3 _cacheScale; + private Tweener _tweener; + private bool _started = false; + private bool _pressed = false; + + void Start() + { + Init(); + } + + void Init() + { + if (!_started) + { + _started = true; + if (tweenTarget == null) tweenTarget = gameObject; + _cacheScale = tweenTarget.transform.localScale; + } + } + + public void OnDestroy() + { + if (_tweener is { active: true }) + { + _tweener.Kill(); + } + _tweener = null; + + if (tweenTarget != null) + { + tweenTarget.transform.localScale = _cacheScale; + } + } + + void OnEnable() + { + if (_started) + { + _pressed = false; + tweenTarget.transform.localScale = _cacheScale; + } + } + + void OnDisable() + { + if (_started) + { + if (tweenTarget != null) + { + if (needRemoveAllTween == false) + { + if (_tweener is { active: true }) + { + _tweener.Kill(); + } + _tweener = null; + } + tweenTarget.transform.localScale = _cacheScale; + } + } + } + + void OnPress(bool isPressed) + { + if (!_started) + { + Init(); + } + + if (enabled) + { + if (needRemoveAllTween == false) + { + if (_tweener is { active: true }) + { + _tweener.Kill(); + } + _tweener = null; + } + if (isPressed) + { + Vector3 destScale = new Vector3(pressedScale.x * _cacheScale.x, pressedScale.y * _cacheScale.y, pressedScale.z * _cacheScale.z); + + _tweener = tweenTarget.transform.DOScale(destScale, duration); + _tweener.SetUpdate(true); + } + else + { + _tweener = tweenTarget.transform.DOScale(_cacheScale, duration); + _tweener.SetUpdate(true); + } + } + } + + public void OnPointerUp(PointerEventData eventData) + { + _pressed = false; + OnPress(_pressed); + } + + public void OnPointerDown(PointerEventData eventData) + { + _pressed = true; + OnPress(_pressed); + } + + public void OnPointerEnter(PointerEventData eventData) + { + OnPress(_pressed); + } + + public void OnPointerExit(PointerEventData eventData) + { + OnPress(false); + } + + public void SetDefaultScale(Vector3 scale) + { + if (!_started) + { + Init(); + } + _cacheScale = scale; + if (needRemoveAllTween == false) + { + if (_tweener is { active: true }) + { + _tweener.Kill(); + } + _tweener = null; + } + } +} +#endif \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/UIButtonScale.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/UIButtonScale.cs.meta new file mode 100644 index 00000000..092fb0a7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/MonoExtend/UIButtonScale.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 95e66cfdf24a4c9d949625a7b449f54a +timeCreated: 1683804898 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper.meta new file mode 100644 index 00000000..0aea0984 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5d5f14034f8f4763b481911841c287d8 +timeCreated: 1673928618 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper/UIButtonSuper.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper/UIButtonSuper.cs new file mode 100644 index 00000000..8a9450dc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper/UIButtonSuper.cs @@ -0,0 +1,292 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.EventSystems; +using System; +using TEngine; +using UnityEngine.UI; + +#if UNITY_EDITOR +using UnityEditor; +using UnityEditor.UI; + +[CustomEditor(typeof(UIButtonSuper), true)] +[CanEditMultipleObjects] +public class UIButtonSuperEditor : ButtonEditor +{ + private SerializedProperty m_ButtonUISounds; + private SerializedProperty m_CanClick; + private SerializedProperty m_CanDoubleClick; + private SerializedProperty m_DoubleClickIntervalTime; + private SerializedProperty onDoubleClick; + + private SerializedProperty m_CanLongPress; + private SerializedProperty m_ResponseOnceByPress; + private SerializedProperty m_LongPressDurationTime; + private SerializedProperty onPress; + + protected override void OnEnable() + { + base.OnEnable(); + + m_ButtonUISounds = serializedObject.FindProperty("m_ButtonUISounds"); + m_CanClick = serializedObject.FindProperty("m_CanClick"); + m_CanDoubleClick = serializedObject.FindProperty("m_CanDoubleClick"); + m_DoubleClickIntervalTime = serializedObject.FindProperty("m_DoubleClickIntervalTime"); + onDoubleClick = serializedObject.FindProperty("onDoubleClick"); + + m_CanLongPress = serializedObject.FindProperty("m_CanLongPress"); + m_ResponseOnceByPress = serializedObject.FindProperty("m_ResponseOnceByPress"); + m_LongPressDurationTime = serializedObject.FindProperty("m_LongPressDurationTime"); + onPress = serializedObject.FindProperty("onPress"); + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + serializedObject.Update(); + EditorGUILayout.PropertyField(m_ButtonUISounds); //显示我们创建的属性 + EditorGUILayout.PropertyField(m_CanClick); //显示我们创建的属性 + EditorGUILayout.Space(); //空行 + EditorGUILayout.PropertyField(m_CanDoubleClick); //显示我们创建的属性 + EditorGUILayout.PropertyField(m_DoubleClickIntervalTime); //显示我们创建的属性 + EditorGUILayout.PropertyField(onDoubleClick); //显示我们创建的属性 + EditorGUILayout.Space(); //空行 + EditorGUILayout.PropertyField(m_CanLongPress); //显示我们创建的属性 + EditorGUILayout.PropertyField(m_ResponseOnceByPress); //显示我们创建的属性 + EditorGUILayout.PropertyField(m_LongPressDurationTime); //显示我们创建的属性 + EditorGUILayout.PropertyField(onPress); //显示我们创建的属性 + serializedObject.ApplyModifiedProperties(); + } +} + +#endif + +public enum ButtonSoundType +{ + Down, + Up, + Click, + Enter, + Exit, + Drag +} + +[Serializable] +public class ButtonSoundCell +{ + public ButtonSoundType ButtonSoundType = ButtonSoundType.Click; + public string ButtonUISoundName = "ui_click_button"; +} + +public delegate void ButtonBeginDragCallback(PointerEventData eventData); + +public delegate void ButtonDragCallback(PointerEventData eventData); + +public delegate void ButtonEndDragCallback(PointerEventData eventData); + +public class UIButtonSuper : Button, IBeginDragHandler, IDragHandler, IEndDragHandler +{ + public List m_ButtonUISounds = new List() { new ButtonSoundCell() }; + [Tooltip("是否可以点击")] public bool m_CanClick = true; + [Tooltip("是否可以双击")] public bool m_CanDoubleClick = false; + [Tooltip("双击间隔时长")] public float m_DoubleClickIntervalTime = 0.1f; + [Tooltip("双击事件")] public ButtonClickedEvent onDoubleClick; + [Tooltip("是否可以长按")] public bool m_CanLongPress = false; + [Tooltip("长按是否只响应一次")] public bool m_ResponseOnceByPress = false; + [Tooltip("长按满足间隔")] public float m_LongPressDurationTime = 1; + + [Tooltip("长按事件")] public ButtonClickedEvent onPress; + + //public ButtonClickedEvent onClick; + public ButtonBeginDragCallback onBeginDrag; + public ButtonDragCallback onDrag; + public ButtonEndDragCallback onEndDrag; + + private bool isDown = false; + private bool isPress = false; + private bool isDownExit = false; + private float downTime = 0; + + private int fingerId = int.MinValue; + + public bool IsDraging + { + get { return fingerId != int.MinValue; } + } //摇杆拖拽状态 + + public int FingerId + { + get { return fingerId; } + } + + private float clickIntervalTime = 0; + private int clickTimes = 0; + + void Update() + { + if (isDown) + { + if (!m_CanLongPress) + { + return; + } + + if (m_ResponseOnceByPress && isPress) + { + return; + } + + downTime += GameTime.deltaTime; + if (downTime > m_LongPressDurationTime) + { + isPress = true; + onPress.Invoke(); + } + } + + if (clickTimes >= 1) + { + if (!m_CanLongPress && !m_CanDoubleClick && m_CanClick) + { + onClick.Invoke(); + clickTimes = 0; + } + else + { + clickIntervalTime += GameTime.deltaTime; + if (clickIntervalTime >= m_DoubleClickIntervalTime) + { + if (clickTimes >= 2) + { + if (m_CanDoubleClick) + { + onDoubleClick.Invoke(); + } + } + else + { + if (m_CanClick) + { + onClick.Invoke(); + } + } + + clickTimes = 0; + clickIntervalTime = 0; + } + } + } + } + + /// + /// 是否按钮按下 + /// + public bool IsDown + { + get { return isDown; } + } + + /// + /// 是否按钮长按 + /// + public bool IsPress + { + get { return isPress; } + } + + /// + /// 是否按钮按下后离开按钮位置 + /// + public bool IsDownExit + { + get { return isDownExit; } + } + + public ButtonSoundCell GetButtonSound(ButtonSoundType buttonSoundType) + { + foreach (var buttonSound in m_ButtonUISounds) + { + if (buttonSound.ButtonSoundType == buttonSoundType) + { + return buttonSound; + } + } + + return null; + } + + private void PlayButtonSound(ButtonSoundType buttonSoundType) + { + ButtonSoundCell buttonSound = GetButtonSound(buttonSoundType); + if (buttonSound == null) + { + return; + } + + GameModule.Audio.Play(TEngine.AudioType.Sound, buttonSound.ButtonUISoundName); + } + + public override void OnPointerEnter(PointerEventData eventData) + { + base.OnPointerEnter(eventData); + PlayButtonSound(ButtonSoundType.Enter); + } + + public override void OnPointerDown(PointerEventData eventData) + { + base.OnPointerDown(eventData); + if (eventData.pointerId < -1 || IsDraging) return; //适配 Touch:只响应一个Touch;适配鼠标:只响应左键 + fingerId = eventData.pointerId; + isDown = true; + isDownExit = false; + downTime = 0; + PlayButtonSound(ButtonSoundType.Down); + } + + public override void OnPointerUp(PointerEventData eventData) + { + base.OnPointerUp(eventData); + if (fingerId != eventData.pointerId) return; //正确的手指抬起时才会; + fingerId = int.MinValue; + isDown = false; + isDownExit = true; + PlayButtonSound(ButtonSoundType.Up); + } + + public override void OnPointerExit(PointerEventData eventData) + { + base.OnPointerExit(eventData); + if (fingerId != eventData.pointerId) return; //正确的手指抬起时才会; + isPress = false; + isDownExit = true; + PlayButtonSound(ButtonSoundType.Exit); + } + + public override void OnPointerClick(PointerEventData eventData) + { + if (!isPress) + { + clickTimes += 1; + } + else + isPress = false; + + PlayButtonSound(ButtonSoundType.Click); + } + + public void OnBeginDrag(PointerEventData eventData) + { + onBeginDrag?.Invoke(eventData); + } + + public void OnDrag(PointerEventData eventData) + { + PlayButtonSound(ButtonSoundType.Drag); + onDrag?.Invoke(eventData); + } + + public void OnEndDrag(PointerEventData eventData) + { + onEndDrag?.Invoke(eventData); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper/UIButtonSuper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper/UIButtonSuper.cs.meta new file mode 100644 index 00000000..e0896e44 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIButtonSuper/UIButtonSuper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fa4f44179d534f148b96822ead9e9b8f +timeCreated: 1673928618 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIExtension.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIExtension.cs new file mode 100644 index 00000000..5063d621 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIExtension.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections; +using UnityEngine; +using UnityEngine.UI; +using TEngine; + +public static class UIExtension +{ + public static IEnumerator FadeToAlpha(this CanvasGroup canvasGroup, float alpha, float duration, + Action callback = null) + { + float time = 0f; + float originalAlpha = canvasGroup.alpha; + while (time < duration) + { + time += GameTime.deltaTime; + canvasGroup.alpha = Mathf.Lerp(originalAlpha, alpha, time / duration); + yield return new WaitForEndOfFrame(); + } + + canvasGroup.alpha = alpha; + + callback?.Invoke(); + } + + public static IEnumerator SmoothValue(this Slider slider, float value, float duration, Action callback = null) + { + float time = 0f; + float originalValue = slider.value; + while (time < duration) + { + time += GameTime.deltaTime; + slider.value = Mathf.Lerp(originalValue, value, time / duration); + yield return new WaitForEndOfFrame(); + } + + slider.value = value; + + callback?.Invoke(); + } + + public static IEnumerator SmoothValue(this Scrollbar slider, float value, float duration, Action callback = null) + { + float time = 0f; + float originalValue = slider.size; + while (time < duration) + { + time += GameTime.deltaTime; + slider.size = Mathf.Lerp(originalValue, value, time / duration); + yield return new WaitForEndOfFrame(); + } + + slider.size = value; + + callback?.Invoke(); + } + + public static IEnumerator SmoothValue(this Image image, float value, float duration, Action callback = null) + { + float time = 0f; + float originalValue = image.fillAmount; + while (time < duration) + { + time += GameTime.deltaTime; + image.fillAmount = Mathf.Lerp(originalValue, value, time / duration); + yield return new WaitForEndOfFrame(); + } + + image.fillAmount = value; + + callback?.Invoke(); + } + + public static bool GetMouseDownUiPos(this UIModule uiModule, out Vector3 screenPos) + { + bool hadMouseDown = false; + Vector3 mousePos = Vector3.zero; + +#if UNITY_EDITOR || PLATFORM_STANDALONE_WIN + mousePos = Input.mousePosition; + hadMouseDown = Input.GetMouseButton(0); +#else + if (Input.touchCount > 0) + { + mousePos = Input.GetTouch(0).position; + hadMouseDown = true; + } + else + { + hadMouseDown = false; + } +#endif + + RectTransformUtility.ScreenPointToLocalPointInRectangle( + uiModule.UIRoot as RectTransform, + mousePos, + uiModule.UICamera, out var pos); + screenPos = uiModule.UIRoot.TransformPoint(pos); + + return hadMouseDown; + } + + /// + /// 对字符串加自定义颜色格式 + /// + /// + /// + /// + public static string ToColor(this string desc, string color) + { + return $"{desc}"; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIExtension.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIExtension.cs.meta new file mode 100644 index 00000000..919259ed --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UGUIExtension/UIExtension.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5fc9b6461d924067bae00595fdf0c65c +timeCreated: 1695287404 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UnityExtension.cs b/EintooAR/Assets/TEngine/Runtime/Extension/UnityExtension.cs new file mode 100644 index 00000000..f5d282e4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UnityExtension.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using Cysharp.Threading.Tasks; +using UnityEngine; +using UnityEngineInternal; + +namespace TEngine +{ + /// + /// Unity 的扩展方法辅助类。 + /// + public static class UnityExtension + { + /// + /// 获取或增加组件。 + /// + /// 要获取或增加的组件。 + /// 目标对象。 + /// 获取或增加的组件。 + public static T GetOrAddComponent(this GameObject gameObject) where T : Component + { + T component = gameObject.GetComponent(); + + if (component == null) + { + component = gameObject.AddComponent(); + } + + + return component; + } + + /// + /// 获取或增加组件。 + /// + /// 目标对象。 + /// 要获取或增加的组件类型。 + /// 获取或增加的组件。 + public static Component GetOrAddComponent(this GameObject gameObject, Type type) + { + Component component = gameObject.GetComponent(type); + + if (component == null) + { + component = gameObject.AddComponent(type); + } + + return component; + } + + /// + /// 移除组件。 + /// + /// 目标对象。 + /// 要获取或增加的组件类型。 + /// + [TypeInferenceRule(TypeInferenceRules.TypeReferencedByFirstArgument)] + public static void RemoveMonoBehaviour(this GameObject gameObject, Type type) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + + Component component = gameObject.GetComponent(type); + + if (component != null) + { + UnityEngine.Object.Destroy(component); + } + } + + /// + /// 移除组件。 + /// + /// 目标对象。 + /// 要获取或增加的组件类型。 + public static void RemoveMonoBehaviour(this GameObject gameObject) where T : Component + { + T component = gameObject.GetComponent(); + + if (component != null) + { + UnityEngine.Object.Destroy(component); + } + } + + /// + /// 获取 GameObject 是否在场景中。 + /// + /// 目标对象。 + /// GameObject 是否在场景中。 + /// 若返回 true,表明此 GameObject 是一个场景中的实例对象;若返回 false,表明此 GameObject 是一个 Prefab。 + public static bool InScene(this GameObject gameObject) + { + return gameObject.scene.name != null; + } + + private static readonly List CachedTransforms = new List(); + + /// + /// 递归设置游戏对象的层次。 + /// + /// 对象。 + /// 目标层次的编号。 + public static void SetLayerRecursively(this GameObject gameObject, int layer) + { + gameObject.GetComponentsInChildren(true, CachedTransforms); + for (int i = 0; i < CachedTransforms.Count; i++) + { + CachedTransforms[i].gameObject.layer = layer; + } + + CachedTransforms.Clear(); + } + + /// + /// ActivatesDeactivates the GameObject, depending on the given true or false/ value. + /// + /// GameObject. + /// Activate or deactivate the object, where true activates the GameObject and false deactivates the GameObject. + /// Cache Activate or deactivate the object, where true activates the GameObject and false deactivates the GameObject. + public static void SetActive(this GameObject go, bool value, ref bool cacheValue) + { + if (go != null && value != cacheValue) + { + cacheValue = value; + go.SetActive(value); + } + } + + /// + /// 查找子节点。 + /// + /// 位置组件。 + /// 子节点路径。 + /// 位置组件。 + public static Transform FindChild(this Transform transform, string path) + { + var findTrans = transform.Find(path); + return findTrans != null ? findTrans : null; + } + + /// + /// 根据名字找到子节点,主要用于dummy接口。 + /// + /// 位置组件。 + /// 子节点名字。 + /// 位置组件。 + public static Transform FindChildByName(this Transform transform, string name) + { + if (transform == null) + { + return null; + } + + for (int i = 0; i < transform.childCount; i++) + { + var childTrans = transform.GetChild(i); + if (childTrans.name == name) + { + return childTrans; + } + + var find = FindChildByName(childTrans, name); + if (find != null) + { + return find; + } + } + + return null; + } + + [TypeInferenceRule(TypeInferenceRules.TypeReferencedByFirstArgument)] + public static Component FindChildComponent(this Transform transform, string path, Type type) + { + var findTrans = transform.Find(path); + if (findTrans != null) + { + return findTrans.gameObject.GetComponent(type); + } + + return null; + } + + public static T FindChildComponent(this Transform transform, string path) where T : Component + { + var findTrans = transform.Find(path); + if (findTrans != null) + { + return findTrans.gameObject.GetComponent(); + } + + return null; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Extension/UnityExtension.cs.meta b/EintooAR/Assets/TEngine/Runtime/Extension/UnityExtension.cs.meta new file mode 100644 index 00000000..4b5350d2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Extension/UnityExtension.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7eae68e7c4794af7ad73bd0b7a2eb424 +timeCreated: 1694831452 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Libraries.meta b/EintooAR/Assets/TEngine/Runtime/Libraries.meta new file mode 100644 index 00000000..58432775 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Libraries.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ab303e72d9fdd0840aaaa9e4c4358163 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Libraries/System.Runtime.CompilerServices.Unsafe.dll b/EintooAR/Assets/TEngine/Runtime/Libraries/System.Runtime.CompilerServices.Unsafe.dll new file mode 100644 index 0000000000000000000000000000000000000000..491a80a97880de93aa893f6974c5f76891d2de73 GIT binary patch literal 18024 zcmeHu2V7Ij()gYv^bR73lu%RzffEn}5v7VqZ&DN?K|L=UDi^Q96;bhrdRV0tWI=}-VAB>8=dGnaPy)`3>p#r9WkTy_ch15rOkka9G zhL-?zNGL+NAxFwjq$nR=ppPGiU|h~~5K<-o^`#<|;Dx6M+6^W$&OnzUGNQ)_p(H}c z7=#odDS^DMsOWDcbg}3pyDZ=!lK8RYv$FYsJ?{^I4lglQkX!PhL+_Sc9ybn%q-@TR zk%m_XUWvyUq_^a<(m23K$V$jewnc|j;&DdERRSfmCy054hmeheq>#@bghr_$Bu7&F zKmc7hwSANy=N?>r93ZeeeChV>1+fpFKO5zLkec&M-9cX0se7k$qlx$3PlJ}UPsj3V z=c-yzu#IodwMw^A)F(RK4BWA#_|>D`P1Mw1ud3JCom^+vJ#Mr9hO~H#5ZxKAJ)>#7 zn6=-EHn!|Nd&ogH>Pz9rS8~%En+z16Jfbdjyf`eqJF4q!Ps(f!978f9(I`_ega(=+ zf+pWf>rux<D)O@N55| z-Co+C>J#K2wJV}yVpXRABNf(%2K+D@HHy5n88OD*tw5Cj2p6w$PTw4mx=+d~oSEy9 z;m{UUxF>!7@YiFW^t|EQmcpY$)Jf7egMPx>e6lKm0&e~wcr z!t&nZ4D=Nft_QKhg%8lEKcGqV(!}fDznQE|tU<3{_9yjHVxO6UHp>h5nRs1Lz(K$S%Ex>#O2pw1t?+!S7cYr`a!S2C&JMJxJ zvj)0v-(YtAz^7#u&>C_dIf*$bI*Y?ioy3^Lo5bYulM|S6eBLBZY|5nI93G#QZW)xx z<|n7KEZsQi8OdoZZZL~GH93yOvkYbPmijvO!==i1{E; zV*QA`6}*1%s=(_8FF})hjYT*@Pcec{)HH+BQW^!2FdwlYzm9~bNO+HgA4#Z&5v9XO z=s`jjHW`yf(?}>F;X)FYl5iIZ>oB7Idt`nJZ8FUt%^|iwJVFVGIV`|b(Ey4(Vn80K zfYB-T6bHzglUNXx5!f&iOAuieBsPOm44f1g`(R{3OTwDyMAM~c3uPwMcrL>B0Y*Vz z#MoTW?|z0t&Xbg4*zKkw>>gm!$XSe)!77D|uvSV1%oAUX{Q{>=i3t0ZvL7j;}?6Z$+3cl=Vk6BcWuv)Ej63(iLG=)Q4~@!Nu4M zWPsd7*jOktLX*VU3p5DvMOXy24Vj|ZB5X3X0}VyX#n@NSfK6gf8O$8*6Jczs8a51_ z6JgoZ0hk497Goxu73vaW78nDmlIm58vZ?l%4KfvB^Qjh?EwUG5_SgtCPK0fQHXTrm z7&E~fQMMSfz?@Kt7_-O5psgZo2ej#e4v8^)%nh9rVRckD%mdvKVRxv0m?wHG!rlPp zg%F%DgoYrRALfnvi7<6q1m=rOMVKy)iTNRW0z-w`<3S_*kk22m=s#dtVk`~n6^b!w zlc2fQf&jE#kZjki9&I{`bd4%~J6biH{S(l(wkvf&=rH}K!Lvet*LV0>?{l8Hr zkurQgUcQ)4LDT=6`7#N9$^8GkoeR)11zjcEZzl6E{xUBdmkmu0jfa_511JqUbUd62 zh9n$HLIw#P0IDDtGVevgKoUj()I>P|_0SZ6(r6wDR{`utp`%DF7+Hd!GK^}8CL$kz zj%Yc>5=}!o02PoiKpT_WmoXc$08)Bw;8Jpky9)Tqv6%P}O3 zLve7L=9Bqy5^e-aINFGEq4$l52mPNQ>8Hs2DU#kyQV>Q+NGG8)31di@Pr`B%o*-c} z2@!?lC!sS5V@Q}!!g3OxAYn5J5tZa8p)(0%NLWt7W)dPA$wR^z5|)$j1PPl-h@?m! z5;~L6T`CqNpDmq2LZXx=BZLHnCQIgJ$x;y{C_z*mM9UXiS=h|5?g(+Q5j4^!69n=x zMoO>;g%1_|LguAJsf;L<6Qv5GR7sSoh*C9Csv$}>MX45<(%{?{wreg*Ekvmmil-7% zS)mlrUTv_WLOvT&YAZ@dh*Aep>L^N`MClk&>LNd^r6GxnI1=8?kspUGns8>UHlFgSDH=@?!H@i7alPh#u*&toV3Ip?#C%xEvlQfe+3?Jj;d6 zOv~XV^AOP@3PC(hCO3{nVxdr!oXBRyqcCnVXkR>w$4_RHDuSjGGb*I_u@UPD+7`e` z1}V5GI5j!Li=E6z!O6KS{{)!Gj2yV$$EBj!96rm91LNwW^|eA&5wd~D!sWZf$8%Xc z9ukxLI9+&%1N{ZD5>UukE+-v@gm7R|V>#J~c%dc&KPR2V=KCik@K}6;;tE}hFhUAZ zHaIhu&jp_f^=2g4B(faP)?_vUu|PAB3zrqlOlP4qRstW9dJGFA64#T<0#)ILB!PB_ zi9Rq65ydYvEsc=7Hx1!3**szgj!k2Nx8xFy|4pUpWphtvCbBuOKyf_e&Wg=UO#GuV z32C4_a2Bz^9i!68vq@IVVJq{)BG*k@JwA_4RfRwW9m8ay5F;|mQgjNYtW0Dn6n!KG zshW%IrD+=9E?Ybd9E_1J9|eU_lw8u%I9a}#Y5e4jG!_u#yx2)BLTlm?jX0-)cXlda zKK`0lMis;KkqRbERi$KAF$$&vBr>BarH|x<6jf0UQWXpefeEriH6o?KKxAbR6{sqh z9Fb9#Qk9aEAt}OCRZ2=un(R%Ns7|&6Z4(*zC#On*9Dxu`LZT}V{R+!u30a7SW&3E_ zec1s-R$ItQWJR@zc8DzWNpwJ!)}s*9sYl5#CvNAoeDIfHo}>vY3V2Yk3xf#A5Z#aNFYOa@d)V?!i7-!hjE!1 zaE5tg$FWEg5R$~@WbrUH3@O?{gut3%X=`oGfIy!-hNK7zWX&-&_)q8CPeK3`q zrJo0EaoBA{7^K%0fDD=#QV_*D2z{r8aN$@Ysb0JgZgP6M1a&xutWIvDi_bs08;6_0 zfg>HvmL;7IDoiJLF^>)h4#ZDb@s0%)vB0?xW+_x}Q zS+rXehbAbEM4nFMzJGe-)qN$=Aff?jOtm zY(3zBPZ9ZlWF%uS2-NaBI>ASLI|z4%Z%42nd!IwJ;gFpGK0`D>4-^DBFYtW*0QUko zmh^%Vs-?B}2=C9*=>0`as3VL#juACPG)ZiE$;TZK3|eI(F0_*jhb#-)WTOPIcEn>s z91LKpxxm3jJSb-(KJak>6F$3X+Q5Q=OkkLxgpCq^&{7BK_u(*Z;ooo+OUwcEGX(0o zL3`=&$Aa2?=!N)>lmjUrDCyv>1))r`B$?zPye@)2LnJR)f8gVyses2pjt4bDfu9Gm zCIC)6J`nfm?I(jAOAgE&lWdPD_a*Ccp+;zIpxCa zFkvnGX5gPGt0jtuwuuNWq2!j(uMhN@NcKpqTn4Nyp(%+d3FZr-Z7|n=fBr3j+l6eO zF3}1Ps9bU-gqi?1Naz`%JaXLrB2Gd(iE;PNA%PKE_s`Wg$?-eGDS$!zm(Z+u(Be24 zao?=}Nbh#RNGyTJ19lxk0`NNjT>sB2-@EQOjCDA&C)b??F^o8PneaCP{#dZzh>}=% z69C$foEFbS8IGb{TE8h1xoL5fixQz&?b~qDc~Py*uWJ)W1*rh!}i#< zXkw)(8bq@qVKGGzDUYFm%Sls1Y0?^$&|roJu0|lT8uDRGUJ^KUd=8tTiYpUD84Z~r zR(v{#9na9mbqR{R#*c5X3{!kCQBKt`5MN{AP8`po2ZP%WtFRRe%-4(qi)|0;~Y7iO6t$ zxP$pZ*D!a(=z#_oZ>?N5VnFA)nR~y^pc z67bpEoBP&=}E7@>>o4NsCA=>pVN+8 zEfzfm(JL0xnjGbCygp;F&#HWWsjR}v!0fyB+s;&IufES&yC8*8^Zw>i`L#Ca;PZ<1 z0Ns-lxtBCP21&&%_MO~3@5%83?>9Pg1Ps5~C-#wF8i$CnSZhYJ6kYvUh^Ut>p?vJ=TifxpdG;5q%^yIdJ zoZP2*?p?f2&F2dbZgn}?s267$H|=`(jge}Z&JVp+KlS*SGw;?O{P?x2OLt2~zOLd| z_eg)aiu?VPTE@?=-i)qIIXAl87@ZNazfJ_#b&!Gn;$8i|_@qPrWl!nr9yW!T>Hs(a) zU?Y^sn2;#H-#B*sivX$Xg6&!(Mi}i+-+CdFvH}kwx-_8q;@-Gdxo5dYp<5E4pE1(P zDl03?GF==ti{qqQWuzu^GI&;T+%zlLJFsbB%fN0SHcK=CEbtK)xVzsy_AL-NX;HFB2m7CfZ+rQMp+4 zq_`E`Ahg{PtSLp?mr3xVp7&CF*Z?j%Ii{dUnsqHo0P3 z5I63mMNwUuX8xY!6|eP&z01t9lAV8g{4Q!VHIH>uUt3MNBWh{M8P_+_@9*oX*K2N> z-u~jrf}KOhtQ)uWMeYQnO984$s~ax;8p&I~w5$5Eb(X(X&ALZLDW@+U71W1Zm>#~e zWv|SQuf|v31g6LoSLr{U-gr9W__^V3ug)F7HuV_RC}*VJ$}TxPZ$?|=GP5iv%>I1t zqJxjS9~W3y-rVmu4+SjD^J9LNFLFwHwP9Ma-;;ECH)U^Y)4hvsy!H&c+GSplbJ=vw zP^laPQw|INP;9@$=J3vx#j>1PHkb15be>;5r_?%ui%+Tf?E>}W^t}&#hMqH`#oTUj z(A_;%`jDI~C-JuH%l;Q#j=o#_VfV$-RPV}x(>rvQsbuck@7Ybm z1v0s~Kq^*fapalGCD+I+0aa326u{6F6#Yw1aFvHmKiGcxQid zmGtg&4mYuW4A<-Plyc(d<}HsgNvmG(wYD{B^0ming7?Y~J5_ymoB6I>x$4`c5f@@~ zq*@cEzOoJ)tZvovi)_G^8ux=ycTQVUGk;0?a54SE$VnCbJH{SqwvXSzj= z)Amj)9C&y1o`q4b=K0Uod0$}_@w~**VwX+$nS-NytgqKlo%ZalUTU9rZC(DbPQM9D z3~dLUa$v{L3_h|}W#<6n*%v#GPzx7*jDFV?RJU;X++!yU`GcahO%GfeVroCA%wfFU zmFaty?$R}`+LrK^X^`^7)N5UI(bGXu*A2Z#2c6y@HpYbd?rQEttDDBpGNM!h$7a=Z zp(n?7Pz2HUPiWTE4!jZS-QrN8(rWB=O#6`gbdTrtr?|Pz+!m9^bz@hZX+NnOc7N8Q zx4vF@)h~-5zn!?D`pd)J2~X=+7EEiq)#lyeHMB~@bW7EY#Qc}@W3!|8TFt&4wsulo zmZ|A)ZRw{>i-#3EkMOU5GRJ-1X*r)WH#WOj@mG9gcV*MVhiOE`tXMtT-)8o`-9=iD z*86po?mjlQJgw|n^R1$V3ccpA4a{LHt|~1jx>RanG`RO63H$d$V>Ccqp&x~&s4ouz zl}vE++>i@-E7DV;5zQ3hD&n(W3a5ez_=B0_T8yMHO56_jlk$7=y6P?ZdbH!yZV zcmVF#i-WOq{VQW<71wL&{-S+8Ua)}>o=z)Ri5D!#3zmo{$&!i}%)-a?c1OYb+x%5` zgz=8&#PO^$AV|#Q=EP<2ER*=@xU;wc3O-!lnyx1iCy6HGPHALRDhJ|xL@bPmyb=Dl zFiK`g*ONRF;6Np^&B7bO8$alo#(cVACm9K)fw4tUKz!jT{2_A*nrSGic6ZC9@;TN}tc_I8ppztofraj!m_;?d(CjUQ`chYkK%Wxq6l9 z$}(SNCx!R2^KKcOveth3?u(Q{0^yIR=5%ZGRoT`KTQ_fP-TQD=z(Sk7=z6lB^YJ5AN6wlPk6q3xoBsNUW%YLD?-i3u@1R>1V{0QmtlTW;Jx+C1zCjZjdS=g>&0{>W^lcli zRaS1u%{A&Cx5D6;&z{Elo$I^mQV)8seEKFcTj%ZT5vy{vy}#Y6F;2>SS>63*!5fAA z*U666U+^}X&*I0AGt=XiI9**g!Oy=gKg_5iTg}=qx7|g4&zR3!FKvpduP9m*Hf4g} zIFA#q=hsY~D4#zr^=r--wx=bx9av(T0L!=h zcptyFC;Vac?go29&-1JI^UQv25Nx^mEi6!xCcE>4-r2TKd7Bsh-Zg=u>9DtM;8HtV zwf76(-&L1s+p>7zwc%Us9^F?u{NVid!p07C;B2hU#KNOHil(kD`DpBzcI3*3^*vF) z_q3e;_;Am(O=qb z)E=3ahSs%w#+_zj4a3cATj!Kzu3wllZB8xsT=jN+HZ{6kd(PrrY8wvu&wPs87W2wz zp8_f~7YEz6wDgRb`PAZ6Ef>oy4vd&2O;5X<^~k*EaFLc@gFDtb=HT<$Gt7QliDJ5= ztfS|*Y_MAJS=DK^jaAc}T{}Y?eZn~gJu}8D$><$2n=>voxA>mUvWv4l*Y50Ox^L`X zoL5}haVsELwcl2^I(k=Tij|3rUB!v2koXeKXV+@tCvM1_rCn?EF8tzw81{4eqbZl> zEI(T8cq^gE+-3gGa!1zVTeDYxc-*%9(o><6)!44(lv zb~P4gP2`<-pHcTBNPVu0)cN|`zs@@)x4q~7lnWGTW{Uo?*DBf?L@)!Q86)63rLDES zCC;#p#A*2ytfRc3X;Z;vyx_vWHm@m5RHtgq1QJ75)zBzPdFKW0-TvOOzzD|z1IGfx(8q7t)ta;CU%k3>%G6cwmwBtwChn}9 zeDYZ3m$HFL+fshj_AvByU$RKX+Awep=hogRs>s6BRsGU7n(|_E7iRq%=dt>;g9(^-qd7?x(%lVYxemd2D6%!7Eq#-z@Qw zQ|$2=nB1{zQOd{>e=?f z!Py1^vl}Lj8(N+>R8i|0ca{`}3$`7gS-hx_TD7nCQQVT$M@oJ6CV9DGe*Rf`fkEMY5ULd z9t~mygJ_Dld~X+2**|Sx2$W(dLA|uTW{AQK>-q~X1eeXCZ#`)kJhry|n2Gc6ziL#T zOE~6v_w}W0`|e$fhW@TK!}7qPGjdg_$A=spXY2m>+r)CKr-wWhR6<|5rJSBOc+63@ zfD!)<1%C<1oZz@!u0$s>TdT#P(ADd}5s@f8ou9c_JBA2JG%5dGnWLa)>LZAbnMl;ds}1uxG%F|qP}JsIK2zY+)+E< z)z>-js>)jF(TOuV6HZV|-SgU;yuY$vtiG^k>-$_YdB(eYe$q=06v^7Y%GTZ8y6W<% z7AyB7RUHrFYd2x_bh%~Om%ki4ao#;@a{slMl)sU0?@9F%PO7JW83Op>(ezIV0o?q3 z!o}iOm6KwVt~xC*nRvT#wf5=%>7gff(M5-zorSf{KkLx@N!#H1mlNk4{ATVO4Vl(<3&(+e_&By9ESW#j_Ha@TWERFKlPHcv&)(XleE4~`ZQU~w#;OLH^1Fg^;~t` z%!ZloN6d&Eqx*hU&iExksM=mdtJ5l{fOU7<{?zAZ8-Kr$i#Xo6yNS`LD{a)xrNt3L zj~)0*dy=uidi;>Dq19GB2VN|;IT{u-=s_+ONpKN@XUCHC4-+jyd5xp zO5D0>hUur)Zmb;DJ#$8BN=f#X^lMMne$xA5e`k3|!)E!?!cDd7b#~EQXC2y~zsAU( zzJJh*__rTB>hj_u2C3v)I)qKFoU&bdzRJA*N0?P=7gyg=_FSERrs;B3Q~Qir@18hL zk$W7)FEf&5-rF6Z&#C?G33}YZklD0s zcKF>hJ+x=r{nEWvu9fGn3~=#nF8pM+dZStbe*Gxl+WT?bw9ZxYtp=Votd7{f>w){I zl>t+3S6n+2`YicTSpC&U_=&HVUiyAks*Cb(U8g_5-s;$ua4E}nrSbsVd+l;VbZ^$= z+3L$4xo3C(dUWw4evy}Yg@DosAz}EG48DI?#s58bqS9C%h9)B|Wv)!6=ukD$TysI` z5#5L$b;Hw<(=n}^+G%eb${{vakiRMK-)yfWzKlspA&L}wVSJ_qH_}!S`+vC2@ZlpO z#RT~FKoamQI9!A=4sbSU7{dy#dh((Mh+wWf018F@It2o-GGt!OOvo@uE0JKZlc-K1 zzPyWrCWQA&DVN7(iE31t3VKCv9xE)DyqbW>)Pe#udr8jV_>p0yGyQz(!{kP_J~MpU z{b2_0*(tv=hYXFzVcHMpA32s-Q1Vo&cCGz@8*lP9exAR8H!OA9Jg?G#_OjJhm(n#J zIw)P37_t4ev6j(S)yX50j^Va5JqE~pTerbHTtS6b*YtHmZ)(JyNn zsMp?kUksWxR|YFMTGNyil9Be=>*n-`07->}xBvuW(A~~C@8?&of4DaEU}xoxQGw>C zx%LhnN0nuR8#PZlyTum|Uzy`!@y)uh-^-^yd$wI%dV7Fi&u?)DAH|~P_phe8&N!2$ zo1M@^ODOP+?~ZV;k-qM3wkO*2=Ki#r)Sl9a6(KltUQj|FO7HDEe@XNX0o zkyd2If%>6Sq9S!8*n@V|s-JR^TK?>MRokP5I<<`rYX__4)IX-_zdUSS@cgoybio_D zd#|214{m)PsJ1GLIfZvI!~2rU=A%ij(); + ret.AssetOperationHandle = assetOperationHandle; + ret.InPool = inPool; + ret.InitFromPool(); + return ret; + } + + internal static void DeAlloc(AudioData audioData) + { + if (audioData != null) + { + MemoryPool.Release(audioData); + audioData.RecycleToPool(); + } + } + } + + /// + /// 音频代理辅助器。 + /// + public class AudioAgent + { + private int _instanceId; + private AudioSource _source; + private AudioData _audioData; + private AudioModuleImp _audioModuleImp; + private Transform _transform; + float _volume = 1.0f; + float _duration; + private float _fadeoutTimer; + private const float FadeoutDuration = 0.2f; + private bool _inPool; + + /// + /// 音频代理辅助器运行时状态。 + /// + AudioAgentRuntimeState _audioAgentRuntimeState = AudioAgentRuntimeState.None; + + /// + /// 音频代理加载请求。 + /// + class LoadRequest + { + public string Path; + public bool BAsync; + public bool BInPool; + } + + /// + /// 音频代理加载请求。 + /// + LoadRequest _pendingLoad = null; + + /// + /// AudioSource实例化Id + /// + public int InstanceId => _instanceId; + + /// + /// 资源操作句柄。 + /// + public AudioData AudioData => _audioData; + + /// + /// 音频代理辅助器音频大小。 + /// + public float Volume + { + set + { + if (_source != null) + { + _volume = value; + _source.volume = _volume; + } + } + get => _volume; + } + + /// + /// 音频代理辅助器当前是否空闲。 + /// + public bool IsFree + { + get + { + if (_source != null) + { + return _audioAgentRuntimeState == AudioAgentRuntimeState.End; + } + else + { + return true; + } + } + } + + /// + /// 音频代理辅助器播放秒数。 + /// + public float Duration => _duration; + + /// + /// 音频代理辅助器当前音频长度。 + /// + public float Length + { + get + { + if (_source != null && _source.clip != null) + { + return _source.clip.length; + } + + return 0; + } + } + + /// + /// 音频代理辅助器实例位置。 + /// + public Vector3 Position + { + get => _transform.position; + set => _transform.position = value; + } + + /// + /// 音频代理辅助器是否循环。 + /// + public bool IsLoop + { + get + { + if (_source != null) + { + return _source.loop; + } + else + { + return false; + } + } + set + { + if (_source != null) + { + _source.loop = value; + } + } + } + + /// + /// 音频代理辅助器是否正在播放。 + /// + internal bool IsPlaying + { + get + { + if (_source != null && _source.isPlaying) + { + return true; + } + else + { + return false; + } + } + } + + /// + /// 音频代理辅助器获取当前声源。 + /// + /// + public AudioSource AudioResource() + { + return _source; + } + + /// + /// 创建音频代理辅助器。 + /// + /// 生效路径。 + /// 是否异步。 + /// 音频轨道(类别)。 + /// 是否池化。 + /// 音频代理辅助器。 + public static AudioAgent Create(string path, bool bAsync, AudioCategory audioCategory, bool bInPool = false) + { + AudioAgent audioAgent = new AudioAgent(); + audioAgent.Init(audioCategory); + audioAgent.Load(path, bAsync, bInPool); + return audioAgent; + } + + /// + /// 初始化音频代理辅助器。 + /// + /// 音频轨道(类别)。 + /// 音频代理辅助器编号。 + public void Init(AudioCategory audioCategory, int index = 0) + { + _audioModuleImp = ModuleImpSystem.GetModule(); + GameObject host = new GameObject(Utility.Text.Format("Audio Agent Helper - {0} - {1}", audioCategory.AudioMixerGroup.name, index)); + host.transform.SetParent(audioCategory.InstanceRoot); + host.transform.localPosition = Vector3.zero; + _transform = host.transform; + _source = host.AddComponent(); + _source.playOnAwake = false; + AudioMixerGroup[] audioMixerGroups = + audioCategory.AudioMixer.FindMatchingGroups(Utility.Text.Format("Master/{0}/{1}", audioCategory.AudioMixerGroup.name, + $"{audioCategory.AudioMixerGroup.name} - {index}")); + _source.outputAudioMixerGroup = audioMixerGroups.Length > 0 ? audioMixerGroups[0] : audioCategory.AudioMixerGroup; + _source.rolloffMode = audioCategory.AudioGroupConfig.audioRolloffMode; + _source.minDistance = audioCategory.AudioGroupConfig.minDistance; + _source.maxDistance = audioCategory.AudioGroupConfig.maxDistance; + _instanceId = _source.GetInstanceID(); + } + + /// + /// 加载音频代理辅助器。 + /// + /// 资源路径。 + /// 是否异步。 + /// 是否池化。 + public void Load(string path, bool bAsync, bool bInPool = false) + { + _inPool = bInPool; + if (_audioAgentRuntimeState == AudioAgentRuntimeState.None || _audioAgentRuntimeState == AudioAgentRuntimeState.End) + { + _duration = 0; + if (!string.IsNullOrEmpty(path)) + { + if (bInPool && _audioModuleImp.AudioClipPool.TryGetValue(path, out var operationHandle)) + { + OnAssetLoadComplete(operationHandle); + return; + } + + if (bAsync) + { + _audioAgentRuntimeState = AudioAgentRuntimeState.Loading; + AssetHandle handle = GameModule.Resource.LoadAssetAsyncHandle(path); + handle.Completed += OnAssetLoadComplete; + } + else + { + AssetHandle handle = GameModule.Resource.LoadAssetGetOperation(path); + OnAssetLoadComplete(handle); + } + } + } + else + { + _pendingLoad = new LoadRequest { Path = path, BAsync = bAsync, BInPool = bInPool }; + + if (_audioAgentRuntimeState == AudioAgentRuntimeState.Playing) + { + Stop(true); + } + } + } + + /// + /// 停止播放音频代理辅助器。 + /// + /// 是否渐出。 + public void Stop(bool fadeout = false) + { + if (_source != null) + { + if (fadeout) + { + _fadeoutTimer = FadeoutDuration; + _audioAgentRuntimeState = AudioAgentRuntimeState.FadingOut; + } + else + { + _source.Stop(); + _audioAgentRuntimeState = AudioAgentRuntimeState.End; + } + } + } + + /// + /// 暂停音频代理辅助器。 + /// + public void Pause() + { + if (_source != null) + { + _source.Pause(); + } + } + + /// + /// 取消暂停音频代理辅助器。 + /// + public void UnPause() + { + if (_source != null) + { + _source.UnPause(); + } + } + + /// + /// 资源加载完成。 + /// + /// 资源操作句柄。 + void OnAssetLoadComplete(AssetHandle handle) + { + if (handle != null) + { + if (_inPool) + { + _audioModuleImp.AudioClipPool.TryAdd(handle.GetAssetInfo().Address, handle); + } + } + + if (_pendingLoad != null) + { + if (!_inPool && handle != null) + { + handle.Dispose(); + } + + _audioAgentRuntimeState = AudioAgentRuntimeState.End; + string path = _pendingLoad.Path; + bool bAsync = _pendingLoad.BAsync; + bool bInPool = _pendingLoad.BInPool; + _pendingLoad = null; + Load(path, bAsync, bInPool); + } + else if (handle != null) + { + if (_audioData != null) + { + AudioData.DeAlloc(_audioData); + _audioData = null; + } + + _audioData = AudioData.Alloc(handle, _inPool); + + _source.clip = handle.AssetObject as AudioClip; + if (_source.clip != null) + { + _source.Play(); + _audioAgentRuntimeState = AudioAgentRuntimeState.Playing; + } + else + { + _audioAgentRuntimeState = AudioAgentRuntimeState.End; + } + } + else + { + _audioAgentRuntimeState = AudioAgentRuntimeState.End; + } + } + + /// + /// 轮询音频代理辅助器。 + /// + /// 逻辑流逝时间,以秒为单位。 + public void Update(float elapseSeconds) + { + if (_audioAgentRuntimeState == AudioAgentRuntimeState.Playing) + { + if (!_source.isPlaying) + { + _audioAgentRuntimeState = AudioAgentRuntimeState.End; + } + } + else if (_audioAgentRuntimeState == AudioAgentRuntimeState.FadingOut) + { + if (_fadeoutTimer > 0f) + { + _fadeoutTimer -= elapseSeconds; + _source.volume = _volume * _fadeoutTimer / FadeoutDuration; + } + else + { + Stop(); + if (_pendingLoad != null) + { + string path = _pendingLoad.Path; + bool bAsync = _pendingLoad.BAsync; + bool bInPool = _pendingLoad.BInPool; + _pendingLoad = null; + Load(path, bAsync, bInPool); + } + + _source.volume = _volume; + } + } + + _duration += elapseSeconds; + } + + /// + /// 销毁音频代理辅助器。 + /// + public void Destroy() + { + if (_transform != null) + { + Object.Destroy(_transform.gameObject); + } + + if (_audioData != null) + { + AudioData.DeAlloc(_audioData); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgent.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgent.cs.meta new file mode 100644 index 00000000..1b0c8d41 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d4824a14181a0d4d921eb98fec100fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgentRuntimeState.cs b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgentRuntimeState.cs new file mode 100644 index 00000000..bf682575 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgentRuntimeState.cs @@ -0,0 +1,33 @@ +namespace TEngine +{ + /// + /// 音频代理辅助器运行时状态枚举。 + /// + public enum AudioAgentRuntimeState + { + /// + /// 无状态。 + /// + None, + + /// + /// 加载中状态。 + /// + Loading, + + /// + /// 播放中状态。 + /// + Playing, + + /// + /// 渐渐消失状态。 + /// + FadingOut, + + /// + /// 结束状态。 + /// + End, + }; +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgentRuntimeState.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgentRuntimeState.cs.meta new file mode 100644 index 00000000..59ab5a21 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioAgentRuntimeState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f4ad4b8dc4cf4ecd813e58ec37406ba0 +timeCreated: 1694849619 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioCategory.cs b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioCategory.cs new file mode 100644 index 00000000..3bca12e3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioCategory.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Audio; + +namespace TEngine +{ + /// + /// 音频轨道(类别)。 + /// + [Serializable] + public class AudioCategory + { + [SerializeField] private AudioMixer audioMixer = null; + public List AudioAgents; + private readonly AudioMixerGroup _audioMixerGroup; + private AudioGroupConfig _audioGroupConfig; + private int _maxChannel; + private bool _bEnable = true; + + /// + /// 音频混响器。 + /// + public AudioMixer AudioMixer => audioMixer; + + /// + /// 音频混响器组。 + /// + public AudioMixerGroup AudioMixerGroup => _audioMixerGroup; + + /// + /// 音频组配置。 + /// + public AudioGroupConfig AudioGroupConfig => _audioGroupConfig; + + /// + /// 实例化根节点。 + /// + public Transform InstanceRoot { private set; get; } + + /// + /// 音频轨道是否启用。 + /// + public bool Enable + { + get => _bEnable; + set + { + if (_bEnable != value) + { + _bEnable = value; + if (!_bEnable) + { + foreach (var audioAgent in AudioAgents) + { + if (audioAgent != null) + { + audioAgent.Stop(); + } + } + } + } + } + } + + /// + /// 音频轨道构造函数。 + /// + /// 最大Channel。 + /// 音频混响器。 + /// 音频轨道组配置。 + public AudioCategory(int maxChannel, AudioMixer audioMixer, AudioGroupConfig audioGroupConfig) + { + this.audioMixer = audioMixer; + _maxChannel = maxChannel; + _audioGroupConfig = audioGroupConfig; + AudioMixerGroup[] audioMixerGroups = audioMixer.FindMatchingGroups(Utility.Text.Format("Master/{0}", audioGroupConfig.AudioType.ToString())); + if (audioMixerGroups.Length > 0) + { + _audioMixerGroup = audioMixerGroups[0]; + } + else + { + _audioMixerGroup = audioMixer.FindMatchingGroups("Master")[0]; + } + + AudioAgents = new List(32); + InstanceRoot = new GameObject(Utility.Text.Format("Audio Category - {0}", _audioMixerGroup.name)).transform; + InstanceRoot.SetParent(GameModule.Audio.InstanceRoot); + for (int index = 0; index < _maxChannel; index++) + { + AudioAgent audioAgent = new AudioAgent(); + audioAgent.Init(this, index); + AudioAgents.Add(audioAgent); + } + } + + /// + /// 增加音频。 + /// + /// + public void AddAudio(int num) + { + _maxChannel += num; + for (int i = 0; i < num; i++) + { + AudioAgents.Add(null); + } + } + + /// + /// 播放音频。 + /// + /// + /// + /// + /// + public AudioAgent Play(string path, bool bAsync, bool bInPool = false) + { + if (!_bEnable) + { + return null; + } + + int freeChannel = -1; + float duration = -1; + + for (int i = 0; i < AudioAgents.Count; i++) + { + if (AudioAgents[i].AudioData?.AssetOperationHandle == null || AudioAgents[i].IsFree) + { + freeChannel = i; + break; + } + else if (AudioAgents[i].Duration > duration) + { + duration = AudioAgents[i].Duration; + freeChannel = i; + } + } + + if (freeChannel >= 0) + { + if (AudioAgents[freeChannel] == null) + { + AudioAgents[freeChannel] = AudioAgent.Create(path, bAsync, this, bInPool); + } + else + { + AudioAgents[freeChannel].Load(path, bAsync, bInPool); + } + + return AudioAgents[freeChannel]; + } + else + { + Log.Error($"Here is no channel to play audio {path}"); + return null; + } + } + + /// + /// 暂停音频。 + /// + /// 是否渐出 + public void Stop(bool fadeout) + { + for (int i = 0; i < AudioAgents.Count; ++i) + { + if (AudioAgents[i] != null) + { + AudioAgents[i].Stop(fadeout); + } + } + } + + /// + /// 音频轨道轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + public void Update(float elapseSeconds) + { + for (int i = 0; i < AudioAgents.Count; ++i) + { + if (AudioAgents[i] != null) + { + AudioAgents[i].Update(elapseSeconds); + } + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioCategory.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioCategory.cs.meta new file mode 100644 index 00000000..04711aac --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioCategory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6aefbd5a06fe1784590d373a93d1cf8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioGroupConfig.cs b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioGroupConfig.cs new file mode 100644 index 00000000..c6a67270 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioGroupConfig.cs @@ -0,0 +1,48 @@ +using System; +using UnityEngine; + +namespace TEngine +{ + /// + /// 音频轨道组配置。 + /// + [Serializable] + public sealed class AudioGroupConfig + { + [SerializeField] private string m_Name = null; + + [SerializeField] private bool m_Mute = false; + + [SerializeField, Range(0f, 1f)] private float m_Volume = 1f; + + [SerializeField] private int m_AgentHelperCount = 1; + + public AudioType AudioType; + + public AudioRolloffMode audioRolloffMode = AudioRolloffMode.Logarithmic; + + public float minDistance = 1f; + + public float maxDistance = 500f; + + public string Name + { + get { return m_Name; } + } + + public bool Mute + { + get { return m_Mute; } + } + + public float Volume + { + get { return m_Volume; } + } + + public int AgentHelperCount + { + get { return m_AgentHelperCount; } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioGroupConfig.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioGroupConfig.cs.meta new file mode 100644 index 00000000..2a2bb7c8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioGroupConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 067935df275fd1340a935f81e7f3a768 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModule.cs new file mode 100644 index 00000000..c1c8a6f6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModule.cs @@ -0,0 +1,216 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Audio; + +namespace TEngine +{ + /// + /// 音效管理,为游戏提供统一的音效播放接口。 + /// + /// 场景3D音效挂到场景物件、技能3D音效挂到技能特效上,并在AudioSource的Output上设置对应分类的AudioMixerGroup + public class AudioModule : Module + { + [SerializeField] private AudioMixer m_AudioMixer; + + [SerializeField] private Transform m_InstanceRoot = null; + + [SerializeField] private AudioGroupConfig[] m_AudioGroupConfigs = null; + + public IAudioModule AudioModuleImp; + + #region Public Propreties + + /// + /// 音频混响器。 + /// + public AudioMixer MAudioMixer => m_AudioMixer; + + /// + /// 实例化根节点。 + /// + public Transform InstanceRoot + { + get => m_InstanceRoot; + set => m_InstanceRoot = value; + } + + /// + /// 总音量控制。 + /// + public float Volume + { + get => AudioModuleImp.Volume; + set => AudioModuleImp.Volume = value; + } + + /// + /// 总开关。 + /// + public bool Enable + { + get => AudioModuleImp.Enable; + set => AudioModuleImp.Enable = value; + } + + /// + /// 音乐音量。 + /// + public float MusicVolume + { + get => AudioModuleImp.MusicVolume; + set => AudioModuleImp.MusicVolume = value; + } + + /// + /// 音效音量。 + /// + public float SoundVolume + { + get => AudioModuleImp.SoundVolume; + set => AudioModuleImp.SoundVolume = value; + } + + /// + /// UI音效音量。 + /// + public float UISoundVolume + { + get => AudioModuleImp.UISoundVolume; + set => AudioModuleImp.UISoundVolume = value; + } + + /// + /// 语音音量。 + /// + public float VoiceVolume + { + get => AudioModuleImp.VoiceVolume; + set => AudioModuleImp.VoiceVolume = value; + } + + /// + /// 音乐开关 + /// + public bool MusicEnable + { + get => AudioModuleImp.MusicEnable; + set => AudioModuleImp.MusicEnable = value; + } + + /// + /// 音效开关。 + /// + public bool SoundEnable + { + get => AudioModuleImp.SoundEnable; + set => AudioModuleImp.SoundEnable = value; + } + + /// + /// UI音效开关。 + /// + public bool UISoundEnable + { + get => AudioModuleImp.UISoundEnable; + set => AudioModuleImp.UISoundEnable = value; + } + + /// + /// 语音开关。 + /// + public bool VoiceEnable + { + get => AudioModuleImp.VoiceEnable; + set => AudioModuleImp.VoiceEnable = value; + } + + #endregion + + /// + /// 初始化音频模块。 + /// + void Start() + { + if (AudioModuleImp == null) + { + AudioModuleImp = ModuleImpSystem.GetModule(); + } + + if (m_InstanceRoot == null) + { + m_InstanceRoot = new GameObject("AudioModule Instances").transform; + m_InstanceRoot.SetParent(gameObject.transform); + m_InstanceRoot.localScale = Vector3.one; + } + + AudioModuleImp.Initialize(m_AudioGroupConfigs, m_InstanceRoot, m_AudioMixer); + } + + /// + /// 重启音频模块。 + /// + public void Restart() + { + AudioModuleImp.Restart(); + } + + /// + /// 播放,如果超过最大发声数采用fadeout的方式复用最久播放的AudioSource。 + /// + /// 声音类型 + /// 声音文件路径 + /// 是否循环播放> + /// 音量(0-1.0) + /// 是否异步加载 + /// 是否支持资源池 + public AudioAgent Play(AudioType type, string path, bool bLoop = false, float volume = 1.0f, bool bAsync = false, bool bInPool = false) + { + return AudioModuleImp.Play(type, path, bLoop, volume, bAsync, bInPool); + } + + /// + /// 停止某类声音播放。 + /// + /// 声音类型。 + /// 是否渐消。 + public void Stop(AudioType type, bool fadeout) + { + AudioModuleImp.Stop(type, fadeout); + } + + /// + /// 停止所有声音。 + /// + /// 是否渐消。 + public void StopAll(bool fadeout) + { + AudioModuleImp.StopAll(fadeout); + } + + /// + /// 预先加载AudioClip,并放入对象池。 + /// + /// AudioClip的AssetPath集合。 + public void PutInAudioPool(List list) + { + AudioModuleImp.PutInAudioPool(list); + } + + /// + /// 将部分AudioClip从对象池移出。 + /// + /// AudioClip的AssetPath集合。 + public void RemoveClipFromPool(List list) + { + AudioModuleImp.RemoveClipFromPool(list); + } + + /// + /// 清空AudioClip的对象池。 + /// + public void CleanSoundPool() + { + AudioModuleImp.CleanSoundPool(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModule.cs.meta new file mode 100644 index 00000000..0ad9335f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d0b3cff83fd3874394b1b456bb54dab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModuleImp.cs b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModuleImp.cs new file mode 100644 index 00000000..932ce21f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModuleImp.cs @@ -0,0 +1,560 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; +using UnityEngine.Audio; +using YooAsset; + +namespace TEngine +{ + [UpdateModule] + internal class AudioModuleImp : ModuleImp, IAudioModule + { + private AudioMixer _audioMixer; + private Transform _instanceRoot = null; + private AudioGroupConfig[] _audioGroupConfigs = null; + + private float _volume = 1f; + private bool _enable = true; + private readonly AudioCategory[] _audioCategories = new AudioCategory[(int)AudioType.Max]; + private readonly float[] _categoriesVolume = new float[(int)AudioType.Max]; + public readonly Dictionary AudioClipPool = new Dictionary(); + private bool _bUnityAudioDisabled = false; + + #region Public Propreties + + /// + /// 音频混响器。 + /// + public AudioMixer AudioMixer => _audioMixer; + + /// + /// 实例化根节点。 + /// + public Transform InstanceRoot => _instanceRoot; + + /// + /// 总音量控制。 + /// + public float Volume + { + get + { + if (_bUnityAudioDisabled) + { + return 0.0f; + } + + return _volume; + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + _volume = value; + AudioListener.volume = _volume; + } + } + + /// + /// 总开关。 + /// + public bool Enable + { + get + { + if (_bUnityAudioDisabled) + { + return false; + } + + return _enable; + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + _enable = value; + AudioListener.volume = _enable ? _volume : 0f; + } + } + + /// + /// 音乐音量。 + /// + public float MusicVolume + { + get + { + if (_bUnityAudioDisabled) + { + return 0.0f; + } + + return _categoriesVolume[(int)AudioType.Music]; + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + float volume = Mathf.Clamp(value, 0.0001f, 1.0f); + _categoriesVolume[(int)AudioType.Music] = volume; + _audioMixer.SetFloat("MusicVolume", Mathf.Log10(volume) * 20f); + } + } + + /// + /// 音效音量。 + /// + public float SoundVolume + { + get + { + if (_bUnityAudioDisabled) + { + return 0.0f; + } + + return _categoriesVolume[(int)AudioType.Sound]; + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + float volume = Mathf.Clamp(value, 0.0001f, 1.0f); + _categoriesVolume[(int)AudioType.Sound] = volume; + _audioMixer.SetFloat("SoundVolume", Mathf.Log10(volume) * 20f); + } + } + + /// + /// UI音效音量。 + /// + public float UISoundVolume + { + get + { + if (_bUnityAudioDisabled) + { + return 0.0f; + } + + return _categoriesVolume[(int)AudioType.UISound]; + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + float volume = Mathf.Clamp(value, 0.0001f, 1.0f); + _categoriesVolume[(int)AudioType.UISound] = volume; + _audioMixer.SetFloat("UISoundVolume", Mathf.Log10(volume) * 20f); + } + } + + /// + /// 语音音量。 + /// + public float VoiceVolume + { + get + { + if (_bUnityAudioDisabled) + { + return 0.0f; + } + + return _categoriesVolume[(int)AudioType.Voice]; + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + float volume = Mathf.Clamp(value, 0.0001f, 1.0f); + _categoriesVolume[(int)AudioType.Voice] = volume; + _audioMixer.SetFloat("VoiceVolume", Mathf.Log10(volume) * 20f); + } + } + + /// + /// 音乐开关 + /// + public bool MusicEnable + { + get + { + if (_bUnityAudioDisabled) + { + return false; + } + + if (_audioMixer.GetFloat("MusicVolume", out var db)) + { + return db > -80f; + } + else + { + return false; + } + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + _audioCategories[(int)AudioType.Music].Enable = value; + + // 音乐采用0音量方式,避免恢复播放时的复杂逻辑 + if (value) + { + _audioMixer.SetFloat("MusicVolume", Mathf.Log10(_categoriesVolume[(int)AudioType.Music]) * 20f); + } + else + { + _audioMixer.SetFloat("MusicVolume", -80f); + } + } + } + + /// + /// 音效开关。 + /// + public bool SoundEnable + { + get + { + if (_bUnityAudioDisabled) + { + return false; + } + + return _audioCategories[(int)AudioType.Sound].Enable; + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + _audioCategories[(int)AudioType.Sound].Enable = value; + } + } + + /// + /// UI音效开关。 + /// + public bool UISoundEnable + { + get + { + if (_bUnityAudioDisabled) + { + return false; + } + + return _audioCategories[(int)AudioType.UISound].Enable; + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + _audioCategories[(int)AudioType.UISound].Enable = value; + } + } + + /// + /// 语音开关。 + /// + public bool VoiceEnable + { + get + { + if (_bUnityAudioDisabled) + { + return false; + } + + return _audioCategories[(int)AudioType.Voice].Enable; + } + set + { + if (_bUnityAudioDisabled) + { + return; + } + + _audioCategories[(int)AudioType.Voice].Enable = value; + } + } + + #endregion + + internal override void Shutdown() + { + StopAll(fadeout: false); + CleanSoundPool(); + } + + /// + /// 初始化音频模块。 + /// + /// 音频轨道组配置。 + /// 实例化根节点。 + /// 音频混响器。 + /// + public void Initialize(AudioGroupConfig[] audioGroupConfigs, Transform instanceRoot = null,AudioMixer audioMixer = null) + { + if (_instanceRoot == null) + { + _instanceRoot = instanceRoot; + } + + if (audioGroupConfigs == null) + { + throw new GameFrameworkException("AudioGroupConfig[] is invalid."); + } + + _audioGroupConfigs = audioGroupConfigs; + + if (_instanceRoot == null) + { + _instanceRoot = new GameObject("AudioModule Instances").transform; + _instanceRoot.SetParent(GameModule.Audio.transform); + _instanceRoot.localScale = Vector3.one; + GameModule.Audio.InstanceRoot = _instanceRoot; + } + + try + { +#if UNITY_EDITOR + TypeInfo typeInfo = typeof(AudioSettings).GetTypeInfo(); + PropertyInfo propertyInfo = typeInfo.GetDeclaredProperty("unityAudioDisabled"); + _bUnityAudioDisabled = (bool)propertyInfo.GetValue(null); + if (_bUnityAudioDisabled) + { + return; + } +#endif + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + + if (audioMixer != null) + { + _audioMixer = audioMixer; + } + + if (_audioMixer == null) + { + _audioMixer = Resources.Load("AudioMixer"); + } + + for (int index = 0; index < (int)AudioType.Max; ++index) + { + AudioType audioType = (AudioType)index; + AudioGroupConfig audioGroupConfig = _audioGroupConfigs.First(t => t.AudioType == audioType); + _audioCategories[index] = new AudioCategory(audioGroupConfig.AgentHelperCount, _audioMixer, audioGroupConfig); + _categoriesVolume[index] = audioGroupConfig.Volume; + } + } + + /// + /// 重启音频模块。 + /// + public void Restart() + { + if (_bUnityAudioDisabled) + { + return; + } + + CleanSoundPool(); + + for (int i = 0; i < (int)AudioType.Max; ++i) + { + var audioCategory = _audioCategories[i]; + if (audioCategory != null) + { + for (int j = 0; j < audioCategory.AudioAgents.Count; ++j) + { + var audioAgent = audioCategory.AudioAgents[j]; + if (audioAgent != null) + { + audioAgent.Destroy(); + audioAgent = null; + } + } + } + + audioCategory = null; + } + + Initialize(_audioGroupConfigs); + } + + /// + /// 播放,如果超过最大发声数采用fadeout的方式复用最久播放的AudioSource。 + /// + /// 声音类型 + /// 声音文件路径 + /// 是否循环播放> + /// 音量(0-1.0) + /// 是否异步加载 + /// 是否支持资源池 + public AudioAgent Play(AudioType type, string path, bool bLoop = false, float volume = 1.0f, bool bAsync = false, bool bInPool = false) + { + if (_bUnityAudioDisabled) + { + return null; + } + + AudioAgent audioAgent = _audioCategories[(int)type].Play(path, bAsync, bInPool); + { + if (audioAgent != null) + { + audioAgent.IsLoop = bLoop; + audioAgent.Volume = volume; + } + + return audioAgent; + } + } + + /// + /// 停止某类声音播放。 + /// + /// 声音类型。 + /// 是否渐消。 + public void Stop(AudioType type, bool fadeout) + { + if (_bUnityAudioDisabled) + { + return; + } + + _audioCategories[(int)type].Stop(fadeout); + } + + /// + /// 停止所有声音。 + /// + /// 是否渐消。 + public void StopAll(bool fadeout) + { + if (_bUnityAudioDisabled) + { + return; + } + + for (int i = 0; i < (int)AudioType.Max; ++i) + { + if (_audioCategories[i] != null) + { + _audioCategories[i].Stop(fadeout); + } + } + } + + /// + /// 预先加载AudioClip,并放入对象池。 + /// + /// AudioClip的AssetPath集合。 + public void PutInAudioPool(List list) + { + if (_bUnityAudioDisabled) + { + return; + } + + foreach (string path in list) + { + if (AudioClipPool != null && !AudioClipPool.ContainsKey(path)) + { + AssetHandle assetData = GameModule.Resource.LoadAssetGetOperation(path); + AudioClipPool?.Add(path, assetData); + } + } + } + + /// + /// 将部分AudioClip从对象池移出。 + /// + /// AudioClip的AssetPath集合。 + public void RemoveClipFromPool(List list) + { + if (_bUnityAudioDisabled) + { + return; + } + + foreach (string path in list) + { + if (AudioClipPool.ContainsKey(path)) + { + AudioClipPool[path].Dispose(); + AudioClipPool.Remove(path); + } + } + } + + /// + /// 清空AudioClip的对象池。 + /// + public void CleanSoundPool() + { + if (_bUnityAudioDisabled) + { + return; + } + + foreach (var dic in AudioClipPool) + { + dic.Value.Dispose(); + } + + AudioClipPool.Clear(); + } + + /// + /// 音频模块轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + foreach (var audioCategory in _audioCategories) + { + if (audioCategory != null) + { + audioCategory.Update(elapseSeconds); + } + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModuleImp.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModuleImp.cs.meta new file mode 100644 index 00000000..c67de972 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioModuleImp.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c35bbf6a82844c72b71b9bbe44f44a1e +timeCreated: 1694847017 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioType.cs b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioType.cs new file mode 100644 index 00000000..918d1a77 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioType.cs @@ -0,0 +1,34 @@ +namespace TEngine +{ + /// + /// 音效分类,可分别关闭/开启对应分类音效。 + /// + /// 命名与AudioMixer中分类名保持一致。 + public enum AudioType + { + /// + /// 声音音效。 + /// + Sound, + + /// + /// UI声效。 + /// + UISound, + + /// + /// 背景音乐音效。 + /// + Music, + + /// + /// 人声音效。 + /// + Voice, + + /// + /// 最大。 + /// + Max + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioType.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioType.cs.meta new file mode 100644 index 00000000..2353c7c9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/AudioType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b4b86f93180273b4996d4f8c428def09 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/IAudioModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/IAudioModule.cs new file mode 100644 index 00000000..e02edcf0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/IAudioModule.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Audio; + +namespace TEngine +{ + public interface IAudioModule + { + /// + /// 总音量控制。 + /// + public float Volume { get; set; } + + /// + /// 总开关。 + /// + public bool Enable { get; set; } + + /// + /// 音乐音量 + /// + public float MusicVolume { get; set; } + + /// + /// 音效音量。 + /// + public float SoundVolume { get; set; } + + /// + /// UI音效音量。 + /// + public float UISoundVolume { get; set; } + + /// + /// 语音音量。 + /// + public float VoiceVolume { get; set; } + + /// + /// 音乐开关。 + /// + public bool MusicEnable { get; set; } + + /// + /// 音效开关。 + /// + public bool SoundEnable { get; set; } + + /// + /// UI音效开关。 + /// + public bool UISoundEnable { get; set; } + + /// + /// 语音开关。 + /// + public bool VoiceEnable { get; set; } + + /// + /// 初始化音频模块。 + /// + /// 音频轨道组配置。 + /// 实例化根节点。 + /// 音频混响器。 + /// + public void Initialize(AudioGroupConfig[] audioGroupConfigs, Transform instanceRoot = null, AudioMixer audioMixer = null); + + /// + /// 重启音频模块。 + /// + public void Restart(); + + /// + /// 播放音频接口。 + /// + /// 如果超过最大发声数采用fadeout的方式复用最久播放的AudioSource。 + /// 声音类型。 + /// 声音文件路径。 + /// 是否循环播放。> + /// 音量(0-1.0)。 + /// 是否异步加载。 + /// 是否支持资源池。 + public AudioAgent Play(AudioType type, string path, bool bLoop = false, float volume = 1.0f, bool bAsync = false, bool bInPool = false); + + /// + /// 停止某类声音播放。 + /// + /// 声音类型。 + /// 是否渐消。 + public void Stop(AudioType type, bool fadeout); + + /// + /// 停止所有声音。 + /// + /// 是否渐消。 + public void StopAll(bool fadeout); + + /// + /// 预先加载AudioClip,并放入对象池。 + /// + /// AudioClip的AssetPath集合。 + public void PutInAudioPool(List list); + + /// + /// 将部分AudioClip从对象池移出。 + /// + /// AudioClip的AssetPath集合。 + public void RemoveClipFromPool(List list); + + /// + /// 清空AudioClip的对象池。 + /// + public void CleanSoundPool(); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/IAudioModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/IAudioModule.cs.meta new file mode 100644 index 00000000..cd3170b9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/IAudioModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f2a332020228453d8546d5d74aa60f9c +timeCreated: 1694847151 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources.meta new file mode 100644 index 00000000..270c429b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 64a654fc0d761c24e9676a185ea4df8e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources/AudioMixer.mixer b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources/AudioMixer.mixer new file mode 100644 index 00000000..284455cc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources/AudioMixer.mixer @@ -0,0 +1,708 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!244 &-8255999005317483048 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 5256fbc85eb3f884eb780f730c8da825 + m_EffectName: Attenuation + m_MixLevel: 989fcb1cc28d4de4ea6e56c14101e674 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &-8165904320333843496 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 6b8ac75d99b7e57489701e084ea19b1f + m_EffectName: Attenuation + m_MixLevel: b19e64315aff6dc4a81ae36b22fc0492 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &-7861682458482441818 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: dcc48474d251d554e9f6f95668853a39 + m_EffectName: Receive + m_MixLevel: e6248274fab455749bc046d72eace6de + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!243 &-7758028812591520460 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Sound - 2 + m_AudioMixer: {fileID: 24100000} + m_GroupID: 039cd795affa7134a8d5f5d43d3b659d + m_Children: [] + m_Volume: 2a8ce0f3383c3f0468a04fa3fc5e317d + m_Pitch: b47f0c73299cd9b4fba9896e70683903 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -3825599753161013374} + m_UserColorIndex: 2 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!243 &-6280614258348125054 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Sound - 1 + m_AudioMixer: {fileID: 24100000} + m_GroupID: c0d40106c2ffb1a44bd48f50b210ee20 + m_Children: [] + m_Volume: f62a8b3fe89df00409532af739ee4e02 + m_Pitch: 77212647508232a458ac7d48fb55d037 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -1890011256548497850} + m_UserColorIndex: 2 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &-4958177229083455073 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 104113b95764fe344a5d25469377c800 + m_EffectName: Attenuation + m_MixLevel: 9ef29befaad178d4386e9d5ac022f964 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!243 &-4372808504093502661 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Sound - 3 + m_AudioMixer: {fileID: 24100000} + m_GroupID: 5f20d1b8f9ac1914dac8beae718e7d40 + m_Children: [] + m_Volume: e54edf7c1bf7ee44297e65adce5b10b7 + m_Pitch: 8542b6bfd7b7bfc4d9b961ba97edf0d2 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: 6637688299338053042} + m_UserColorIndex: 2 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!243 &-4209890294574411305 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Music + m_AudioMixer: {fileID: 24100000} + m_GroupID: efe8591c00084024187b9df78858c0af + m_Children: + - {fileID: 1543978434442340687} + m_Volume: 6d4c2b8bc0ef38d44b2fbff2b3298ab4 + m_Pitch: 862389c428a73854ab442dd043008729 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: 246003612463095956} + m_UserColorIndex: 1 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &-3825599753161013374 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: d1bbcc7cbe0a53c459c9064925118e41 + m_EffectName: Attenuation + m_MixLevel: e43bb5de098a2ec49807913fa5fdd2f7 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!243 &-3720557753501792270 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: UISound - 1 + m_AudioMixer: {fileID: 24100000} + m_GroupID: e012b6d2e0501df43a88eb6beff8ae07 + m_Children: [] + m_Volume: 265eaf7c8910ab842a845c7bb5e570c4 + m_Pitch: bf3ca9b57c9a67b40944a59839b12f62 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: 5734415080786067514} + m_UserColorIndex: 3 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!243 &-3395020342500439107 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Voice + m_AudioMixer: {fileID: 24100000} + m_GroupID: 5117f9b5a365ec049a9d5891c563b893 + m_Children: + - {fileID: -1649243360580130678} + m_Volume: fe15a1b40c14ea646a13dacb15b6a73b + m_Pitch: 3398197a464677a4186e0cecd66bb13c + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -8165904320333843496} + m_UserColorIndex: 6 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!243 &-2659745067392564156 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Sound - 0 + m_AudioMixer: {fileID: 24100000} + m_GroupID: 71c50c6b966d1f548a63193919ebfbad + m_Children: [] + m_Volume: 7835f2c4248cb3e43a1a773bab1f8b9d + m_Pitch: 30975daa872456b41bc18e0277e301e6 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -284252157345190109} + m_UserColorIndex: 2 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &-1890011256548497850 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 520975c71ea21c249b3cdf1f22032e57 + m_EffectName: Attenuation + m_MixLevel: 932e3e893621c5b46bff3c368017e689 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!243 &-1649243360580130678 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Voice - 0 + m_AudioMixer: {fileID: 24100000} + m_GroupID: f46651e8ad3c6034b8764fd635dda3fd + m_Children: [] + m_Volume: 0bc64c1c6cebbeb40ba2f724fdcaa257 + m_Pitch: fff252bdd985513469f8607e016fc594 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -890847686165078200} + m_UserColorIndex: 6 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &-998299258853400712 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: d7d19927abbe5584080506164cb4e644 + m_EffectName: Attenuation + m_MixLevel: 0b4264524e3eafc49b2daba7fba2ce97 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &-890847686165078200 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 4b41d8aa7a7944041a8b9428add83eff + m_EffectName: Attenuation + m_MixLevel: 73b7a9825978be245a1962a1001b0212 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &-284252157345190109 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 15668b74147caee41a72f695c3a2de56 + m_EffectName: Attenuation + m_MixLevel: f71e84fb9a62ff24cad690a0a86cc47e + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &-21257493329335984 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: c9a6f7a9214534644bf2e6d83ff86569 + m_EffectName: Distortion + m_MixLevel: 3f356cddae5dba949a6e8f4d20564d3e + m_Parameters: + - m_ParameterName: Level + m_GUID: 080be1914d960974481df4bebe2a2d77 + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!241 &24100000 +AudioMixerController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: AudioMixer + m_OutputGroup: {fileID: 0} + m_MasterGroup: {fileID: 24300002} + m_Snapshots: + - {fileID: 24500006} + m_StartSnapshot: {fileID: 24500006} + m_SuspendThreshold: -80 + m_EnableSuspend: 1 + m_UpdateMode: 0 + m_ExposedParameters: + - guid: 7835f2c4248cb3e43a1a773bab1f8b9d + name: SoundVolume0 + - guid: 41591fd4a32f4034f880ecbc14ee69f1 + name: MusicVolume0 + - guid: 6e0d1a5935a802d41b27d9e2fad3ba2f + name: UISoundVolume0 + - guid: 0bc64c1c6cebbeb40ba2f724fdcaa257 + name: VoiceVolume0 + - guid: f62a8b3fe89df00409532af739ee4e02 + name: SoundVolume1 + - guid: 265eaf7c8910ab842a845c7bb5e570c4 + name: UISoundVolume1 + - guid: 2a8ce0f3383c3f0468a04fa3fc5e317d + name: SoundVolume2 + - guid: e83be6d6c4ae85142a51f584159c4ff6 + name: UISoundVolume2 + - guid: e54edf7c1bf7ee44297e65adce5b10b7 + name: SoundVolume3 + - guid: 2dd26f9dadf160f4bbd77f307c3f4f2e + name: UISoundVolume3 + - guid: ba83e724007d7e9459f157db3a54a741 + name: MasterVolume + - guid: 6d4c2b8bc0ef38d44b2fbff2b3298ab4 + name: MusicVolume + - guid: 3bbd22597ed32714eb271cf06b098c63 + name: SoundVolume + - guid: 7d1c7ed015f5dba4f934c33ef330c5eb + name: UISoundVolume + - guid: fe15a1b40c14ea646a13dacb15b6a73b + name: VoiceVolume + m_AudioMixerGroupViews: + - guids: + - 72c1e77b100e3274fbfb88ca2ca12c4d + - efe8591c00084024187b9df78858c0af + - 648e49a020cf83346a9220d606e4ff39 + - 5117f9b5a365ec049a9d5891c563b893 + - f46651e8ad3c6034b8764fd635dda3fd + - 1cf576bd46399874d9494863d6502d94 + - 71c50c6b966d1f548a63193919ebfbad + - df986418fa3e4ae448a1909ffbb633fb + - 29257697b1e6be546aa0558e342a15a6 + - c0d40106c2ffb1a44bd48f50b210ee20 + - 039cd795affa7134a8d5f5d43d3b659d + - 5f20d1b8f9ac1914dac8beae718e7d40 + - e012b6d2e0501df43a88eb6beff8ae07 + - e84c25a476798ea43a2f6de217af7dba + - 98657376d4096a947953ee04d82830c1 + name: View + m_CurrentViewIndex: 0 + m_TargetSnapshot: {fileID: 24500006} +--- !u!243 &24300002 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Master + m_AudioMixer: {fileID: 24100000} + m_GroupID: 72c1e77b100e3274fbfb88ca2ca12c4d + m_Children: + - {fileID: -4209890294574411305} + - {fileID: 7235523536312936115} + - {fileID: 7185772616558441635} + - {fileID: -3395020342500439107} + m_Volume: ba83e724007d7e9459f157db3a54a741 + m_Pitch: a2d2b77391464bb4887f0bcd3835015b + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: 24400004} + m_UserColorIndex: 8 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &24400004 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: ce944d90cb57ee4418426132d391d900 + m_EffectName: Attenuation + m_MixLevel: 891c3ec10e0ae1b42a95c83727d411f1 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!245 &24500006 +AudioMixerSnapshotController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Snapshot + m_AudioMixer: {fileID: 24100000} + m_SnapshotID: 91dee90f8902c804c9da7728ea355157 + m_FloatValues: + b47f0c73299cd9b4fba9896e70683903: 1 + ba83e724007d7e9459f157db3a54a741: 0 + fe15a1b40c14ea646a13dacb15b6a73b: 0 + 77212647508232a458ac7d48fb55d037: 1 + 3bbd22597ed32714eb271cf06b098c63: 0 + 30975daa872456b41bc18e0277e301e6: 1 + 6d4c2b8bc0ef38d44b2fbff2b3298ab4: -0.03 + 8542b6bfd7b7bfc4d9b961ba97edf0d2: 1 + m_TransitionOverrides: {} +--- !u!244 &246003612463095956 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 860c45ba06e3cbd4794061eaefe970a3 + m_EffectName: Attenuation + m_MixLevel: bb4c221c9e3208941b1a2107831692ab + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &281287199725387719 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 812fbfe4555eb1641aeaeee69a13b4a6 + m_EffectName: Lowpass Simple + m_MixLevel: 391139084347578409e42387008bd110 + m_Parameters: + - m_ParameterName: Cutoff freq + m_GUID: b19756871f24b194d87c7d1fce3159e9 + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &1413273517213151576 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: ce0c93d89826c7349a19b232116484db + m_EffectName: Attenuation + m_MixLevel: 7625365898787684c9bce9298a96f044 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!243 &1543978434442340687 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Music - 0 + m_AudioMixer: {fileID: 24100000} + m_GroupID: 1cf576bd46399874d9494863d6502d94 + m_Children: [] + m_Volume: 41591fd4a32f4034f880ecbc14ee69f1 + m_Pitch: 9ad7e859a0cd1f142b59ffc659be28a7 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -8255999005317483048} + m_UserColorIndex: 1 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!243 &1601410790413250045 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: UISound - 3 + m_AudioMixer: {fileID: 24100000} + m_GroupID: 98657376d4096a947953ee04d82830c1 + m_Children: [] + m_Volume: 2dd26f9dadf160f4bbd77f307c3f4f2e + m_Pitch: 5627fa8b0176a344bbb4e59ac5e648d3 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: 1413273517213151576} + m_UserColorIndex: 3 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &2567082640316932351 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: a7394d86e1e2a1e4389182f0aec98773 + m_EffectName: Attenuation + m_MixLevel: cb8b6dfd682072d4fb81143ba077bc3f + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!243 &3865010338301366421 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: UISound - 2 + m_AudioMixer: {fileID: 24100000} + m_GroupID: e84c25a476798ea43a2f6de217af7dba + m_Children: [] + m_Volume: e83be6d6c4ae85142a51f584159c4ff6 + m_Pitch: c45439925e1cfd547894fd886160a11c + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: 7834155774142160187} + m_UserColorIndex: 3 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &5734415080786067514 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 20eac414948135e49b2b54a89235f15e + m_EffectName: Attenuation + m_MixLevel: d087be8c429707c4db724a61186f67f6 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &5954042604037024145 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: ba434c984ec3c4442bfe3a399c11572b + m_EffectName: Echo + m_MixLevel: 0323002ce01f29a4abebc242337ea816 + m_Parameters: + - m_ParameterName: Delay + m_GUID: f4cc548867353f843bc36a61722c6cbf + - m_ParameterName: Decay + m_GUID: e67c7b4426842f948a83f3dada794a99 + - m_ParameterName: Max channels + m_GUID: 75c7951a8373f4644a44979a8c5776ed + - m_ParameterName: Drymix + m_GUID: 4d26b3b7a84b31d499176a7879734ba1 + - m_ParameterName: Wetmix + m_GUID: 6efaeec45de20b045a4d560994684cba + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &6255340296135181231 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 3a251f2e65751b349bb255f73f0caeaf + m_EffectName: Duck Volume + m_MixLevel: 58cfdd03ab24c874cbe074238d636208 + m_Parameters: + - m_ParameterName: Threshold + m_GUID: b1b5c57689fc533408e6195c0a9e26a9 + - m_ParameterName: Ratio + m_GUID: dc9c2c635bce58746bd68c7dffb99ca0 + - m_ParameterName: Attack Time + m_GUID: 078ff252301e4594c880cd5754b8a563 + - m_ParameterName: Release Time + m_GUID: b3918efd0a966ea4882714c0f9edd40b + - m_ParameterName: Make-up Gain + m_GUID: 3cf881ca64b7cdb46b35d3593ff2cbe9 + - m_ParameterName: Knee + m_GUID: 31ea47a78d927ab4abf12f854bd4c626 + - m_ParameterName: Sidechain Mix + m_GUID: 468d86503d3572541a33c33bb9693dfd + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &6554641470784401750 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 4499c94d696ee5741a71370ed7431e12 + m_EffectName: Send + m_MixLevel: f01b57f2509f26f4b8f2772993c2b8c6 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &6637688299338053042 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: e84926aaeedf4074698e7d7f7f36b78b + m_EffectName: Attenuation + m_MixLevel: 8141a348079ee934686d3569f4758582 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!243 &7040861873718444651 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: UISound - 0 + m_AudioMixer: {fileID: 24100000} + m_GroupID: 29257697b1e6be546aa0558e342a15a6 + m_Children: [] + m_Volume: 6e0d1a5935a802d41b27d9e2fad3ba2f + m_Pitch: 7d01f3677fe8c5b41a877b64cc509766 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -4958177229083455073} + m_UserColorIndex: 3 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!243 &7185772616558441635 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: UISound + m_AudioMixer: {fileID: 24100000} + m_GroupID: df986418fa3e4ae448a1909ffbb633fb + m_Children: + - {fileID: 7040861873718444651} + - {fileID: -3720557753501792270} + - {fileID: 3865010338301366421} + - {fileID: 1601410790413250045} + m_Volume: 7d1c7ed015f5dba4f934c33ef330c5eb + m_Pitch: 611d9d89c8a65b548b591e852596c35d + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -998299258853400712} + m_UserColorIndex: 3 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!243 &7235523536312936115 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Sound + m_AudioMixer: {fileID: 24100000} + m_GroupID: 648e49a020cf83346a9220d606e4ff39 + m_Children: + - {fileID: -2659745067392564156} + - {fileID: -6280614258348125054} + - {fileID: -7758028812591520460} + - {fileID: -4372808504093502661} + m_Volume: 3bbd22597ed32714eb271cf06b098c63 + m_Pitch: 7f8a6510dd472ff4db8b07c5079a2013 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: 2567082640316932351} + m_UserColorIndex: 2 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &7834155774142160187 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 09e809d6183106b4a804ff08ca8ff9ed + m_EffectName: Attenuation + m_MixLevel: 92339d91519b09543844a84cea03aed3 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources/AudioMixer.mixer.meta b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources/AudioMixer.mixer.meta new file mode 100644 index 00000000..68fada2e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/AudioModule/Resources/AudioMixer.mixer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1af7a1b121ae17541a1967d430cef006 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule.meta new file mode 100644 index 00000000..9d5a723c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 240db69237354f240a5988aa5e6a8268 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component.meta new file mode 100644 index 00000000..6d758fd5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9871da9e5bc640969d89e4bd1efd8b4d +timeCreated: 1680489758 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.EnvironmentInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.EnvironmentInformationWindow.cs new file mode 100644 index 00000000..5ddb800e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.EnvironmentInformationWindow.cs @@ -0,0 +1,89 @@ +using UnityEngine; +#if UNITY_5_5_OR_NEWER +using UnityEngine.Rendering; +#endif + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class EnvironmentInformationWindow : ScrollableDebuggerWindowBase + { + private RootModule _mRootModule = null; + + private ResourceModule _mResourceModule = null; + + public override void Initialize(params object[] args) + { + _mRootModule = ModuleSystem.GetModule(); + if (_mRootModule == null) + { + Log.Fatal("Base component is invalid."); + return; + } + + _mResourceModule = ModuleSystem.GetModule(); + if (_mResourceModule == null) + { + Log.Fatal("Resource component is invalid."); + return; + } + } + + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Environment Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Product Name", Application.productName); + DrawItem("Company Name", Application.companyName); +#if UNITY_5_6_OR_NEWER + DrawItem("Game Identifier", Application.identifier); +#else + DrawItem("Game Identifier", Application.bundleIdentifier); +#endif + DrawItem("Game Framework Version", Version.GameFrameworkVersion); + DrawItem("Game Version", Utility.Text.Format("{0} ({1})", Version.GameVersion, Version.InternalGameVersion)); + DrawItem("Resource Version", (string.IsNullOrEmpty(_mResourceModule.ApplicableGameVersion) ? "Unknown" : Utility.Text.Format("{0} ({1})", _mResourceModule.ApplicableGameVersion, _mResourceModule.InternalResourceVersion))); + DrawItem("Application Version", Application.version); + DrawItem("Unity Version", Application.unityVersion); + DrawItem("Platform", Application.platform.ToString()); + DrawItem("System Language", Application.systemLanguage.ToString()); + DrawItem("Cloud Project Id", Application.cloudProjectId); +#if UNITY_5_6_OR_NEWER + DrawItem("Build Guid", Application.buildGUID); +#endif + DrawItem("Target Frame Rate", Application.targetFrameRate.ToString()); + DrawItem("Internet Reachability", Application.internetReachability.ToString()); + DrawItem("Background Loading Priority", Application.backgroundLoadingPriority.ToString()); + DrawItem("Is Playing", Application.isPlaying.ToString()); +#if UNITY_5_5_OR_NEWER + DrawItem("Splash Screen Is Finished", SplashScreen.isFinished.ToString()); +#else + DrawItem("Is Showing Splash Screen", Application.isShowingSplashScreen.ToString()); +#endif + DrawItem("Run In Background", Application.runInBackground.ToString()); +#if UNITY_5_5_OR_NEWER + DrawItem("Install Name", Application.installerName); +#endif + DrawItem("Install Mode", Application.installMode.ToString()); + DrawItem("Sandbox Type", Application.sandboxType.ToString()); + DrawItem("Is Mobile Platform", Application.isMobilePlatform.ToString()); + DrawItem("Is Console Platform", Application.isConsolePlatform.ToString()); + DrawItem("Is Editor", Application.isEditor.ToString()); + DrawItem("Is Debug Build", Debug.isDebugBuild.ToString()); +#if UNITY_5_6_OR_NEWER + DrawItem("Is Focused", Application.isFocused.ToString()); +#endif +#if UNITY_2018_2_OR_NEWER + DrawItem("Is Batch Mode", Application.isBatchMode.ToString()); +#endif +#if UNITY_5_3 + DrawItem("Stack Trace Log Type", Application.stackTraceLogType.ToString()); +#endif + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.EnvironmentInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.EnvironmentInformationWindow.cs.meta new file mode 100644 index 00000000..56fd055a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.EnvironmentInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 117d1215a84c42189328f73f5e9eac2d +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.GraphicsInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.GraphicsInformationWindow.cs new file mode 100644 index 00000000..7983dca5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.GraphicsInformationWindow.cs @@ -0,0 +1,162 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class GraphicsInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Graphics Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Device ID", SystemInfo.graphicsDeviceID.ToString()); + DrawItem("Device Name", SystemInfo.graphicsDeviceName); + DrawItem("Device Vendor ID", SystemInfo.graphicsDeviceVendorID.ToString()); + DrawItem("Device Vendor", SystemInfo.graphicsDeviceVendor); + DrawItem("Device Type", SystemInfo.graphicsDeviceType.ToString()); + DrawItem("Device Version", SystemInfo.graphicsDeviceVersion); + DrawItem("Memory Size", Utility.Text.Format("{0} MB", SystemInfo.graphicsMemorySize)); + DrawItem("Multi Threaded", SystemInfo.graphicsMultiThreaded.ToString()); +#if UNITY_2019_3_OR_NEWER + DrawItem("Rendering Threading Mode", SystemInfo.renderingThreadingMode.ToString()); +#endif +#if UNITY_2020_1_OR_NEWER + DrawItem("HRD Display Support Flags", SystemInfo.hdrDisplaySupportFlags.ToString()); +#endif + DrawItem("Shader Level", GetShaderLevelString(SystemInfo.graphicsShaderLevel)); + DrawItem("Global Maximum LOD", Shader.globalMaximumLOD.ToString()); +#if UNITY_5_6_OR_NEWER + DrawItem("Global Render Pipeline", Shader.globalRenderPipeline); +#endif +#if UNITY_2020_2_OR_NEWER + DrawItem("Min OpenGLES Version", Graphics.minOpenGLESVersion.ToString()); +#endif +#if UNITY_5_5_OR_NEWER + DrawItem("Active Tier", Graphics.activeTier.ToString()); +#endif +#if UNITY_2017_2_OR_NEWER + DrawItem("Active Color Gamut", Graphics.activeColorGamut.ToString()); +#endif +#if UNITY_2019_2_OR_NEWER + DrawItem("Preserve Frame Buffer Alpha", Graphics.preserveFramebufferAlpha.ToString()); +#endif + DrawItem("NPOT Support", SystemInfo.npotSupport.ToString()); + DrawItem("Max Texture Size", SystemInfo.maxTextureSize.ToString()); + DrawItem("Supported Render Target Count", SystemInfo.supportedRenderTargetCount.ToString()); +#if UNITY_2019_3_OR_NEWER + DrawItem("Supported Random Write Target Count", SystemInfo.supportedRandomWriteTargetCount.ToString()); +#endif +#if UNITY_5_4_OR_NEWER + DrawItem("Copy Texture Support", SystemInfo.copyTextureSupport.ToString()); +#endif +#if UNITY_5_5_OR_NEWER + DrawItem("Uses Reversed ZBuffer", SystemInfo.usesReversedZBuffer.ToString()); +#endif +#if UNITY_5_6_OR_NEWER + DrawItem("Max Cubemap Size", SystemInfo.maxCubemapSize.ToString()); + DrawItem("Graphics UV Starts At Top", SystemInfo.graphicsUVStartsAtTop.ToString()); +#endif +#if UNITY_2020_2_OR_NEWER + DrawItem("Constant Buffer Offset Alignment", SystemInfo.constantBufferOffsetAlignment.ToString()); +#elif UNITY_2019_1_OR_NEWER + DrawItem("Min Constant Buffer Offset Alignment", SystemInfo.minConstantBufferOffsetAlignment.ToString()); +#endif +#if UNITY_2018_3_OR_NEWER + DrawItem("Has Hidden Surface Removal On GPU", SystemInfo.hasHiddenSurfaceRemovalOnGPU.ToString()); + DrawItem("Has Dynamic Uniform Array Indexing In Fragment Shaders", SystemInfo.hasDynamicUniformArrayIndexingInFragmentShaders.ToString()); +#endif +#if UNITY_2019_2_OR_NEWER + DrawItem("Has Mip Max Level", SystemInfo.hasMipMaxLevel.ToString()); +#endif +#if UNITY_2019_3_OR_NEWER + DrawItem("Uses Load Store Actions", SystemInfo.usesLoadStoreActions.ToString()); + DrawItem("Max Compute Buffer Inputs Compute", SystemInfo.maxComputeBufferInputsCompute.ToString()); + DrawItem("Max Compute Buffer Inputs Domain", SystemInfo.maxComputeBufferInputsDomain.ToString()); + DrawItem("Max Compute Buffer Inputs Fragment", SystemInfo.maxComputeBufferInputsFragment.ToString()); + DrawItem("Max Compute Buffer Inputs Geometry", SystemInfo.maxComputeBufferInputsGeometry.ToString()); + DrawItem("Max Compute Buffer Inputs Hull", SystemInfo.maxComputeBufferInputsHull.ToString()); + DrawItem("Max Compute Buffer Inputs Vertex", SystemInfo.maxComputeBufferInputsVertex.ToString()); + DrawItem("Max Compute Work Group Size", SystemInfo.maxComputeWorkGroupSize.ToString()); + DrawItem("Max Compute Work Group Size X", SystemInfo.maxComputeWorkGroupSizeX.ToString()); + DrawItem("Max Compute Work Group Size Y", SystemInfo.maxComputeWorkGroupSizeY.ToString()); + DrawItem("Max Compute Work Group Size Z", SystemInfo.maxComputeWorkGroupSizeZ.ToString()); +#endif +#if UNITY_5_3 || UNITY_5_4 + DrawItem("Supports Stencil", SystemInfo.supportsStencil.ToString()); + DrawItem("Supports Render Textures", SystemInfo.supportsRenderTextures.ToString()); +#endif + DrawItem("Supports Sparse Textures", SystemInfo.supportsSparseTextures.ToString()); + DrawItem("Supports 3D Textures", SystemInfo.supports3DTextures.ToString()); + DrawItem("Supports Shadows", SystemInfo.supportsShadows.ToString()); + DrawItem("Supports Raw Shadow Depth Sampling", SystemInfo.supportsRawShadowDepthSampling.ToString()); +#if !UNITY_2019_1_OR_NEWER + DrawItem("Supports Render To Cubemap", SystemInfo.supportsRenderToCubemap.ToString()); + DrawItem("Supports Image Effects", SystemInfo.supportsImageEffects.ToString()); +#endif + DrawItem("Supports Compute Shader", SystemInfo.supportsComputeShaders.ToString()); + DrawItem("Supports Instancing", SystemInfo.supportsInstancing.ToString()); +#if UNITY_5_4_OR_NEWER + DrawItem("Supports 2D Array Textures", SystemInfo.supports2DArrayTextures.ToString()); + DrawItem("Supports Motion Vectors", SystemInfo.supportsMotionVectors.ToString()); +#endif +#if UNITY_5_5_OR_NEWER + DrawItem("Supports Cubemap Array Textures", SystemInfo.supportsCubemapArrayTextures.ToString()); +#endif +#if UNITY_5_6_OR_NEWER + DrawItem("Supports 3D Render Textures", SystemInfo.supports3DRenderTextures.ToString()); +#endif +#if UNITY_2017_2_OR_NEWER && !UNITY_2017_2_0 || UNITY_2017_1_4 + DrawItem("Supports Texture Wrap Mirror Once", SystemInfo.supportsTextureWrapMirrorOnce.ToString()); +#endif +#if UNITY_2019_1_OR_NEWER + DrawItem("Supports Graphics Fence", SystemInfo.supportsGraphicsFence.ToString()); +#elif UNITY_2017_3_OR_NEWER + DrawItem("Supports GPU Fence", SystemInfo.supportsGPUFence.ToString()); +#endif +#if UNITY_2017_3_OR_NEWER + DrawItem("Supports Async Compute", SystemInfo.supportsAsyncCompute.ToString()); + DrawItem("Supports Multi-sampled Textures", SystemInfo.supportsMultisampledTextures.ToString()); +#endif +#if UNITY_2018_1_OR_NEWER + DrawItem("Supports Async GPU Readback", SystemInfo.supportsAsyncGPUReadback.ToString()); + DrawItem("Supports 32bits Index Buffer", SystemInfo.supports32bitsIndexBuffer.ToString()); + DrawItem("Supports Hardware Quad Topology", SystemInfo.supportsHardwareQuadTopology.ToString()); +#endif +#if UNITY_2018_2_OR_NEWER + DrawItem("Supports Mip Streaming", SystemInfo.supportsMipStreaming.ToString()); + DrawItem("Supports Multi-sample Auto Resolve", SystemInfo.supportsMultisampleAutoResolve.ToString()); +#endif +#if UNITY_2018_3_OR_NEWER + DrawItem("Supports Separated Render Targets Blend", SystemInfo.supportsSeparatedRenderTargetsBlend.ToString()); +#endif +#if UNITY_2019_1_OR_NEWER + DrawItem("Supports Set Constant Buffer", SystemInfo.supportsSetConstantBuffer.ToString()); +#endif +#if UNITY_2019_3_OR_NEWER + DrawItem("Supports Geometry Shaders", SystemInfo.supportsGeometryShaders.ToString()); + DrawItem("Supports Ray Tracing", SystemInfo.supportsRayTracing.ToString()); + DrawItem("Supports Tessellation Shaders", SystemInfo.supportsTessellationShaders.ToString()); +#endif +#if UNITY_2020_1_OR_NEWER + DrawItem("Supports Compressed 3D Textures", SystemInfo.supportsCompressed3DTextures.ToString()); + DrawItem("Supports Conservative Raster", SystemInfo.supportsConservativeRaster.ToString()); + DrawItem("Supports GPU Recorder", SystemInfo.supportsGpuRecorder.ToString()); +#endif +#if UNITY_2020_2_OR_NEWER + DrawItem("Supports Multi-sampled 2D Array Textures", SystemInfo.supportsMultisampled2DArrayTextures.ToString()); + DrawItem("Supports Multiview", SystemInfo.supportsMultiview.ToString()); + DrawItem("Supports Render Target Array Index From Vertex Shader", SystemInfo.supportsRenderTargetArrayIndexFromVertexShader.ToString()); +#endif + } + GUILayout.EndVertical(); + } + + private string GetShaderLevelString(int shaderLevel) + { + return Utility.Text.Format("Shader Model {0}.{1}", shaderLevel / 10, shaderLevel % 10); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.GraphicsInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.GraphicsInformationWindow.cs.meta new file mode 100644 index 00000000..a8c3d00a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.GraphicsInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b257b0e038194eb480632d81e640058e +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputAccelerationInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputAccelerationInformationWindow.cs new file mode 100644 index 00000000..4551b67e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputAccelerationInformationWindow.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class InputAccelerationInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Input Acceleration Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Acceleration", Input.acceleration.ToString()); + DrawItem("Acceleration Event Count", Input.accelerationEventCount.ToString()); + DrawItem("Acceleration Events", GetAccelerationEventsString(Input.accelerationEvents)); + } + GUILayout.EndVertical(); + } + + private string GetAccelerationEventString(AccelerationEvent accelerationEvent) + { + return Utility.Text.Format("{0}, {1}", accelerationEvent.acceleration, accelerationEvent.deltaTime); + } + + private string GetAccelerationEventsString(AccelerationEvent[] accelerationEvents) + { + string[] accelerationEventStrings = new string[accelerationEvents.Length]; + for (int i = 0; i < accelerationEvents.Length; i++) + { + accelerationEventStrings[i] = GetAccelerationEventString(accelerationEvents[i]); + } + + return string.Join("; ", accelerationEventStrings); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputAccelerationInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputAccelerationInformationWindow.cs.meta new file mode 100644 index 00000000..cf45344b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputAccelerationInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 88685f3bc75649dc8c198de19ae84c3e +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputCompassInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputCompassInformationWindow.cs new file mode 100644 index 00000000..4497e7cd --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputCompassInformationWindow.cs @@ -0,0 +1,41 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class InputCompassInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Input Compass Information"); + GUILayout.BeginVertical("box"); + { + GUILayout.BeginHorizontal(); + { + if (GUILayout.Button("Enable", GUILayout.Height(30f))) + { + Input.compass.enabled = true; + } + if (GUILayout.Button("Disable", GUILayout.Height(30f))) + { + Input.compass.enabled = false; + } + } + GUILayout.EndHorizontal(); + + DrawItem("Enabled", Input.compass.enabled.ToString()); + if (Input.compass.enabled) + { + DrawItem("Heading Accuracy", Input.compass.headingAccuracy.ToString()); + DrawItem("Magnetic Heading", Input.compass.magneticHeading.ToString()); + DrawItem("Raw Vector", Input.compass.rawVector.ToString()); + DrawItem("Timestamp", Input.compass.timestamp.ToString()); + DrawItem("True Heading", Input.compass.trueHeading.ToString()); + } + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputCompassInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputCompassInformationWindow.cs.meta new file mode 100644 index 00000000..b3d0cfd9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputCompassInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dfbb3d3f61b041d9a0fa135a7cac876a +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputGyroscopeInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputGyroscopeInformationWindow.cs new file mode 100644 index 00000000..0642f001 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputGyroscopeInformationWindow.cs @@ -0,0 +1,42 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class InputGyroscopeInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Input Gyroscope Information"); + GUILayout.BeginVertical("box"); + { + GUILayout.BeginHorizontal(); + { + if (GUILayout.Button("Enable", GUILayout.Height(30f))) + { + Input.gyro.enabled = true; + } + if (GUILayout.Button("Disable", GUILayout.Height(30f))) + { + Input.gyro.enabled = false; + } + } + GUILayout.EndHorizontal(); + + DrawItem("Enabled", Input.gyro.enabled.ToString()); + if (Input.gyro.enabled) + { + DrawItem("Update Interval", Input.gyro.updateInterval.ToString()); + DrawItem("Attitude", Input.gyro.attitude.eulerAngles.ToString()); + DrawItem("Gravity", Input.gyro.gravity.ToString()); + DrawItem("Rotation Rate", Input.gyro.rotationRate.ToString()); + DrawItem("Rotation Rate Unbiased", Input.gyro.rotationRateUnbiased.ToString()); + DrawItem("User Acceleration", Input.gyro.userAcceleration.ToString()); + } + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputGyroscopeInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputGyroscopeInformationWindow.cs.meta new file mode 100644 index 00000000..5b5afcaf --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputGyroscopeInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 153ce8ea1c9b400c82c4ec742d8aa6b7 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputLocationInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputLocationInformationWindow.cs new file mode 100644 index 00000000..b2dd75b8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputLocationInformationWindow.cs @@ -0,0 +1,43 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class InputLocationInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Input Location Information"); + GUILayout.BeginVertical("box"); + { + GUILayout.BeginHorizontal(); + { + if (GUILayout.Button("Enable", GUILayout.Height(30f))) + { + Input.location.Start(); + } + if (GUILayout.Button("Disable", GUILayout.Height(30f))) + { + Input.location.Stop(); + } + } + GUILayout.EndHorizontal(); + + DrawItem("Is Enabled By User", Input.location.isEnabledByUser.ToString()); + DrawItem("Status", Input.location.status.ToString()); + if (Input.location.status == LocationServiceStatus.Running) + { + DrawItem("Horizontal Accuracy", Input.location.lastData.horizontalAccuracy.ToString()); + DrawItem("Vertical Accuracy", Input.location.lastData.verticalAccuracy.ToString()); + DrawItem("Longitude", Input.location.lastData.longitude.ToString()); + DrawItem("Latitude", Input.location.lastData.latitude.ToString()); + DrawItem("Altitude", Input.location.lastData.altitude.ToString()); + DrawItem("Timestamp", Input.location.lastData.timestamp.ToString()); + } + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputLocationInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputLocationInformationWindow.cs.meta new file mode 100644 index 00000000..d6d26238 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputLocationInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 04628888fa364b2b97b4cb77dcbbdd44 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputSummaryInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputSummaryInformationWindow.cs new file mode 100644 index 00000000..7a39800a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputSummaryInformationWindow.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class InputSummaryInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Input Summary Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Back Button Leaves App", Input.backButtonLeavesApp.ToString()); + DrawItem("Device Orientation", Input.deviceOrientation.ToString()); + DrawItem("Mouse Present", Input.mousePresent.ToString()); + DrawItem("Mouse Position", Input.mousePosition.ToString()); + DrawItem("Mouse Scroll Delta", Input.mouseScrollDelta.ToString()); + DrawItem("Any Key", Input.anyKey.ToString()); + DrawItem("Any Key Down", Input.anyKeyDown.ToString()); + DrawItem("Input String", Input.inputString); + DrawItem("IME Is Selected", Input.imeIsSelected.ToString()); + DrawItem("IME Composition Mode", Input.imeCompositionMode.ToString()); + DrawItem("Compensate Sensors", Input.compensateSensors.ToString()); + DrawItem("Composition Cursor Position", Input.compositionCursorPos.ToString()); + DrawItem("Composition String", Input.compositionString); + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputSummaryInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputSummaryInformationWindow.cs.meta new file mode 100644 index 00000000..86cb5d1e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputSummaryInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ada3bed2bef9413a85c890e907e0e449 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputTouchInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputTouchInformationWindow.cs new file mode 100644 index 00000000..256d0d72 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputTouchInformationWindow.cs @@ -0,0 +1,42 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class InputTouchInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Input Touch Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Touch Supported", Input.touchSupported.ToString()); + DrawItem("Touch Pressure Supported", Input.touchPressureSupported.ToString()); + DrawItem("Stylus Touch Supported", Input.stylusTouchSupported.ToString()); + DrawItem("Simulate Mouse With Touches", Input.simulateMouseWithTouches.ToString()); + DrawItem("Multi Touch Enabled", Input.multiTouchEnabled.ToString()); + DrawItem("Touch Count", Input.touchCount.ToString()); + DrawItem("Touches", GetTouchesString(Input.touches)); + } + GUILayout.EndVertical(); + } + + private string GetTouchString(Touch touch) + { + return Utility.Text.Format("{0}, {1}, {2}, {3}, {4}", touch.position, touch.deltaPosition, touch.rawPosition, touch.pressure, touch.phase); + } + + private string GetTouchesString(Touch[] touches) + { + string[] touchStrings = new string[touches.Length]; + for (int i = 0; i < touches.Length; i++) + { + touchStrings[i] = GetTouchString(touches[i]); + } + + return string.Join("; ", touchStrings); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputTouchInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputTouchInformationWindow.cs.meta new file mode 100644 index 00000000..c2bdc78a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.InputTouchInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1a54fc6c38204d28b511fe8747b4151d +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.LogNode.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.LogNode.cs new file mode 100644 index 00000000..e2ea8c63 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.LogNode.cs @@ -0,0 +1,117 @@ +using System; +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + /// + /// 日志记录结点。 + /// + public sealed class LogNode : IMemory + { + private DateTime m_LogTime; + private int m_LogFrameCount; + private LogType m_LogType; + private string m_LogMessage; + private string m_StackTrack; + + /// + /// 初始化日志记录结点的新实例。 + /// + public LogNode() + { + m_LogTime = default(DateTime); + m_LogFrameCount = 0; + m_LogType = LogType.Error; + m_LogMessage = null; + m_StackTrack = null; + } + + /// + /// 获取日志时间。 + /// + public DateTime LogTime + { + get + { + return m_LogTime; + } + } + + /// + /// 获取日志帧计数。 + /// + public int LogFrameCount + { + get + { + return m_LogFrameCount; + } + } + + /// + /// 获取日志类型。 + /// + public LogType LogType + { + get + { + return m_LogType; + } + } + + /// + /// 获取日志内容。 + /// + public string LogMessage + { + get + { + return m_LogMessage; + } + } + + /// + /// 获取日志堆栈信息。 + /// + public string StackTrack + { + get + { + return m_StackTrack; + } + } + + /// + /// 创建日志记录结点。 + /// + /// 日志类型。 + /// 日志内容。 + /// 日志堆栈信息。 + /// 创建的日志记录结点。 + public static LogNode Create(LogType logType, string logMessage, string stackTrack) + { + LogNode logNode = MemoryPool.Acquire(); + logNode.m_LogTime = DateTime.UtcNow; + logNode.m_LogFrameCount = Time.frameCount; + logNode.m_LogType = logType; + logNode.m_LogMessage = logMessage; + logNode.m_StackTrack = stackTrack; + return logNode; + } + + /// + /// 清理日志记录结点。 + /// + public void Clear() + { + m_LogTime = default(DateTime); + m_LogFrameCount = 0; + m_LogType = LogType.Error; + m_LogMessage = null; + m_StackTrack = null; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.LogNode.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.LogNode.cs.meta new file mode 100644 index 00000000..2df706d6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.LogNode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e7135a7b2bbe46f8a69c3b6b9b4cf2be +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.MemoryPoolInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.MemoryPoolInformationWindow.cs new file mode 100644 index 00000000..4b698b6f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.MemoryPoolInformationWindow.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class MemoryPoolPoolInformationWindow : ScrollableDebuggerWindowBase + { + private readonly Dictionary> m_MemoryPoolInfos = new Dictionary>(StringComparer.Ordinal); + private readonly Comparison m_NormalClassNameComparer = NormalClassNameComparer; + private readonly Comparison m_FullClassNameComparer = FullClassNameComparer; + private bool m_ShowFullClassName = false; + + public override void Initialize(params object[] args) + { + } + + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Memory Pool Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Enable Strict Check", MemoryPool.EnableStrictCheck.ToString()); + DrawItem("Memory Pool Count", MemoryPool.Count.ToString()); + } + GUILayout.EndVertical(); + + m_ShowFullClassName = GUILayout.Toggle(m_ShowFullClassName, "Show Full Class Name"); + m_MemoryPoolInfos.Clear(); + MemoryPoolInfo[] memoryPoolInfos = MemoryPool.GetAllMemoryPoolInfos(); + foreach (MemoryPoolInfo memoryPoolInfo in memoryPoolInfos) + { + string assemblyName = memoryPoolInfo.Type.Assembly.GetName().Name; + List results = null; + if (!m_MemoryPoolInfos.TryGetValue(assemblyName, out results)) + { + results = new List(); + m_MemoryPoolInfos.Add(assemblyName, results); + } + + results.Add(memoryPoolInfo); + } + + foreach (KeyValuePair> assemblyMemoryPoolInfo in m_MemoryPoolInfos) + { + GUILayout.Label(Utility.Text.Format("Assembly: {0}", assemblyMemoryPoolInfo.Key)); + GUILayout.BeginVertical("box"); + { + GUILayout.BeginHorizontal(); + { + GUILayout.Label(m_ShowFullClassName ? "Full Class Name" : "Class Name"); + GUILayout.Label("Unused", GUILayout.Width(60f)); + GUILayout.Label("Using", GUILayout.Width(60f)); + GUILayout.Label("Acquire", GUILayout.Width(60f)); + GUILayout.Label("Release", GUILayout.Width(60f)); + GUILayout.Label("Add", GUILayout.Width(60f)); + GUILayout.Label("Remove", GUILayout.Width(60f)); + } + GUILayout.EndHorizontal(); + + if (assemblyMemoryPoolInfo.Value.Count > 0) + { + assemblyMemoryPoolInfo.Value.Sort(m_ShowFullClassName ? m_FullClassNameComparer : m_NormalClassNameComparer); + foreach (MemoryPoolInfo memoryPoolInfo in assemblyMemoryPoolInfo.Value) + { + DrawMemoryPoolInfo(memoryPoolInfo); + } + } + else + { + GUILayout.Label("Memory Pool is Empty ..."); + } + } + GUILayout.EndVertical(); + } + } + + private void DrawMemoryPoolInfo(MemoryPoolInfo memoryPoolInfo) + { + GUILayout.BeginHorizontal(); + { + GUILayout.Label(m_ShowFullClassName ? memoryPoolInfo.Type.FullName : memoryPoolInfo.Type.Name); + GUILayout.Label(memoryPoolInfo.UnusedMemoryCount.ToString(), GUILayout.Width(60f)); + GUILayout.Label(memoryPoolInfo.UsingMemoryCount.ToString(), GUILayout.Width(60f)); + GUILayout.Label(memoryPoolInfo.AcquireMemoryCount.ToString(), GUILayout.Width(60f)); + GUILayout.Label(memoryPoolInfo.ReleaseMemoryCount.ToString(), GUILayout.Width(60f)); + GUILayout.Label(memoryPoolInfo.AddMemoryCount.ToString(), GUILayout.Width(60f)); + GUILayout.Label(memoryPoolInfo.RemoveMemoryCount.ToString(), GUILayout.Width(60f)); + } + GUILayout.EndHorizontal(); + } + + private static int NormalClassNameComparer(MemoryPoolInfo a, MemoryPoolInfo b) + { + return a.Type.Name.CompareTo(b.Type.Name); + } + + private static int FullClassNameComparer(MemoryPoolInfo a, MemoryPoolInfo b) + { + return a.Type.FullName.CompareTo(b.Type.FullName); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.MemoryPoolInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.MemoryPoolInformationWindow.cs.meta new file mode 100644 index 00000000..adf51a4f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.MemoryPoolInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 71ce9435de5c41b3a582614d4ea71512 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.NetworkInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.NetworkInformationWindow.cs new file mode 100644 index 00000000..cdfe477b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.NetworkInformationWindow.cs @@ -0,0 +1,61 @@ +// using UnityEngine; +// +// namespace TEngine +// { +// public sealed partial class DebuggerModule : Module +// { +// private sealed class NetworkInformationWindow : ScrollableDebuggerWindowBase +// { +// private NetworkComponent m_NetworkComponent = null; +// +// public override void Initialize(params object[] args) +// { +// m_NetworkComponent = GameEntry.GetComponent(); +// if (m_NetworkComponent == null) +// { +// Log.Fatal("Network component is invalid."); +// return; +// } +// } +// +// protected override void OnDrawScrollableWindow() +// { +// GUILayout.Label("Network Information"); +// GUILayout.BeginVertical("box"); +// { +// DrawItem("Network Channel Count", m_NetworkComponent.NetworkChannelCount.ToString()); +// } +// GUILayout.EndVertical(); +// INetworkChannel[] networkChannels = m_NetworkComponent.GetAllNetworkChannels(); +// for (int i = 0; i < networkChannels.Length; i++) +// { +// DrawNetworkChannel(networkChannels[i]); +// } +// } +// +// private void DrawNetworkChannel(INetworkChannel networkChannel) +// { +// GUILayout.Label(Utility.Text.Format("Network Channel: {0} ({1})", networkChannel.Name, networkChannel.Connected ? "Connected" : "Disconnected")); +// GUILayout.BeginVertical("box"); +// { +// DrawItem("Service Type", networkChannel.ServiceType.ToString()); +// DrawItem("Address Family", networkChannel.AddressFamily.ToString()); +// DrawItem("Local Address", networkChannel.Connected ? networkChannel.Socket.LocalEndPoint.ToString() : "Unavailable"); +// DrawItem("Remote Address", networkChannel.Connected ? networkChannel.Socket.RemoteEndPoint.ToString() : "Unavailable"); +// DrawItem("Send Packet", Utility.Text.Format("{0} / {1}", networkChannel.SendPacketCount, networkChannel.SentPacketCount)); +// DrawItem("Receive Packet", Utility.Text.Format("{0} / {1}", networkChannel.ReceivePacketCount, networkChannel.ReceivedPacketCount)); +// DrawItem("Miss Heart Beat Count", networkChannel.MissHeartBeatCount.ToString()); +// DrawItem("Heart Beat", Utility.Text.Format("{0:F2} / {1:F2}", networkChannel.HeartBeatElapseSeconds, networkChannel.HeartBeatInterval)); +// if (networkChannel.Connected) +// { +// if (GUILayout.Button("Disconnect", GUILayout.Height(30f))) +// { +// networkChannel.Close(); +// } +// } +// } +// GUILayout.EndVertical(); +// } +// } +// } +// } diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.NetworkInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.NetworkInformationWindow.cs.meta new file mode 100644 index 00000000..7d7440b2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.NetworkInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 91eb2683b03a4eb0afdd2edd034df2cc +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ObjectPoolInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ObjectPoolInformationWindow.cs new file mode 100644 index 00000000..30b52827 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ObjectPoolInformationWindow.cs @@ -0,0 +1,86 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class ObjectPoolInformationWindow : ScrollableDebuggerWindowBase + { + private ObjectPoolModule _mObjectPoolModule = null; + + public override void Initialize(params object[] args) + { + _mObjectPoolModule = ModuleSystem.GetModule(); + if (_mObjectPoolModule == null) + { + Log.Fatal("Object pool component is invalid."); + return; + } + } + + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Object Pool Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Object Pool Count", _mObjectPoolModule.Count.ToString()); + } + GUILayout.EndVertical(); + ObjectPoolBase[] objectPools = _mObjectPoolModule.GetAllObjectPools(true); + for (int i = 0; i < objectPools.Length; i++) + { + DrawObjectPool(objectPools[i]); + } + } + + private void DrawObjectPool(ObjectPoolBase objectPool) + { + GUILayout.Label(Utility.Text.Format("Object Pool: {0}", objectPool.FullName)); + GUILayout.BeginVertical("box"); + { + DrawItem("Name", objectPool.Name); + DrawItem("Type", objectPool.ObjectType.FullName); + DrawItem("Auto Release Interval", objectPool.AutoReleaseInterval.ToString()); + DrawItem("Capacity", objectPool.Capacity.ToString()); + DrawItem("Used Count", objectPool.Count.ToString()); + DrawItem("Can Release Count", objectPool.CanReleaseCount.ToString()); + DrawItem("Expire Time", objectPool.ExpireTime.ToString()); + DrawItem("Priority", objectPool.Priority.ToString()); + ObjectInfo[] objectInfos = objectPool.GetAllObjectInfos(); + GUILayout.BeginHorizontal(); + { + GUILayout.Label("Name"); + GUILayout.Label("Locked", GUILayout.Width(60f)); + GUILayout.Label(objectPool.AllowMultiSpawn ? "Count" : "In Use", GUILayout.Width(60f)); + GUILayout.Label("Flag", GUILayout.Width(60f)); + GUILayout.Label("Priority", GUILayout.Width(60f)); + GUILayout.Label("Last Use Time", GUILayout.Width(120f)); + } + GUILayout.EndHorizontal(); + + if (objectInfos.Length > 0) + { + for (int i = 0; i < objectInfos.Length; i++) + { + GUILayout.BeginHorizontal(); + { + GUILayout.Label(string.IsNullOrEmpty(objectInfos[i].Name) ? "" : objectInfos[i].Name); + GUILayout.Label(objectInfos[i].Locked.ToString(), GUILayout.Width(60f)); + GUILayout.Label(objectPool.AllowMultiSpawn ? objectInfos[i].SpawnCount.ToString() : objectInfos[i].IsInUse.ToString(), GUILayout.Width(60f)); + GUILayout.Label(objectInfos[i].CustomCanReleaseFlag.ToString(), GUILayout.Width(60f)); + GUILayout.Label(objectInfos[i].Priority.ToString(), GUILayout.Width(60f)); + GUILayout.Label(objectInfos[i].LastUseTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"), GUILayout.Width(120f)); + } + GUILayout.EndHorizontal(); + } + } + else + { + GUILayout.Label("Object Pool is Empty ..."); + } + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ObjectPoolInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ObjectPoolInformationWindow.cs.meta new file mode 100644 index 00000000..e86dbdf4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ObjectPoolInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2f669ce069054868b72a95ebf28d8042 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.OperationsWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.OperationsWindow.cs new file mode 100644 index 00000000..694998d2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.OperationsWindow.cs @@ -0,0 +1,59 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class OperationsWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Operations"); + GUILayout.BeginVertical("box"); + { + ObjectPoolModule objectPoolModule = ModuleSystem.GetModule(); + if (objectPoolModule != null) + { + if (GUILayout.Button("Object Pool Release", GUILayout.Height(30f))) + { + objectPoolModule.Release(); + } + + if (GUILayout.Button("Object Pool Release All Unused", GUILayout.Height(30f))) + { + objectPoolModule.ReleaseAllUnused(); + } + } + + ResourceModule resourceModule = ModuleSystem.GetModule(); + if (resourceModule != null) + { + if (GUILayout.Button("Unload Unused Assets", GUILayout.Height(30f))) + { + resourceModule.ForceUnloadUnusedAssets(false); + } + + if (GUILayout.Button("Unload Unused Assets and Garbage Collect", GUILayout.Height(30f))) + { + resourceModule.ForceUnloadUnusedAssets(true); + } + } + + if (GUILayout.Button("Shutdown Game Framework (None)", GUILayout.Height(30f))) + { + ModuleSystem.Shutdown(ShutdownType.None); + } + if (GUILayout.Button("Shutdown Game Framework (Restart)", GUILayout.Height(30f))) + { + ModuleSystem.Shutdown(ShutdownType.Restart); + } + if (GUILayout.Button("Shutdown Game Framework (Quit)", GUILayout.Height(30f))) + { + ModuleSystem.Shutdown(ShutdownType.Quit); + } + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.OperationsWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.OperationsWindow.cs.meta new file mode 100644 index 00000000..a126cdc9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.OperationsWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 88ba6493eca64e6f8e8135b305f4eaf0 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.PathInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.PathInformationWindow.cs new file mode 100644 index 00000000..eeb03d8a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.PathInformationWindow.cs @@ -0,0 +1,28 @@ +using System; +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class PathInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Path Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Current Directory", Utility.Path.GetRegularPath(Environment.CurrentDirectory)); + DrawItem("Data Path", Utility.Path.GetRegularPath(Application.dataPath)); + DrawItem("Persistent Data Path", Utility.Path.GetRegularPath(Application.persistentDataPath)); + DrawItem("Streaming Assets Path", Utility.Path.GetRegularPath(Application.streamingAssetsPath)); + DrawItem("Temporary Cache Path", Utility.Path.GetRegularPath(Application.temporaryCachePath)); +#if UNITY_2018_3_OR_NEWER + DrawItem("Console Log Path", Utility.Path.GetRegularPath(Application.consoleLogPath)); +#endif + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.PathInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.PathInformationWindow.cs.meta new file mode 100644 index 00000000..d0b1df17 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.PathInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6d2a77c65d5e472792cf84e5c52894b8 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ProfilerInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ProfilerInformationWindow.cs new file mode 100644 index 00000000..c1467dd1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ProfilerInformationWindow.cs @@ -0,0 +1,59 @@ +using UnityEngine; +#if UNITY_5_5_OR_NEWER +using UnityEngine.Profiling; +#endif + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class ProfilerInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Profiler Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Supported", Profiler.supported.ToString()); + DrawItem("Enabled", Profiler.enabled.ToString()); + DrawItem("Enable Binary Log", Profiler.enableBinaryLog ? Utility.Text.Format("True, {0}", Profiler.logFile) : "False"); +#if UNITY_2019_3_OR_NEWER + DrawItem("Enable Allocation Callstacks", Profiler.enableAllocationCallstacks.ToString()); +#endif +#if UNITY_2018_3_OR_NEWER + DrawItem("Area Count", Profiler.areaCount.ToString()); +#endif +#if UNITY_5_3 || UNITY_5_4 + DrawItem("Max Samples Number Per Frame", Profiler.maxNumberOfSamplesPerFrame.ToString()); +#endif +#if UNITY_2018_3_OR_NEWER + DrawItem("Max Used Memory", GetByteLengthString(Profiler.maxUsedMemory)); +#endif +#if UNITY_5_6_OR_NEWER + DrawItem("Mono Used Size", GetByteLengthString(Profiler.GetMonoUsedSizeLong())); + DrawItem("Mono Heap Size", GetByteLengthString(Profiler.GetMonoHeapSizeLong())); + DrawItem("Used Heap Size", GetByteLengthString(Profiler.usedHeapSizeLong)); + DrawItem("Total Allocated Memory", GetByteLengthString(Profiler.GetTotalAllocatedMemoryLong())); + DrawItem("Total Reserved Memory", GetByteLengthString(Profiler.GetTotalReservedMemoryLong())); + DrawItem("Total Unused Reserved Memory", GetByteLengthString(Profiler.GetTotalUnusedReservedMemoryLong())); +#else + DrawItem("Mono Used Size", GetByteLengthString(Profiler.GetMonoUsedSize())); + DrawItem("Mono Heap Size", GetByteLengthString(Profiler.GetMonoHeapSize())); + DrawItem("Used Heap Size", GetByteLengthString(Profiler.usedHeapSize)); + DrawItem("Total Allocated Memory", GetByteLengthString(Profiler.GetTotalAllocatedMemory())); + DrawItem("Total Reserved Memory", GetByteLengthString(Profiler.GetTotalReservedMemory())); + DrawItem("Total Unused Reserved Memory", GetByteLengthString(Profiler.GetTotalUnusedReservedMemory())); +#endif +#if UNITY_2018_1_OR_NEWER + DrawItem("Allocated Memory For Graphics Driver", GetByteLengthString(Profiler.GetAllocatedMemoryForGraphicsDriver())); +#endif +#if UNITY_5_5_OR_NEWER + DrawItem("Temp Allocator Size", GetByteLengthString(Profiler.GetTempAllocatorSize())); +#endif + DrawItem("Marshal Cached HGlobal Size", GetByteLengthString(Utility.Marshal.CachedHGlobalSize)); + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ProfilerInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ProfilerInformationWindow.cs.meta new file mode 100644 index 00000000..f412ce2d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ProfilerInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 10a0760b9718472586a653a79646f05d +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.QualityInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.QualityInformationWindow.cs new file mode 100644 index 00000000..5e3a771f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.QualityInformationWindow.cs @@ -0,0 +1,102 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class QualityInformationWindow : ScrollableDebuggerWindowBase + { + private bool m_ApplyExpensiveChanges = false; + + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Quality Level"); + GUILayout.BeginVertical("box"); + { + int currentQualityLevel = QualitySettings.GetQualityLevel(); + + DrawItem("Current Quality Level", QualitySettings.names[currentQualityLevel]); + m_ApplyExpensiveChanges = GUILayout.Toggle(m_ApplyExpensiveChanges, "Apply expensive changes on quality level change."); + + int newQualityLevel = GUILayout.SelectionGrid(currentQualityLevel, QualitySettings.names, 3, "toggle"); + if (newQualityLevel != currentQualityLevel) + { + QualitySettings.SetQualityLevel(newQualityLevel, m_ApplyExpensiveChanges); + } + } + GUILayout.EndVertical(); + + GUILayout.Label("Rendering Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Active Color Space", QualitySettings.activeColorSpace.ToString()); + DrawItem("Desired Color Space", QualitySettings.desiredColorSpace.ToString()); + DrawItem("Max Queued Frames", QualitySettings.maxQueuedFrames.ToString()); + DrawItem("Pixel Light Count", QualitySettings.pixelLightCount.ToString()); + DrawItem("Master Texture Limit", QualitySettings.globalTextureMipmapLimit.ToString()); + DrawItem("Anisotropic Filtering", QualitySettings.anisotropicFiltering.ToString()); + DrawItem("Anti Aliasing", QualitySettings.antiAliasing.ToString()); +#if UNITY_5_5_OR_NEWER + DrawItem("Soft Particles", QualitySettings.softParticles.ToString()); +#endif + DrawItem("Soft Vegetation", QualitySettings.softVegetation.ToString()); + DrawItem("Realtime Reflection Probes", QualitySettings.realtimeReflectionProbes.ToString()); + DrawItem("Billboards Face Camera Position", QualitySettings.billboardsFaceCameraPosition.ToString()); +#if UNITY_2017_1_OR_NEWER + DrawItem("Resolution Scaling Fixed DPI Factor", QualitySettings.resolutionScalingFixedDPIFactor.ToString()); +#endif +#if UNITY_2018_2_OR_NEWER + DrawItem("Texture Streaming Enabled", QualitySettings.streamingMipmapsActive.ToString()); + DrawItem("Texture Streaming Add All Cameras", QualitySettings.streamingMipmapsAddAllCameras.ToString()); + DrawItem("Texture Streaming Memory Budget", QualitySettings.streamingMipmapsMemoryBudget.ToString()); + DrawItem("Texture Streaming Renderers Per Frame", QualitySettings.streamingMipmapsRenderersPerFrame.ToString()); + DrawItem("Texture Streaming Max Level Reduction", QualitySettings.streamingMipmapsMaxLevelReduction.ToString()); + DrawItem("Texture Streaming Max File IO Requests", QualitySettings.streamingMipmapsMaxFileIORequests.ToString()); +#endif + } + GUILayout.EndVertical(); + + GUILayout.Label("Shadows Information"); + GUILayout.BeginVertical("box"); + { +#if UNITY_2017_1_OR_NEWER + DrawItem("Shadowmask Mode", QualitySettings.shadowmaskMode.ToString()); +#endif +#if UNITY_5_5_OR_NEWER + DrawItem("Shadow Quality", QualitySettings.shadows.ToString()); +#endif +#if UNITY_5_4_OR_NEWER + DrawItem("Shadow Resolution", QualitySettings.shadowResolution.ToString()); +#endif + DrawItem("Shadow Projection", QualitySettings.shadowProjection.ToString()); + DrawItem("Shadow Distance", QualitySettings.shadowDistance.ToString()); + DrawItem("Shadow Near Plane Offset", QualitySettings.shadowNearPlaneOffset.ToString()); + DrawItem("Shadow Cascades", QualitySettings.shadowCascades.ToString()); + DrawItem("Shadow Cascade 2 Split", QualitySettings.shadowCascade2Split.ToString()); + DrawItem("Shadow Cascade 4 Split", QualitySettings.shadowCascade4Split.ToString()); + } + GUILayout.EndVertical(); + + GUILayout.Label("Other Information"); + GUILayout.BeginVertical("box"); + { +#if UNITY_2019_1_OR_NEWER + DrawItem("Skin Weights", QualitySettings.skinWeights.ToString()); +#else + DrawItem("Blend Weights", QualitySettings.blendWeights.ToString()); +#endif + DrawItem("VSync Count", QualitySettings.vSyncCount.ToString()); + DrawItem("LOD Bias", QualitySettings.lodBias.ToString()); + DrawItem("Maximum LOD Level", QualitySettings.maximumLODLevel.ToString()); + DrawItem("Particle Raycast Budget", QualitySettings.particleRaycastBudget.ToString()); + DrawItem("Async Upload Time Slice", Utility.Text.Format("{0} ms", QualitySettings.asyncUploadTimeSlice)); + DrawItem("Async Upload Buffer Size", Utility.Text.Format("{0} MB", QualitySettings.asyncUploadBufferSize)); +#if UNITY_2018_3_OR_NEWER + DrawItem("Async Upload Persistent Buffer", QualitySettings.asyncUploadPersistentBuffer.ToString()); +#endif + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.QualityInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.QualityInformationWindow.cs.meta new file mode 100644 index 00000000..5ff5715b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.QualityInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9e0be8441f814651a4a238586278df12 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.Sample.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.Sample.cs new file mode 100644 index 00000000..9f57a4b7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.Sample.cs @@ -0,0 +1,60 @@ +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed partial class RuntimeMemoryInformationWindow : ScrollableDebuggerWindowBase where T : UnityEngine.Object + { + private sealed class Sample + { + private readonly string m_Name; + private readonly string m_Type; + private readonly long m_Size; + private bool m_Highlight; + + public Sample(string name, string type, long size) + { + m_Name = name; + m_Type = type; + m_Size = size; + m_Highlight = false; + } + + public string Name + { + get + { + return m_Name; + } + } + + public string Type + { + get + { + return m_Type; + } + } + + public long Size + { + get + { + return m_Size; + } + } + + public bool Highlight + { + get + { + return m_Highlight; + } + set + { + m_Highlight = value; + } + } + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.Sample.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.Sample.cs.meta new file mode 100644 index 00000000..f39141bd --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.Sample.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c056a5278fb046c693656d9b3c5d1639 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.cs new file mode 100644 index 00000000..458266c4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +#if UNITY_5_5_OR_NEWER +using UnityEngine.Profiling; +#endif + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed partial class RuntimeMemoryInformationWindow : ScrollableDebuggerWindowBase where T : UnityEngine.Object + { + private const int ShowSampleCount = 300; + + private readonly List m_Samples = new List(); + private readonly Comparison m_SampleComparer = SampleComparer; + private DateTime m_SampleTime = DateTime.MinValue; + private long m_SampleSize = 0L; + private long m_DuplicateSampleSize = 0L; + private int m_DuplicateSimpleCount = 0; + + protected override void OnDrawScrollableWindow() + { + string typeName = typeof(T).Name; + GUILayout.Label(Utility.Text.Format("{0} Runtime Memory Information", typeName)); + GUILayout.BeginVertical("box"); + { + if (GUILayout.Button(Utility.Text.Format("Take Sample for {0}", typeName), GUILayout.Height(30f))) + { + TakeSample(); + } + + if (m_SampleTime <= DateTime.MinValue) + { + GUILayout.Label(Utility.Text.Format("Please take sample for {0} first.", typeName)); + } + else + { + if (m_DuplicateSimpleCount > 0) + { + GUILayout.Label(Utility.Text.Format("{0} {1}s ({2}) obtained at {3:yyyy-MM-dd HH:mm:ss}, while {4} {1}s ({5}) might be duplicated.", m_Samples.Count, typeName, GetByteLengthString(m_SampleSize), m_SampleTime.ToLocalTime(), m_DuplicateSimpleCount, GetByteLengthString(m_DuplicateSampleSize))); + } + else + { + GUILayout.Label(Utility.Text.Format("{0} {1}s ({2}) obtained at {3:yyyy-MM-dd HH:mm:ss}.", m_Samples.Count, typeName, GetByteLengthString(m_SampleSize), m_SampleTime.ToLocalTime())); + } + + if (m_Samples.Count > 0) + { + GUILayout.BeginHorizontal(); + { + GUILayout.Label(Utility.Text.Format("{0} Name", typeName)); + GUILayout.Label("Type", GUILayout.Width(240f)); + GUILayout.Label("Size", GUILayout.Width(80f)); + } + GUILayout.EndHorizontal(); + } + + int count = 0; + for (int i = 0; i < m_Samples.Count; i++) + { + GUILayout.BeginHorizontal(); + { + GUILayout.Label(m_Samples[i].Highlight ? Utility.Text.Format("{0}", m_Samples[i].Name) : m_Samples[i].Name); + GUILayout.Label(m_Samples[i].Highlight ? Utility.Text.Format("{0}", m_Samples[i].Type) : m_Samples[i].Type, GUILayout.Width(240f)); + GUILayout.Label(m_Samples[i].Highlight ? Utility.Text.Format("{0}", GetByteLengthString(m_Samples[i].Size)) : GetByteLengthString(m_Samples[i].Size), GUILayout.Width(80f)); + } + GUILayout.EndHorizontal(); + + count++; + if (count >= ShowSampleCount) + { + break; + } + } + } + } + GUILayout.EndVertical(); + } + + private void TakeSample() + { + m_SampleTime = DateTime.UtcNow; + m_SampleSize = 0L; + m_DuplicateSampleSize = 0L; + m_DuplicateSimpleCount = 0; + m_Samples.Clear(); + + T[] samples = Resources.FindObjectsOfTypeAll(); + for (int i = 0; i < samples.Length; i++) + { + long sampleSize = 0L; +#if UNITY_5_6_OR_NEWER + sampleSize = Profiler.GetRuntimeMemorySizeLong(samples[i]); +#else + sampleSize = Profiler.GetRuntimeMemorySize(samples[i]); +#endif + m_SampleSize += sampleSize; + m_Samples.Add(new Sample(samples[i].name, samples[i].GetType().Name, sampleSize)); + } + + m_Samples.Sort(m_SampleComparer); + + for (int i = 1; i < m_Samples.Count; i++) + { + if (m_Samples[i].Name == m_Samples[i - 1].Name && m_Samples[i].Type == m_Samples[i - 1].Type && m_Samples[i].Size == m_Samples[i - 1].Size) + { + m_Samples[i].Highlight = true; + m_DuplicateSampleSize += m_Samples[i].Size; + m_DuplicateSimpleCount++; + } + } + } + + private static int SampleComparer(Sample a, Sample b) + { + int result = b.Size.CompareTo(a.Size); + if (result != 0) + { + return result; + } + + result = a.Type.CompareTo(b.Type); + if (result != 0) + { + return result; + } + + return a.Name.CompareTo(b.Name); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.cs.meta new file mode 100644 index 00000000..3f3a4395 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemoryInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c46a0358d21f41a1bffbeb15874b7986 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.Record.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.Record.cs new file mode 100644 index 00000000..47647b29 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.Record.cs @@ -0,0 +1,54 @@ +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed partial class RuntimeMemorySummaryWindow : ScrollableDebuggerWindowBase + { + private sealed class Record + { + private readonly string m_Name; + private int m_Count; + private long m_Size; + + public Record(string name) + { + m_Name = name; + m_Count = 0; + m_Size = 0L; + } + + public string Name + { + get + { + return m_Name; + } + } + + public int Count + { + get + { + return m_Count; + } + set + { + m_Count = value; + } + } + + public long Size + { + get + { + return m_Size; + } + set + { + m_Size = value; + } + } + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.Record.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.Record.cs.meta new file mode 100644 index 00000000..2c1f1f89 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.Record.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0fe142cd19ea404092e714667f5e75d1 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.cs new file mode 100644 index 00000000..6edbb22c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +#if UNITY_5_5_OR_NEWER +using UnityEngine.Profiling; +#endif + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed partial class RuntimeMemorySummaryWindow : ScrollableDebuggerWindowBase + { + private readonly List m_Records = new List(); + private readonly Comparison m_RecordComparer = RecordComparer; + private DateTime m_SampleTime = DateTime.MinValue; + private int m_SampleCount = 0; + private long m_SampleSize = 0L; + + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Runtime Memory Summary"); + GUILayout.BeginVertical("box"); + { + if (GUILayout.Button("Take Sample", GUILayout.Height(30f))) + { + TakeSample(); + } + + if (m_SampleTime <= DateTime.MinValue) + { + GUILayout.Label("Please take sample first."); + } + else + { + GUILayout.Label(Utility.Text.Format("{0} Objects ({1}) obtained at {2:yyyy-MM-dd HH:mm:ss}.", m_SampleCount, GetByteLengthString(m_SampleSize), m_SampleTime.ToLocalTime())); + + GUILayout.BeginHorizontal(); + { + GUILayout.Label("Type"); + GUILayout.Label("Count", GUILayout.Width(120f)); + GUILayout.Label("Size", GUILayout.Width(120f)); + } + GUILayout.EndHorizontal(); + + for (int i = 0; i < m_Records.Count; i++) + { + GUILayout.BeginHorizontal(); + { + GUILayout.Label(m_Records[i].Name); + GUILayout.Label(m_Records[i].Count.ToString(), GUILayout.Width(120f)); + GUILayout.Label(GetByteLengthString(m_Records[i].Size), GUILayout.Width(120f)); + } + GUILayout.EndHorizontal(); + } + } + } + GUILayout.EndVertical(); + } + + private void TakeSample() + { + m_Records.Clear(); + m_SampleTime = DateTime.UtcNow; + m_SampleCount = 0; + m_SampleSize = 0L; + + UnityEngine.Object[] samples = Resources.FindObjectsOfTypeAll(); + for (int i = 0; i < samples.Length; i++) + { + long sampleSize = 0L; +#if UNITY_5_6_OR_NEWER + sampleSize = Profiler.GetRuntimeMemorySizeLong(samples[i]); +#else + sampleSize = Profiler.GetRuntimeMemorySize(samples[i]); +#endif + string name = samples[i].GetType().Name; + m_SampleCount++; + m_SampleSize += sampleSize; + + Record record = null; + foreach (Record r in m_Records) + { + if (r.Name == name) + { + record = r; + break; + } + } + + if (record == null) + { + record = new Record(name); + m_Records.Add(record); + } + + record.Count++; + record.Size += sampleSize; + } + + m_Records.Sort(m_RecordComparer); + } + + private static int RecordComparer(Record a, Record b) + { + int result = b.Size.CompareTo(a.Size); + if (result != 0) + { + return result; + } + + result = a.Count.CompareTo(b.Count); + if (result != 0) + { + return result; + } + + return a.Name.CompareTo(b.Name); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.cs.meta new file mode 100644 index 00000000..b341c6a8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.RuntimeMemorySummaryWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 57978b9ccd8246c8a63d3384f9010078 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SceneInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SceneInformationWindow.cs new file mode 100644 index 00000000..b1311645 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SceneInformationWindow.cs @@ -0,0 +1,37 @@ +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class SceneInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Scene Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Scene Count", SceneManager.sceneCount.ToString()); + DrawItem("Scene Count In Build Settings", SceneManager.sceneCountInBuildSettings.ToString()); + + Scene activeScene = SceneManager.GetActiveScene(); +#if UNITY_2018_3_OR_NEWER + DrawItem("Active Scene Handle", activeScene.handle.ToString()); +#endif + DrawItem("Active Scene Name", activeScene.name); + DrawItem("Active Scene Path", activeScene.path); + DrawItem("Active Scene Build Index", activeScene.buildIndex.ToString()); + DrawItem("Active Scene Is Dirty", activeScene.isDirty.ToString()); + DrawItem("Active Scene Is Loaded", activeScene.isLoaded.ToString()); + DrawItem("Active Scene Is Valid", activeScene.IsValid().ToString()); + DrawItem("Active Scene Root Count", activeScene.rootCount.ToString()); +#if UNITY_2019_1_OR_NEWER + DrawItem("Active Scene Is Sub Scene", activeScene.isSubScene.ToString()); +#endif + } + GUILayout.EndVertical(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SceneInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SceneInformationWindow.cs.meta new file mode 100644 index 00000000..a1eec3fe --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SceneInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 23188b9cc7074bbfaeb3023f6a2e317e +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScreenInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScreenInformationWindow.cs new file mode 100644 index 00000000..a5dc67f1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScreenInformationWindow.cs @@ -0,0 +1,87 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class ScreenInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Screen Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Current Resolution", GetResolutionString(Screen.currentResolution)); + DrawItem("Screen Width", Utility.Text.Format("{0} px / {1:F2} in / {2:F2} cm", Screen.width, Utility.Converter.GetInchesFromPixels(Screen.width), Utility.Converter.GetCentimetersFromPixels(Screen.width))); + DrawItem("Screen Height", Utility.Text.Format("{0} px / {1:F2} in / {2:F2} cm", Screen.height, Utility.Converter.GetInchesFromPixels(Screen.height), Utility.Converter.GetCentimetersFromPixels(Screen.height))); + DrawItem("Screen DPI", Screen.dpi.ToString("F2")); + DrawItem("Screen Orientation", Screen.orientation.ToString()); + DrawItem("Is Full Screen", Screen.fullScreen.ToString()); +#if UNITY_2018_1_OR_NEWER + DrawItem("Full Screen Mode", Screen.fullScreenMode.ToString()); +#endif + DrawItem("Sleep Timeout", GetSleepTimeoutDescription(Screen.sleepTimeout)); +#if UNITY_2019_2_OR_NEWER + DrawItem("Brightness", Screen.brightness.ToString("F2")); +#endif + DrawItem("Cursor Visible", Cursor.visible.ToString()); + DrawItem("Cursor Lock State", Cursor.lockState.ToString()); + DrawItem("Auto Landscape Left", Screen.autorotateToLandscapeLeft.ToString()); + DrawItem("Auto Landscape Right", Screen.autorotateToLandscapeRight.ToString()); + DrawItem("Auto Portrait", Screen.autorotateToPortrait.ToString()); + DrawItem("Auto Portrait Upside Down", Screen.autorotateToPortraitUpsideDown.ToString()); +#if UNITY_2017_2_OR_NEWER && !UNITY_2017_2_0 + DrawItem("Safe Area", Screen.safeArea.ToString()); +#endif +#if UNITY_2019_2_OR_NEWER + DrawItem("Cutouts", GetCutoutsString(Screen.cutouts)); +#endif + DrawItem("Support Resolutions", GetResolutionsString(Screen.resolutions)); + } + GUILayout.EndVertical(); + } + + private string GetSleepTimeoutDescription(int sleepTimeout) + { + if (sleepTimeout == SleepTimeout.NeverSleep) + { + return "Never Sleep"; + } + + if (sleepTimeout == SleepTimeout.SystemSetting) + { + return "System Setting"; + } + + return sleepTimeout.ToString(); + } + + private string GetResolutionString(Resolution resolution) + { + return Utility.Text.Format("{0} x {1} @ {2}Hz", resolution.width, resolution.height, resolution.refreshRate); + } + + private string GetCutoutsString(Rect[] cutouts) + { + string[] cutoutStrings = new string[cutouts.Length]; + for (int i = 0; i < cutouts.Length; i++) + { + cutoutStrings[i] = cutouts[i].ToString(); + } + + return string.Join("; ", cutoutStrings); + } + + private string GetResolutionsString(Resolution[] resolutions) + { + string[] resolutionStrings = new string[resolutions.Length]; + for (int i = 0; i < resolutions.Length; i++) + { + resolutionStrings[i] = GetResolutionString(resolutions[i]); + } + + return string.Join("; ", resolutionStrings); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScreenInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScreenInformationWindow.cs.meta new file mode 100644 index 00000000..47c405ac --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScreenInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b2e9629c3200474c83a384685f1b32d0 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScrollableDebuggerWindowBase.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScrollableDebuggerWindowBase.cs new file mode 100644 index 00000000..06992b79 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScrollableDebuggerWindowBase.cs @@ -0,0 +1,92 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private abstract class ScrollableDebuggerWindowBase : IDebuggerWindow + { + private const float TitleWidth = 240f; + private Vector2 m_ScrollPosition = Vector2.zero; + + public virtual void Initialize(params object[] args) + { + } + + public virtual void Shutdown() + { + } + + public virtual void OnEnter() + { + } + + public virtual void OnLeave() + { + } + + public virtual void OnUpdate(float elapseSeconds, float realElapseSeconds) + { + } + + public void OnDraw() + { + m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition); + { + OnDrawScrollableWindow(); + } + GUILayout.EndScrollView(); + } + + protected abstract void OnDrawScrollableWindow(); + + protected static void DrawItem(string title, string content) + { + GUILayout.BeginHorizontal(); + { + GUILayout.Label(title, GUILayout.Width(TitleWidth)); + if (GUILayout.Button(content, "label")) + { + CopyToClipboard(content); + } + } + GUILayout.EndHorizontal(); + } + + protected static string GetByteLengthString(long byteLength) + { + if (byteLength < 1024L) // 2 ^ 10 + { + return Utility.Text.Format("{0} Bytes", byteLength); + } + + if (byteLength < 1048576L) // 2 ^ 20 + { + return Utility.Text.Format("{0:F2} KB", byteLength / 1024f); + } + + if (byteLength < 1073741824L) // 2 ^ 30 + { + return Utility.Text.Format("{0:F2} MB", byteLength / 1048576f); + } + + if (byteLength < 1099511627776L) // 2 ^ 40 + { + return Utility.Text.Format("{0:F2} GB", byteLength / 1073741824f); + } + + if (byteLength < 1125899906842624L) // 2 ^ 50 + { + return Utility.Text.Format("{0:F2} TB", byteLength / 1099511627776f); + } + + if (byteLength < 1152921504606846976L) // 2 ^ 60 + { + return Utility.Text.Format("{0:F2} PB", byteLength / 1125899906842624f); + } + + return Utility.Text.Format("{0:F2} EB", byteLength / 1152921504606846976f); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScrollableDebuggerWindowBase.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScrollableDebuggerWindowBase.cs.meta new file mode 100644 index 00000000..4daea339 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.ScrollableDebuggerWindowBase.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1ab46898981a41189c05d040d7c9291e +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SettingsWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SettingsWindow.cs new file mode 100644 index 00000000..3736f4ed --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SettingsWindow.cs @@ -0,0 +1,218 @@ +using System; +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class SettingsWindow : ScrollableDebuggerWindowBase + { + private DebuggerModule _mDebuggerModule = null; + private SettingModule _mSettingModule = null; + private float m_LastIconX = 0f; + private float m_LastIconY = 0f; + private float m_LastWindowX = 0f; + private float m_LastWindowY = 0f; + private float m_LastWindowWidth = 0f; + private float m_LastWindowHeight = 0f; + private float m_LastWindowScale = 0f; + + public override void Initialize(params object[] args) + { + _mDebuggerModule = ModuleSystem.GetModule(); + if (_mDebuggerModule == null) + { + Log.Fatal("Debugger component is invalid."); + return; + } + + _mSettingModule = ModuleSystem.GetModule(); + if (_mSettingModule == null) + { + Log.Fatal("Setting component is invalid."); + return; + } + + m_LastIconX = _mSettingModule.GetFloat("Debugger.Icon.X", DefaultIconRect.x); + m_LastIconY = _mSettingModule.GetFloat("Debugger.Icon.Y", DefaultIconRect.y); + m_LastWindowX = _mSettingModule.GetFloat("Debugger.Window.X", DefaultWindowRect.x); + m_LastWindowY = _mSettingModule.GetFloat("Debugger.Window.Y", DefaultWindowRect.y); + m_LastWindowWidth = _mSettingModule.GetFloat("Debugger.Window.Width", DefaultWindowRect.width); + m_LastWindowHeight = _mSettingModule.GetFloat("Debugger.Window.Height", DefaultWindowRect.height); + _mDebuggerModule.WindowScale = m_LastWindowScale = _mSettingModule.GetFloat("Debugger.Window.Scale", DefaultWindowScale); + _mDebuggerModule.IconRect = new Rect(m_LastIconX, m_LastIconY, DefaultIconRect.width, DefaultIconRect.height); + _mDebuggerModule.WindowRect = new Rect(m_LastWindowX, m_LastWindowY, m_LastWindowWidth, m_LastWindowHeight); + } + + public override void OnUpdate(float elapseSeconds, float realElapseSeconds) + { + if (Math.Abs(m_LastIconX - _mDebuggerModule.IconRect.x) > 0.01f) + { + m_LastIconX = _mDebuggerModule.IconRect.x; + _mSettingModule.SetFloat("Debugger.Icon.X", _mDebuggerModule.IconRect.x); + } + + if (Math.Abs(m_LastIconY - _mDebuggerModule.IconRect.y) > 0.01f) + { + m_LastIconY = _mDebuggerModule.IconRect.y; + _mSettingModule.SetFloat("Debugger.Icon.Y", _mDebuggerModule.IconRect.y); + } + + if (Math.Abs(m_LastWindowX - _mDebuggerModule.WindowRect.x) > 0.01f) + { + m_LastWindowX = _mDebuggerModule.WindowRect.x; + _mSettingModule.SetFloat("Debugger.Window.X", _mDebuggerModule.WindowRect.x); + } + + if (Math.Abs(m_LastWindowY - _mDebuggerModule.WindowRect.y) > 0.01f) + { + m_LastWindowY = _mDebuggerModule.WindowRect.y; + _mSettingModule.SetFloat("Debugger.Window.Y", _mDebuggerModule.WindowRect.y); + } + + if (Math.Abs(m_LastWindowWidth - _mDebuggerModule.WindowRect.width) > 0.01f) + { + m_LastWindowWidth = _mDebuggerModule.WindowRect.width; + _mSettingModule.SetFloat("Debugger.Window.Width", _mDebuggerModule.WindowRect.width); + } + + if (Math.Abs(m_LastWindowHeight - _mDebuggerModule.WindowRect.height) > 0.01f) + { + m_LastWindowHeight = _mDebuggerModule.WindowRect.height; + _mSettingModule.SetFloat("Debugger.Window.Height", _mDebuggerModule.WindowRect.height); + } + + if (Math.Abs(m_LastWindowScale - _mDebuggerModule.WindowScale) > 0.01f) + { + m_LastWindowScale = _mDebuggerModule.WindowScale; + _mSettingModule.SetFloat("Debugger.Window.Scale", _mDebuggerModule.WindowScale); + } + } + + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Window Settings"); + GUILayout.BeginVertical("box"); + { + GUILayout.BeginHorizontal(); + { + GUILayout.Label("Position:", GUILayout.Width(60f)); + GUILayout.Label("Drag window caption to move position."); + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + { + float width = _mDebuggerModule.WindowRect.width; + GUILayout.Label("Width:", GUILayout.Width(60f)); + if (GUILayout.RepeatButton("-", GUILayout.Width(30f))) + { + width--; + } + width = GUILayout.HorizontalSlider(width, 100f, Screen.width - 20f); + if (GUILayout.RepeatButton("+", GUILayout.Width(30f))) + { + width++; + } + width = Mathf.Clamp(width, 100f, Screen.width - 20f); + if (Math.Abs(width - _mDebuggerModule.WindowRect.width) > 0.01f) + { + _mDebuggerModule.WindowRect = new Rect(_mDebuggerModule.WindowRect.x, _mDebuggerModule.WindowRect.y, width, _mDebuggerModule.WindowRect.height); + } + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + { + float height = _mDebuggerModule.WindowRect.height; + GUILayout.Label("Height:", GUILayout.Width(60f)); + if (GUILayout.RepeatButton("-", GUILayout.Width(30f))) + { + height--; + } + height = GUILayout.HorizontalSlider(height, 100f, Screen.height - 20f); + if (GUILayout.RepeatButton("+", GUILayout.Width(30f))) + { + height++; + } + height = Mathf.Clamp(height, 100f, Screen.height - 20f); + if (Math.Abs(height - _mDebuggerModule.WindowRect.height) > 0.01f) + { + _mDebuggerModule.WindowRect = new Rect(_mDebuggerModule.WindowRect.x, _mDebuggerModule.WindowRect.y, _mDebuggerModule.WindowRect.width, height); + } + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + { + float scale = _mDebuggerModule.WindowScale; + GUILayout.Label("Scale:", GUILayout.Width(60f)); + if (GUILayout.RepeatButton("-", GUILayout.Width(30f))) + { + scale -= 0.01f; + } + scale = GUILayout.HorizontalSlider(scale, 0.5f, 4f); + if (GUILayout.RepeatButton("+", GUILayout.Width(30f))) + { + scale += 0.01f; + } + scale = Mathf.Clamp(scale, 0.5f, 4f); + if (Math.Abs(scale - _mDebuggerModule.WindowScale) > 0.01f) + { + _mDebuggerModule.WindowScale = scale; + } + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + { + if (GUILayout.Button("0.5x", GUILayout.Height(60f))) + { + _mDebuggerModule.WindowScale = 0.5f; + } + if (GUILayout.Button("1.0x", GUILayout.Height(60f))) + { + _mDebuggerModule.WindowScale = 1f; + } + if (GUILayout.Button("1.5x", GUILayout.Height(60f))) + { + _mDebuggerModule.WindowScale = 1.5f; + } + if (GUILayout.Button("2.0x", GUILayout.Height(60f))) + { + _mDebuggerModule.WindowScale = 2f; + } + if (GUILayout.Button("2.5x", GUILayout.Height(60f))) + { + _mDebuggerModule.WindowScale = 2.5f; + } + if (GUILayout.Button("3.0x", GUILayout.Height(60f))) + { + _mDebuggerModule.WindowScale = 3f; + } + if (GUILayout.Button("3.5x", GUILayout.Height(60f))) + { + _mDebuggerModule.WindowScale = 3.5f; + } + if (GUILayout.Button("4.0x", GUILayout.Height(60f))) + { + _mDebuggerModule.WindowScale = 4f; + } + } + GUILayout.EndHorizontal(); + + if (GUILayout.Button("Reset Layout", GUILayout.Height(30f))) + { + _mDebuggerModule.ResetLayout(); + } + } + GUILayout.EndVertical(); + } + + public override void OnLeave() + { + _mSettingModule.Save(); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SettingsWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SettingsWindow.cs.meta new file mode 100644 index 00000000..7c240bf5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SettingsWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d6cd4faabca74c3f9af9cd407d4663d5 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SystemInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SystemInformationWindow.cs new file mode 100644 index 00000000..f59176bc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SystemInformationWindow.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class SystemInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("System Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Device Unique ID", SystemInfo.deviceUniqueIdentifier); + DrawItem("Device Name", SystemInfo.deviceName); + DrawItem("Device Type", SystemInfo.deviceType.ToString()); + DrawItem("Device Model", SystemInfo.deviceModel); + DrawItem("Processor Type", SystemInfo.processorType); + DrawItem("Processor Count", SystemInfo.processorCount.ToString()); + DrawItem("Processor Frequency", Utility.Text.Format("{0} MHz", SystemInfo.processorFrequency)); + DrawItem("System Memory Size", Utility.Text.Format("{0} MB", SystemInfo.systemMemorySize)); +#if UNITY_5_5_OR_NEWER + DrawItem("Operating System Family", SystemInfo.operatingSystemFamily.ToString()); +#endif + DrawItem("Operating System", SystemInfo.operatingSystem); +#if UNITY_5_6_OR_NEWER + DrawItem("Battery Status", SystemInfo.batteryStatus.ToString()); + DrawItem("Battery Level", GetBatteryLevelString(SystemInfo.batteryLevel)); +#endif +#if UNITY_5_4_OR_NEWER + DrawItem("Supports Audio", SystemInfo.supportsAudio.ToString()); +#endif + DrawItem("Supports Location Service", SystemInfo.supportsLocationService.ToString()); + DrawItem("Supports Accelerometer", SystemInfo.supportsAccelerometer.ToString()); + DrawItem("Supports Gyroscope", SystemInfo.supportsGyroscope.ToString()); + DrawItem("Supports Vibration", SystemInfo.supportsVibration.ToString()); + DrawItem("Genuine", Application.genuine.ToString()); + DrawItem("Genuine Check Available", Application.genuineCheckAvailable.ToString()); + } + GUILayout.EndVertical(); + } + + private string GetBatteryLevelString(float batteryLevel) + { + if (batteryLevel < 0f) + { + return "Unavailable"; + } + + return batteryLevel.ToString("P0"); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SystemInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SystemInformationWindow.cs.meta new file mode 100644 index 00000000..24652fd6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.SystemInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dce6d86504004300ae4dbbd204f53f8b +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.TimeInformationWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.TimeInformationWindow.cs new file mode 100644 index 00000000..7ea50ca7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.TimeInformationWindow.cs @@ -0,0 +1,68 @@ +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class TimeInformationWindow : ScrollableDebuggerWindowBase + { + protected override void OnDrawScrollableWindow() + { + GUILayout.Label("Time Information"); + GUILayout.BeginVertical("box"); + { + DrawItem("Time Scale", Utility.Text.Format("{0} [{1}]", Time.timeScale, GetTimeScaleDescription(Time.timeScale))); + DrawItem("Realtime Since Startup", Time.realtimeSinceStartup.ToString()); + DrawItem("Time Since Level Load", Time.timeSinceLevelLoad.ToString()); + DrawItem("Time", Time.time.ToString()); + DrawItem("Fixed Time", Time.fixedTime.ToString()); + DrawItem("Unscaled Time", Time.unscaledTime.ToString()); +#if UNITY_5_6_OR_NEWER + DrawItem("Fixed Unscaled Time", Time.fixedUnscaledTime.ToString()); +#endif + DrawItem("Delta Time", Time.deltaTime.ToString()); + DrawItem("Fixed Delta Time", Time.fixedDeltaTime.ToString()); + DrawItem("Unscaled Delta Time", Time.unscaledDeltaTime.ToString()); +#if UNITY_5_6_OR_NEWER + DrawItem("Fixed Unscaled Delta Time", Time.fixedUnscaledDeltaTime.ToString()); +#endif + DrawItem("Smooth Delta Time", Time.smoothDeltaTime.ToString()); + DrawItem("Maximum Delta Time", Time.maximumDeltaTime.ToString()); +#if UNITY_5_5_OR_NEWER + DrawItem("Maximum Particle Delta Time", Time.maximumParticleDeltaTime.ToString()); +#endif + DrawItem("Frame Count", Time.frameCount.ToString()); + DrawItem("Rendered Frame Count", Time.renderedFrameCount.ToString()); + DrawItem("Capture Framerate", Time.captureFramerate.ToString()); +#if UNITY_2019_2_OR_NEWER + DrawItem("Capture Delta Time", Time.captureDeltaTime.ToString()); +#endif +#if UNITY_5_6_OR_NEWER + DrawItem("In Fixed Time Step", Time.inFixedTimeStep.ToString()); +#endif + } + GUILayout.EndVertical(); + } + + private string GetTimeScaleDescription(float timeScale) + { + if (timeScale <= 0f) + { + return "Pause"; + } + + if (timeScale < 1f) + { + return "Slower"; + } + + if (timeScale > 1f) + { + return "Faster"; + } + + return "Normal"; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.TimeInformationWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.TimeInformationWindow.cs.meta new file mode 100644 index 00000000..2d144445 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/Component/DebuggerModule.TimeInformationWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 49e6de7a5fa043ba9c489ac67147bbee +timeCreated: 1680489775 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerActiveWindowType.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerActiveWindowType.cs new file mode 100644 index 00000000..c6850b25 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerActiveWindowType.cs @@ -0,0 +1,28 @@ +namespace TEngine +{ + /// + /// 调试器激活窗口类型。 + /// + public enum DebuggerActiveWindowType : byte + { + /// + /// 总是打开。 + /// + AlwaysOpen = 0, + + /// + /// 仅在开发模式时打开。 + /// + OnlyOpenWhenDevelopment, + + /// + /// 仅在编辑器中打开。 + /// + OnlyOpenInEditor, + + /// + /// 总是关闭。 + /// + AlwaysClose, + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerActiveWindowType.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerActiveWindowType.cs.meta new file mode 100644 index 00000000..38680341 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerActiveWindowType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 71186a1869d3486e8a8b47c9053623c5 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.ConsoleWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.ConsoleWindow.cs new file mode 100644 index 00000000..3a8eaea5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.ConsoleWindow.cs @@ -0,0 +1,416 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + [Serializable] + private sealed class ConsoleWindow : IDebuggerWindow + { + private readonly Queue _logNodes = new Queue(); + + private SettingModule _settingModule = null; + private Vector2 _logScrollPosition = Vector2.zero; + private Vector2 _stackScrollPosition = Vector2.zero; + private int _infoCount = 0; + private int _warningCount = 0; + private int _errorCount = 0; + private int _fatalCount = 0; + private LogNode _selectedNode = null; + private bool _lastLockScroll = true; + private bool _lastInfoFilter = true; + private bool _lastWarningFilter = true; + private bool _lastErrorFilter = true; + private bool _lastFatalFilter = true; + + [SerializeField] + private bool m_LockScroll = true; + + [SerializeField] + private int m_MaxLine = 100; + + [SerializeField] + private bool m_InfoFilter = true; + + [SerializeField] + private bool m_WarningFilter = true; + + [SerializeField] + private bool m_ErrorFilter = true; + + [SerializeField] + private bool m_FatalFilter = true; + + [SerializeField] + private Color32 m_InfoColor = Color.white; + + [SerializeField] + private Color32 m_WarningColor = Color.yellow; + + [SerializeField] + private Color32 m_ErrorColor = Color.red; + + [SerializeField] + private Color32 m_FatalColor = new Color(0.7f, 0.2f, 0.2f); + + public bool LockScroll + { + get => m_LockScroll; + set => m_LockScroll = value; + } + + public int MaxLine + { + get => m_MaxLine; + set => m_MaxLine = value; + } + + public bool InfoFilter + { + get => m_InfoFilter; + set => m_InfoFilter = value; + } + + public bool WarningFilter + { + get => m_WarningFilter; + set => m_WarningFilter = value; + } + + public bool ErrorFilter + { + get => m_ErrorFilter; + set => m_ErrorFilter = value; + } + + public bool FatalFilter + { + get => m_FatalFilter; + set => m_FatalFilter = value; + } + + public int InfoCount => _infoCount; + + public int WarningCount => _warningCount; + + public int ErrorCount => _errorCount; + + public int FatalCount => _fatalCount; + + public Color32 InfoColor + { + get => m_InfoColor; + set => m_InfoColor = value; + } + + public Color32 WarningColor + { + get => m_WarningColor; + set => m_WarningColor = value; + } + + public Color32 ErrorColor + { + get => m_ErrorColor; + set => m_ErrorColor = value; + } + + public Color32 FatalColor + { + get => m_FatalColor; + set => m_FatalColor = value; + } + + public void Initialize(params object[] args) + { + _settingModule = ModuleSystem.GetModule(); + if (_settingModule == null) + { + Log.Fatal("Setting component is invalid."); + return; + } + + Application.logMessageReceived += OnLogMessageReceived; + m_LockScroll = _lastLockScroll = _settingModule.GetBool("Debugger.Console.LockScroll", true); + m_InfoFilter = _lastInfoFilter = _settingModule.GetBool("Debugger.Console.InfoFilter", true); + m_WarningFilter = _lastWarningFilter = _settingModule.GetBool("Debugger.Console.WarningFilter", true); + m_ErrorFilter = _lastErrorFilter = _settingModule.GetBool("Debugger.Console.ErrorFilter", true); + m_FatalFilter = _lastFatalFilter = _settingModule.GetBool("Debugger.Console.FatalFilter", true); + } + + public void Shutdown() + { + Application.logMessageReceived -= OnLogMessageReceived; + Clear(); + } + + public void OnEnter() + { + } + + public void OnLeave() + { + } + + public void OnUpdate(float elapseSeconds, float realElapseSeconds) + { + if (_lastLockScroll != m_LockScroll) + { + _lastLockScroll = m_LockScroll; + _settingModule.SetBool("Debugger.Console.LockScroll", m_LockScroll); + } + + if (_lastInfoFilter != m_InfoFilter) + { + _lastInfoFilter = m_InfoFilter; + _settingModule.SetBool("Debugger.Console.InfoFilter", m_InfoFilter); + } + + if (_lastWarningFilter != m_WarningFilter) + { + _lastWarningFilter = m_WarningFilter; + _settingModule.SetBool("Debugger.Console.WarningFilter", m_WarningFilter); + } + + if (_lastErrorFilter != m_ErrorFilter) + { + _lastErrorFilter = m_ErrorFilter; + _settingModule.SetBool("Debugger.Console.ErrorFilter", m_ErrorFilter); + } + + if (_lastFatalFilter != m_FatalFilter) + { + _lastFatalFilter = m_FatalFilter; + _settingModule.SetBool("Debugger.Console.FatalFilter", m_FatalFilter); + } + } + + public void OnDraw() + { + RefreshCount(); + + GUILayout.BeginHorizontal(); + { + if (GUILayout.Button("Clear All", GUILayout.Width(100f))) + { + Clear(); + } + m_LockScroll = GUILayout.Toggle(m_LockScroll, "Lock Scroll", GUILayout.Width(90f)); + GUILayout.FlexibleSpace(); + m_InfoFilter = GUILayout.Toggle(m_InfoFilter, Utility.Text.Format("Info ({0})", _infoCount), GUILayout.Width(90f)); + m_WarningFilter = GUILayout.Toggle(m_WarningFilter, Utility.Text.Format("Warning ({0})", _warningCount), GUILayout.Width(90f)); + m_ErrorFilter = GUILayout.Toggle(m_ErrorFilter, Utility.Text.Format("Error ({0})", _errorCount), GUILayout.Width(90f)); + m_FatalFilter = GUILayout.Toggle(m_FatalFilter, Utility.Text.Format("Fatal ({0})", _fatalCount), GUILayout.Width(90f)); + } + GUILayout.EndHorizontal(); + + GUILayout.BeginVertical("box"); + { + if (m_LockScroll) + { + _logScrollPosition.y = float.MaxValue; + } + + _logScrollPosition = GUILayout.BeginScrollView(_logScrollPosition); + { + bool selected = false; + foreach (LogNode logNode in _logNodes) + { + switch (logNode.LogType) + { + case LogType.Log: + if (!m_InfoFilter) + { + continue; + } + break; + + case LogType.Warning: + if (!m_WarningFilter) + { + continue; + } + break; + + case LogType.Error: + if (!m_ErrorFilter) + { + continue; + } + break; + + case LogType.Exception: + if (!m_FatalFilter) + { + continue; + } + break; + } + if (GUILayout.Toggle(_selectedNode == logNode, GetLogString(logNode))) + { + selected = true; + if (_selectedNode != logNode) + { + _selectedNode = logNode; + _stackScrollPosition = Vector2.zero; + } + } + } + if (!selected) + { + _selectedNode = null; + } + } + GUILayout.EndScrollView(); + } + GUILayout.EndVertical(); + + GUILayout.BeginVertical("box"); + { + _stackScrollPosition = GUILayout.BeginScrollView(_stackScrollPosition, GUILayout.Height(100f)); + { + if (_selectedNode != null) + { + Color32 color = GetLogStringColor(_selectedNode.LogType); + if (GUILayout.Button(Utility.Text.Format("{4}{6}{6}{5}", color.r, color.g, color.b, color.a, _selectedNode.LogMessage, _selectedNode.StackTrack, Environment.NewLine), "label")) + { + CopyToClipboard(Utility.Text.Format("{0}{2}{2}{1}", _selectedNode.LogMessage, _selectedNode.StackTrack, Environment.NewLine)); + } + } + } + GUILayout.EndScrollView(); + } + GUILayout.EndVertical(); + } + + private void Clear() + { + _logNodes.Clear(); + } + + public void RefreshCount() + { + _infoCount = 0; + _warningCount = 0; + _errorCount = 0; + _fatalCount = 0; + foreach (LogNode logNode in _logNodes) + { + switch (logNode.LogType) + { + case LogType.Log: + _infoCount++; + break; + + case LogType.Warning: + _warningCount++; + break; + + case LogType.Error: + _errorCount++; + break; + + case LogType.Exception: + _fatalCount++; + break; + } + } + } + + public void GetRecentLogs(List results) + { + if (results == null) + { + Log.Error("Results is invalid."); + return; + } + + results.Clear(); + foreach (LogNode logNode in _logNodes) + { + results.Add(logNode); + } + } + + public void GetRecentLogs(List results, int count) + { + if (results == null) + { + Log.Error("Results is invalid."); + return; + } + + if (count <= 0) + { + Log.Error("Count is invalid."); + return; + } + + int position = _logNodes.Count - count; + if (position < 0) + { + position = 0; + } + + int index = 0; + results.Clear(); + foreach (LogNode logNode in _logNodes) + { + if (index++ < position) + { + continue; + } + + results.Add(logNode); + } + } + + private void OnLogMessageReceived(string logMessage, string stackTrace, LogType logType) + { + if (logType == LogType.Assert) + { + logType = LogType.Error; + } + + _logNodes.Enqueue(LogNode.Create(logType, logMessage, stackTrace)); + while (_logNodes.Count > m_MaxLine) + { + MemoryPool.Release(_logNodes.Dequeue()); + } + } + + private string GetLogString(LogNode logNode) + { + Color32 color = GetLogStringColor(logNode.LogType); + return Utility.Text.Format("[{4:HH:mm:ss.fff}][{5}] {6}", color.r, color.g, color.b, color.a, logNode.LogTime.ToLocalTime(), logNode.LogFrameCount, logNode.LogMessage); + } + + internal Color32 GetLogStringColor(LogType logType) + { + Color32 color = Color.white; + switch (logType) + { + case LogType.Log: + color = m_InfoColor; + break; + + case LogType.Warning: + color = m_WarningColor; + break; + + case LogType.Error: + color = m_ErrorColor; + break; + + case LogType.Exception: + color = m_FatalColor; + break; + } + + return color; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.ConsoleWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.ConsoleWindow.cs.meta new file mode 100644 index 00000000..9cab1639 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.ConsoleWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dbdea71d14c947dab46792b72d024906 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.FpsCounter.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.FpsCounter.cs new file mode 100644 index 00000000..1a82ccf1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.FpsCounter.cs @@ -0,0 +1,67 @@ +namespace TEngine +{ + public sealed partial class DebuggerModule : Module + { + private sealed class FpsCounter + { + private float _updateInterval; + private float _currentFps; + private int _frames; + private float _accumulator; + private float _timeLeft; + + public FpsCounter(float updateInterval) + { + if (updateInterval <= 0f) + { + Log.Error("Update interval is invalid."); + return; + } + + _updateInterval = updateInterval; + Reset(); + } + + public float UpdateInterval + { + get => _updateInterval; + set + { + if (value <= 0f) + { + Log.Error("Update interval is invalid."); + return; + } + + _updateInterval = value; + Reset(); + } + } + + public float CurrentFps => _currentFps; + + public void Update(float elapseSeconds, float realElapseSeconds) + { + _frames++; + _accumulator += realElapseSeconds; + _timeLeft -= realElapseSeconds; + + if (_timeLeft <= 0f) + { + _currentFps = _accumulator > 0f ? _frames / _accumulator : 0f; + _frames = 0; + _accumulator = 0f; + _timeLeft += _updateInterval; + } + } + + private void Reset() + { + _currentFps = 0f; + _frames = 0; + _accumulator = 0f; + _timeLeft = 0f; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.FpsCounter.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.FpsCounter.cs.meta new file mode 100644 index 00000000..8e23ec01 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerComponent.FpsCounter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 37c643db0e8a488ebf3941df04d18c35 +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.DebuggerWindowGroup.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.DebuggerWindowGroup.cs new file mode 100644 index 00000000..f2e9475c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.DebuggerWindowGroup.cs @@ -0,0 +1,300 @@ +using System.Collections.Generic; + +namespace TEngine +{ + internal sealed partial class DebuggerManager : ModuleImp, IDebuggerManager + { + /// + /// 调试器窗口组。 + /// + private sealed class DebuggerWindowGroup : IDebuggerWindowGroup + { + private readonly List> _debuggerWindows; + private int _selectedIndex; + private string[] _debuggerWindowNames; + + public DebuggerWindowGroup() + { + _debuggerWindows = new List>(); + _selectedIndex = 0; + _debuggerWindowNames = null; + } + + /// + /// 获取调试器窗口数量。 + /// + public int DebuggerWindowCount + { + get + { + return _debuggerWindows.Count; + } + } + + /// + /// 获取或设置当前选中的调试器窗口索引。 + /// + public int SelectedIndex + { + get + { + return _selectedIndex; + } + set + { + _selectedIndex = value; + } + } + + /// + /// 获取当前选中的调试器窗口。 + /// + public IDebuggerWindow SelectedWindow + { + get + { + if (_selectedIndex >= _debuggerWindows.Count) + { + return null; + } + + return _debuggerWindows[_selectedIndex].Value; + } + } + + /// + /// 初始化调试组。 + /// + /// 初始化调试组参数。 + public void Initialize(params object[] args) + { + } + + /// + /// 关闭调试组。 + /// + public void Shutdown() + { + foreach (KeyValuePair debuggerWindow in _debuggerWindows) + { + debuggerWindow.Value.Shutdown(); + } + + _debuggerWindows.Clear(); + } + + /// + /// 进入调试器窗口。 + /// + public void OnEnter() + { + SelectedWindow.OnEnter(); + } + + /// + /// 离开调试器窗口。 + /// + public void OnLeave() + { + SelectedWindow.OnLeave(); + } + + /// + /// 调试组轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + public void OnUpdate(float elapseSeconds, float realElapseSeconds) + { + SelectedWindow.OnUpdate(elapseSeconds, realElapseSeconds); + } + + /// + /// 调试器窗口绘制。 + /// + public void OnDraw() + { + } + + private void RefreshDebuggerWindowNames() + { + int index = 0; + _debuggerWindowNames = new string[_debuggerWindows.Count]; + foreach (KeyValuePair debuggerWindow in _debuggerWindows) + { + _debuggerWindowNames[index++] = debuggerWindow.Key; + } + } + + /// + /// 获取调试组的调试器窗口名称集合。 + /// + public string[] GetDebuggerWindowNames() + { + return _debuggerWindowNames; + } + + /// + /// 获取调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要获取的调试器窗口。 + public IDebuggerWindow GetDebuggerWindow(string path) + { + if (string.IsNullOrEmpty(path)) + { + return null; + } + + int pos = path.IndexOf('/'); + if (pos < 0 || pos >= path.Length - 1) + { + return InternalGetDebuggerWindow(path); + } + + string debuggerWindowGroupName = path.Substring(0, pos); + string leftPath = path.Substring(pos + 1); + DebuggerWindowGroup debuggerWindowGroup = (DebuggerWindowGroup)InternalGetDebuggerWindow(debuggerWindowGroupName); + if (debuggerWindowGroup == null) + { + return null; + } + + return debuggerWindowGroup.GetDebuggerWindow(leftPath); + } + + /// + /// 选中调试器窗口。 + /// + /// 调试器窗口路径。 + /// 是否成功选中调试器窗口。 + public bool SelectDebuggerWindow(string path) + { + if (string.IsNullOrEmpty(path)) + { + return false; + } + + int pos = path.IndexOf('/'); + if (pos < 0 || pos >= path.Length - 1) + { + return InternalSelectDebuggerWindow(path); + } + + string debuggerWindowGroupName = path.Substring(0, pos); + string leftPath = path.Substring(pos + 1); + DebuggerWindowGroup debuggerWindowGroup = (DebuggerWindowGroup)InternalGetDebuggerWindow(debuggerWindowGroupName); + if (debuggerWindowGroup == null || !InternalSelectDebuggerWindow(debuggerWindowGroupName)) + { + return false; + } + + return debuggerWindowGroup.SelectDebuggerWindow(leftPath); + } + + /// + /// 注册调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要注册的调试器窗口。 + public void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow) + { + if (string.IsNullOrEmpty(path)) + { + throw new GameFrameworkException("Path is invalid."); + } + + int pos = path.IndexOf('/'); + if (pos < 0 || pos >= path.Length - 1) + { + if (InternalGetDebuggerWindow(path) != null) + { + throw new GameFrameworkException("Debugger window has been registered."); + } + + _debuggerWindows.Add(new KeyValuePair(path, debuggerWindow)); + RefreshDebuggerWindowNames(); + } + else + { + string debuggerWindowGroupName = path.Substring(0, pos); + string leftPath = path.Substring(pos + 1); + DebuggerWindowGroup debuggerWindowGroup = (DebuggerWindowGroup)InternalGetDebuggerWindow(debuggerWindowGroupName); + if (debuggerWindowGroup == null) + { + if (InternalGetDebuggerWindow(debuggerWindowGroupName) != null) + { + throw new GameFrameworkException("Debugger window has been registered, can not create debugger window group."); + } + + debuggerWindowGroup = new DebuggerWindowGroup(); + _debuggerWindows.Add(new KeyValuePair(debuggerWindowGroupName, debuggerWindowGroup)); + RefreshDebuggerWindowNames(); + } + + debuggerWindowGroup.RegisterDebuggerWindow(leftPath, debuggerWindow); + } + } + + /// + /// 解除注册调试器窗口。 + /// + /// 调试器窗口路径。 + /// 是否解除注册调试器窗口成功。 + public bool UnregisterDebuggerWindow(string path) + { + if (string.IsNullOrEmpty(path)) + { + return false; + } + + int pos = path.IndexOf('/'); + if (pos < 0 || pos >= path.Length - 1) + { + IDebuggerWindow debuggerWindow = InternalGetDebuggerWindow(path); + bool result = _debuggerWindows.Remove(new KeyValuePair(path, debuggerWindow)); + debuggerWindow.Shutdown(); + RefreshDebuggerWindowNames(); + return result; + } + + string debuggerWindowGroupName = path.Substring(0, pos); + string leftPath = path.Substring(pos + 1); + DebuggerWindowGroup debuggerWindowGroup = (DebuggerWindowGroup)InternalGetDebuggerWindow(debuggerWindowGroupName); + if (debuggerWindowGroup == null) + { + return false; + } + + return debuggerWindowGroup.UnregisterDebuggerWindow(leftPath); + } + + private IDebuggerWindow InternalGetDebuggerWindow(string name) + { + foreach (KeyValuePair debuggerWindow in _debuggerWindows) + { + if (debuggerWindow.Key == name) + { + return debuggerWindow.Value; + } + } + + return null; + } + + private bool InternalSelectDebuggerWindow(string name) + { + for (int i = 0; i < _debuggerWindows.Count; i++) + { + if (_debuggerWindows[i].Key == name) + { + _selectedIndex = i; + return true; + } + } + + return false; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.DebuggerWindowGroup.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.DebuggerWindowGroup.cs.meta new file mode 100644 index 00000000..18fbccf8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.DebuggerWindowGroup.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d4a3c5214e924154ad543eae04e6cb7e +timeCreated: 1680489597 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.cs new file mode 100644 index 00000000..061b5cef --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.cs @@ -0,0 +1,135 @@ +namespace TEngine +{ + /// + /// 调试器管理器。 + /// + [UpdateModule] + internal sealed partial class DebuggerManager : ModuleImp, IDebuggerManager + { + private readonly DebuggerWindowGroup _debuggerWindowRoot; + private bool _activeWindow; + + /// + /// 初始化调试器管理器的新实例。 + /// + public DebuggerManager() + { + _debuggerWindowRoot = new DebuggerWindowGroup(); + _activeWindow = false; + } + + /// + /// 获取游戏框架模块优先级。 + /// + /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 + internal override int Priority + { + get + { + return -1; + } + } + + /// + /// 获取或设置调试器窗口是否激活。 + /// + public bool ActiveWindow + { + get + { + return _activeWindow; + } + set + { + _activeWindow = value; + } + } + + /// + /// 调试器窗口根结点。 + /// + public IDebuggerWindowGroup DebuggerWindowRoot + { + get + { + return _debuggerWindowRoot; + } + } + + /// + /// 调试器管理器轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + if (!_activeWindow) + { + return; + } + + _debuggerWindowRoot.OnUpdate(elapseSeconds, realElapseSeconds); + } + + /// + /// 关闭并清理调试器管理器。 + /// + internal override void Shutdown() + { + _activeWindow = false; + _debuggerWindowRoot.Shutdown(); + } + + /// + /// 注册调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要注册的调试器窗口。 + /// 初始化调试器窗口参数。 + public void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow, params object[] args) + { + if (string.IsNullOrEmpty(path)) + { + throw new GameFrameworkException("Path is invalid."); + } + + if (debuggerWindow == null) + { + throw new GameFrameworkException("Debugger window is invalid."); + } + + _debuggerWindowRoot.RegisterDebuggerWindow(path, debuggerWindow); + debuggerWindow.Initialize(args); + } + + /// + /// 解除注册调试器窗口。 + /// + /// 调试器窗口路径。 + /// 是否解除注册调试器窗口成功。 + public bool UnregisterDebuggerWindow(string path) + { + return _debuggerWindowRoot.UnregisterDebuggerWindow(path); + } + + /// + /// 获取调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要获取的调试器窗口。 + public IDebuggerWindow GetDebuggerWindow(string path) + { + return _debuggerWindowRoot.GetDebuggerWindow(path); + } + + /// + /// 选中调试器窗口。 + /// + /// 调试器窗口路径。 + /// 是否成功选中调试器窗口。 + public bool SelectDebuggerWindow(string path) + { + return _debuggerWindowRoot.SelectDebuggerWindow(path); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.cs.meta new file mode 100644 index 00000000..d854079d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9ac1ec4655aa4faba2d1a0ddd044712b +timeCreated: 1680489597 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerModule.cs new file mode 100644 index 00000000..e269b8f0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerModule.cs @@ -0,0 +1,440 @@ +using System.Collections.Generic; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace TEngine +{ + /// + /// 调试器模块。 + /// + [DisallowMultipleComponent] + public sealed partial class DebuggerModule : Module + { + /// + /// 默认调试器漂浮框大小。 + /// + internal static readonly Rect DefaultIconRect = new Rect(10f, 10f, 60f, 60f); + + /// + /// 默认调试器窗口大小。 + /// + internal static readonly Rect DefaultWindowRect = new Rect(10f, 10f, 640f, 480f); + + /// + /// 默认调试器窗口缩放比例。 + /// + internal static readonly float DefaultWindowScale = 1.5f; + + private static TextEditor s_TextEditor = null; + private IDebuggerManager _debuggerManager = null; + private Rect m_DragRect = new Rect(0f, 0f, float.MaxValue, 25f); + private Rect m_IconRect = DefaultIconRect; + private Rect m_WindowRect = DefaultWindowRect; + private float m_WindowScale = DefaultWindowScale; + + [SerializeField] + private GUISkin m_Skin = null; + + [SerializeField] + private DebuggerActiveWindowType m_ActiveWindow = DebuggerActiveWindowType.AlwaysOpen; + + public DebuggerActiveWindowType ActiveWindowType => m_ActiveWindow; + + [SerializeField] + private bool m_ShowFullWindow = false; + + [SerializeField] + private ConsoleWindow m_ConsoleWindow = new ConsoleWindow(); + + private SystemInformationWindow m_SystemInformationWindow = new SystemInformationWindow(); + private EnvironmentInformationWindow m_EnvironmentInformationWindow = new EnvironmentInformationWindow(); + private ScreenInformationWindow m_ScreenInformationWindow = new ScreenInformationWindow(); + private GraphicsInformationWindow m_GraphicsInformationWindow = new GraphicsInformationWindow(); + private InputSummaryInformationWindow m_InputSummaryInformationWindow = new InputSummaryInformationWindow(); + private InputTouchInformationWindow m_InputTouchInformationWindow = new InputTouchInformationWindow(); + private InputLocationInformationWindow m_InputLocationInformationWindow = new InputLocationInformationWindow(); + private InputAccelerationInformationWindow m_InputAccelerationInformationWindow = new InputAccelerationInformationWindow(); + private InputGyroscopeInformationWindow m_InputGyroscopeInformationWindow = new InputGyroscopeInformationWindow(); + private InputCompassInformationWindow m_InputCompassInformationWindow = new InputCompassInformationWindow(); + private PathInformationWindow m_PathInformationWindow = new PathInformationWindow(); + private SceneInformationWindow m_SceneInformationWindow = new SceneInformationWindow(); + private TimeInformationWindow m_TimeInformationWindow = new TimeInformationWindow(); + private QualityInformationWindow m_QualityInformationWindow = new QualityInformationWindow(); + private ProfilerInformationWindow m_ProfilerInformationWindow = new ProfilerInformationWindow(); + private RuntimeMemorySummaryWindow m_RuntimeMemorySummaryWindow = new RuntimeMemorySummaryWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryAllInformationWindow = new RuntimeMemoryInformationWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryTextureInformationWindow = new RuntimeMemoryInformationWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryMeshInformationWindow = new RuntimeMemoryInformationWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryMaterialInformationWindow = new RuntimeMemoryInformationWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryShaderInformationWindow = new RuntimeMemoryInformationWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryAnimationClipInformationWindow = new RuntimeMemoryInformationWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryAudioClipInformationWindow = new RuntimeMemoryInformationWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryFontInformationWindow = new RuntimeMemoryInformationWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryTextAssetInformationWindow = new RuntimeMemoryInformationWindow(); + private RuntimeMemoryInformationWindow m_RuntimeMemoryScriptableObjectInformationWindow = new RuntimeMemoryInformationWindow(); + private ObjectPoolInformationWindow m_ObjectPoolInformationWindow = new ObjectPoolInformationWindow(); + private MemoryPoolPoolInformationWindow _mMemoryPoolPoolInformationWindow = new MemoryPoolPoolInformationWindow(); + // private NetworkInformationWindow m_NetworkInformationWindow = new NetworkInformationWindow(); + private SettingsWindow m_SettingsWindow = new SettingsWindow(); + private OperationsWindow m_OperationsWindow = new OperationsWindow(); + + private FpsCounter m_FpsCounter = null; + + /// + /// 获取或设置调试器窗口是否激活。 + /// + public bool ActiveWindow + { + get => _debuggerManager.ActiveWindow; + set + { + _debuggerManager.ActiveWindow = value; + enabled = value; + } + } + + /// + /// 获取或设置是否显示完整调试器界面。 + /// + public bool ShowFullWindow + { + get => m_ShowFullWindow; + set + { + if (_eventSystem != null) + { + _eventSystem.SetActive(!value,ref _eventSystemActive); + } + m_ShowFullWindow = value; + } + } + + /// + /// 获取或设置调试器漂浮框大小。 + /// + public Rect IconRect + { + get => m_IconRect; + set => m_IconRect = value; + } + + /// + /// 获取或设置调试器窗口大小。 + /// + public Rect WindowRect + { + get => m_WindowRect; + set => m_WindowRect = value; + } + + /// + /// 获取或设置调试器窗口缩放比例。 + /// + public float WindowScale + { + get => m_WindowScale; + set => m_WindowScale = value; + } + + private SettingModule _settingModule = null; + + private bool _eventSystemActive = true; + private GameObject _eventSystem; + /// + /// 游戏框架模块初始化。 + /// + protected override void Awake() + { + base.Awake(); + s_TextEditor = new TextEditor(); + _eventSystem = GameObject.Find("UIRoot/EventSystem"); + _debuggerManager = ModuleImpSystem.GetModule(); + if (_debuggerManager == null) + { + Log.Fatal("Debugger manager is invalid."); + return; + } + + m_FpsCounter = new FpsCounter(0.5f); + } + + private void OnDestroy() + { + if (_settingModule == null) + { + Log.Fatal("Setting component is invalid."); + return; + } + + _settingModule.Save(); + } + + private void Initialize() + { + _settingModule = ModuleSystem.GetModule(); + if (_settingModule == null) + { + Log.Fatal("Setting component is invalid."); + return; + } + + var lastIconX = _settingModule.GetFloat("Debugger.Icon.X", DefaultIconRect.x); + var lastIconY = _settingModule.GetFloat("Debugger.Icon.Y", DefaultIconRect.y); + var lastWindowX = _settingModule.GetFloat("Debugger.Window.X", DefaultWindowRect.x); + var lastWindowY = _settingModule.GetFloat("Debugger.Window.Y", DefaultWindowRect.y); + var lastWindowWidth = _settingModule.GetFloat("Debugger.Window.Width", DefaultWindowRect.width); + var lastWindowHeight = _settingModule.GetFloat("Debugger.Window.Height", DefaultWindowRect.height); + m_WindowScale = _settingModule.GetFloat("Debugger.Window.Scale", DefaultWindowScale); + m_WindowRect = new Rect(lastIconX, lastIconY, DefaultIconRect.width, DefaultIconRect.height); + m_WindowRect = new Rect(lastWindowX, lastWindowY, lastWindowWidth, lastWindowHeight); + } + + private void Start() + { + Initialize(); + RegisterDebuggerWindow("Console", m_ConsoleWindow); + RegisterDebuggerWindow("Information/System", m_SystemInformationWindow); + RegisterDebuggerWindow("Information/Environment", m_EnvironmentInformationWindow); + RegisterDebuggerWindow("Information/Screen", m_ScreenInformationWindow); + RegisterDebuggerWindow("Information/Graphics", m_GraphicsInformationWindow); + RegisterDebuggerWindow("Information/Input/Summary", m_InputSummaryInformationWindow); + RegisterDebuggerWindow("Information/Input/Touch", m_InputTouchInformationWindow); + RegisterDebuggerWindow("Information/Input/Location", m_InputLocationInformationWindow); + RegisterDebuggerWindow("Information/Input/Acceleration", m_InputAccelerationInformationWindow); + RegisterDebuggerWindow("Information/Input/Gyroscope", m_InputGyroscopeInformationWindow); + RegisterDebuggerWindow("Information/Input/Compass", m_InputCompassInformationWindow); + RegisterDebuggerWindow("Information/Other/Scene", m_SceneInformationWindow); + RegisterDebuggerWindow("Information/Other/Path", m_PathInformationWindow); + RegisterDebuggerWindow("Information/Other/Time", m_TimeInformationWindow); + RegisterDebuggerWindow("Information/Other/Quality", m_QualityInformationWindow); + RegisterDebuggerWindow("Profiler/Summary", m_ProfilerInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/Summary", m_RuntimeMemorySummaryWindow); + RegisterDebuggerWindow("Profiler/Memory/All", m_RuntimeMemoryAllInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/Texture", m_RuntimeMemoryTextureInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/Mesh", m_RuntimeMemoryMeshInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/Material", m_RuntimeMemoryMaterialInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/Shader", m_RuntimeMemoryShaderInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/AnimationClip", m_RuntimeMemoryAnimationClipInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/AudioClip", m_RuntimeMemoryAudioClipInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/Font", m_RuntimeMemoryFontInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/TextAsset", m_RuntimeMemoryTextAssetInformationWindow); + RegisterDebuggerWindow("Profiler/Memory/ScriptableObject", m_RuntimeMemoryScriptableObjectInformationWindow); + RegisterDebuggerWindow("Profiler/Object Pool", m_ObjectPoolInformationWindow); + RegisterDebuggerWindow("Profiler/Reference Pool", _mMemoryPoolPoolInformationWindow); + // RegisterDebuggerWindow("Profiler/Network", m_NetworkInformationWindow); + RegisterDebuggerWindow("Other/Settings", m_SettingsWindow); + RegisterDebuggerWindow("Other/Operations", m_OperationsWindow); + + switch (m_ActiveWindow) + { + case DebuggerActiveWindowType.AlwaysOpen: + ActiveWindow = true; + break; + + case DebuggerActiveWindowType.OnlyOpenWhenDevelopment: + ActiveWindow = Debug.isDebugBuild; + break; + + case DebuggerActiveWindowType.OnlyOpenInEditor: + ActiveWindow = Application.isEditor; + break; + + default: + ActiveWindow = false; + break; + } + } + + private void Update() + { + m_FpsCounter.Update(GameTime.deltaTime, GameTime.unscaledDeltaTime); + } + + private void OnGUI() + { + if (_debuggerManager == null || !_debuggerManager.ActiveWindow) + { + return; + } + + GUISkin cachedGuiSkin = GUI.skin; + Matrix4x4 cachedMatrix = GUI.matrix; + + GUI.skin = m_Skin; + GUI.matrix = Matrix4x4.Scale(new Vector3(m_WindowScale, m_WindowScale, 1f)); + + if (m_ShowFullWindow) + { + m_WindowRect = GUILayout.Window(0, m_WindowRect, DrawWindow, "TENGINE DEBUGGER"); + } + else + { + m_IconRect = GUILayout.Window(0, m_IconRect, DrawDebuggerWindowIcon, "DEBUGGER"); + } + + GUI.matrix = cachedMatrix; + GUI.skin = cachedGuiSkin; + } + + /// + /// 注册调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要注册的调试器窗口。 + /// 初始化调试器窗口参数。 + public void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow, params object[] args) + { + _debuggerManager.RegisterDebuggerWindow(path, debuggerWindow, args); + } + + /// + /// 解除注册调试器窗口。 + /// + /// 调试器窗口路径。 + /// 是否解除注册调试器窗口成功。 + public bool UnregisterDebuggerWindow(string path) + { + return _debuggerManager.UnregisterDebuggerWindow(path); + } + + /// + /// 获取调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要获取的调试器窗口。 + public IDebuggerWindow GetDebuggerWindow(string path) + { + return _debuggerManager.GetDebuggerWindow(path); + } + + /// + /// 选中调试器窗口。 + /// + /// 调试器窗口路径。 + /// 是否成功选中调试器窗口。 + public bool SelectDebuggerWindow(string path) + { + return _debuggerManager.SelectDebuggerWindow(path); + } + + /// + /// 还原调试器窗口布局。 + /// + public void ResetLayout() + { + IconRect = DefaultIconRect; + WindowRect = DefaultWindowRect; + WindowScale = DefaultWindowScale; + } + + /// + /// 获取记录的所有日志。 + /// + /// 要获取的日志。 + public void GetRecentLogs(List results) + { + m_ConsoleWindow.GetRecentLogs(results); + } + + /// + /// 获取记录的最近日志。 + /// + /// 要获取的日志。 + /// 要获取最近日志的数量。 + public void GetRecentLogs(List results, int count) + { + m_ConsoleWindow.GetRecentLogs(results, count); + } + + private void DrawWindow(int windowId) + { + GUI.DragWindow(m_DragRect); + DrawDebuggerWindowGroup(_debuggerManager.DebuggerWindowRoot); + } + + private void DrawDebuggerWindowGroup(IDebuggerWindowGroup debuggerWindowGroup) + { + if (debuggerWindowGroup == null) + { + return; + } + + List names = new List(); + string[] debuggerWindowNames = debuggerWindowGroup.GetDebuggerWindowNames(); + for (int i = 0; i < debuggerWindowNames.Length; i++) + { + names.Add(Utility.Text.Format("{0}", debuggerWindowNames[i])); + } + + if (debuggerWindowGroup == _debuggerManager.DebuggerWindowRoot) + { + names.Add("Close"); + } + + int toolbarIndex = GUILayout.Toolbar(debuggerWindowGroup.SelectedIndex, names.ToArray(), GUILayout.Height(30f), GUILayout.MaxWidth(Screen.width)); + if (toolbarIndex >= debuggerWindowGroup.DebuggerWindowCount) + { + ShowFullWindow = false; + return; + } + + if (debuggerWindowGroup.SelectedWindow == null) + { + return; + } + + if (debuggerWindowGroup.SelectedIndex != toolbarIndex) + { + debuggerWindowGroup.SelectedWindow.OnLeave(); + debuggerWindowGroup.SelectedIndex = toolbarIndex; + debuggerWindowGroup.SelectedWindow.OnEnter(); + } + + IDebuggerWindowGroup subDebuggerWindowGroup = debuggerWindowGroup.SelectedWindow as IDebuggerWindowGroup; + if (subDebuggerWindowGroup != null) + { + DrawDebuggerWindowGroup(subDebuggerWindowGroup); + } + + debuggerWindowGroup?.SelectedWindow?.OnDraw(); + } + + private void DrawDebuggerWindowIcon(int windowId) + { + GUI.DragWindow(m_DragRect); + GUILayout.Space(5); + Color32 color = Color.white; + m_ConsoleWindow.RefreshCount(); + if (m_ConsoleWindow.FatalCount > 0) + { + color = m_ConsoleWindow.GetLogStringColor(LogType.Exception); + } + else if (m_ConsoleWindow.ErrorCount > 0) + { + color = m_ConsoleWindow.GetLogStringColor(LogType.Error); + } + else if (m_ConsoleWindow.WarningCount > 0) + { + color = m_ConsoleWindow.GetLogStringColor(LogType.Warning); + } + else + { + color = m_ConsoleWindow.GetLogStringColor(LogType.Log); + } + + string title = Utility.Text.Format("FPS: {4:F2}", color.r, color.g, color.b, color.a, m_FpsCounter.CurrentFps); + if (GUILayout.Button(title, GUILayout.Width(100f), GUILayout.Height(40f))) + { + ShowFullWindow = true; + } + } + + private static void CopyToClipboard(string content) + { + s_TextEditor.text = content; + s_TextEditor.OnFocus(); + s_TextEditor.Copy(); + s_TextEditor.text = string.Empty; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerModule.cs.meta new file mode 100644 index 00000000..84aeedb7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d58978a9ed0f473ca3cc5a302c3bf87b +timeCreated: 1680489774 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerSkin.guiskin b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerSkin.guiskin new file mode 100644 index 00000000..16bbd46b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerSkin.guiskin @@ -0,0 +1,1427 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12001, guid: 0000000000000000e000000000000000, type: 0} + m_Name: DebuggerSkin + m_EditorClassIdentifier: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_box: + m_Name: box + m_Normal: + m_Background: {fileID: 11001, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.79999995, g: 0.79999995, b: 0.79999995, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 6 + m_Right: 6 + m_Top: 6 + m_Bottom: 6 + m_Margin: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Padding: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 1 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_button: + m_Name: button + m_Normal: + m_Background: {fileID: 11006, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.9, g: 0.9, b: 0.9, a: 1} + m_Hover: + m_Background: {fileID: 11003, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_Active: + m_Background: {fileID: 11002, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.9, g: 0.9, b: 0.9, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_OnNormal: + m_Background: {fileID: 11005, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.9019608, g: 0.9019608, b: 0.9019608, a: 1} + m_OnHover: + m_Background: {fileID: 11004, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_OnActive: + m_Background: {fileID: 11002, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.9, g: 0.9, b: 0.9, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 6 + m_Right: 6 + m_Top: 6 + m_Bottom: 4 + m_Margin: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Padding: + m_Left: 6 + m_Right: 6 + m_Top: 3 + m_Bottom: 3 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 4 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_toggle: + m_Name: toggle + m_Normal: + m_Background: {fileID: 11018, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.89112896, g: 0.89112896, b: 0.89112896, a: 1} + m_Hover: + m_Background: {fileID: 11014, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_Active: + m_Background: {fileID: 11013, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 11016, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.8901961, g: 0.8901961, b: 0.8901961, a: 1} + m_OnHover: + m_Background: {fileID: 11015, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_OnActive: + m_Background: {fileID: 11017, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 14 + m_Right: 0 + m_Top: 14 + m_Bottom: 0 + m_Margin: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Padding: + m_Left: 15 + m_Right: 0 + m_Top: 3 + m_Bottom: 0 + m_Overflow: + m_Left: -1 + m_Right: 0 + m_Top: -4 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_label: + m_Name: label + m_Normal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.9, g: 0.9, b: 0.9, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.9, g: 0.9, b: 0.9, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 3 + m_Bottom: 3 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 1 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_textField: + m_Name: textfield + m_Normal: + m_Background: {fileID: 11024, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.79999995, g: 0.79999995, b: 0.79999995, a: 1} + m_Hover: + m_Background: {fileID: 11026, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.9, g: 0.9, b: 0.9, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 11026, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_OnNormal: + m_Background: {fileID: 11025, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Margin: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Padding: + m_Left: 3 + m_Right: 3 + m_Top: 3 + m_Bottom: 3 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 0 + m_TextClipping: 1 + m_ImagePosition: 3 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_textArea: + m_Name: textarea + m_Normal: + m_Background: {fileID: 11024, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.9019608, g: 0.9019608, b: 0.9019608, a: 1} + m_Hover: + m_Background: {fileID: 11026, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0.79999995, g: 0.79999995, b: 0.79999995, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 11025, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Margin: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Padding: + m_Left: 3 + m_Right: 3 + m_Top: 3 + m_Bottom: 3 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 1 + m_RichText: 0 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_window: + m_Name: window + m_Normal: + m_Background: {fileID: 11023, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 11022, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 1, g: 1, b: 1, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 8 + m_Right: 8 + m_Top: 18 + m_Bottom: 8 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 10 + m_Right: 10 + m_Top: 20 + m_Bottom: 10 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 1 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: -18} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_horizontalSlider: + m_Name: horizontalslider + m_Normal: + m_Background: {fileID: 11009, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 3 + m_Right: 3 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Padding: + m_Left: -1 + m_Right: -1 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: -2 + m_Bottom: -3 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 2 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 12 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_horizontalSliderThumb: + m_Name: horizontalsliderthumb + m_Normal: + m_Background: {fileID: 11011, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 11012, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 11010, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 4 + m_Right: 4 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 7 + m_Right: 7 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: -1 + m_Right: -1 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 2 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 12 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_verticalSlider: + m_Name: verticalslider + m_Normal: + m_Background: {fileID: 11021, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 3 + m_Bottom: 3 + m_Margin: + m_Left: 4 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: -1 + m_Bottom: -1 + m_Overflow: + m_Left: -2 + m_Right: -3 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 0 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 12 + m_FixedHeight: 0 + m_StretchWidth: 0 + m_StretchHeight: 1 + m_verticalSliderThumb: + m_Name: verticalsliderthumb + m_Normal: + m_Background: {fileID: 11011, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 11012, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 11010, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 7 + m_Bottom: 7 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: -1 + m_Bottom: -1 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 12 + m_FixedHeight: 0 + m_StretchWidth: 0 + m_StretchHeight: 1 + m_horizontalScrollbar: + m_Name: horizontalscrollbar + m_Normal: + m_Background: {fileID: 11008, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 9 + m_Right: 9 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 4 + m_Right: 4 + m_Top: 1 + m_Bottom: 4 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 2 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 15 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_horizontalScrollbarThumb: + m_Name: horizontalscrollbarthumb + m_Normal: + m_Background: {fileID: 11007, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 6 + m_Right: 6 + m_Top: 6 + m_Bottom: 6 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 6 + m_Right: 6 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: -1 + m_Bottom: 1 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 13 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_horizontalScrollbarLeftButton: + m_Name: horizontalscrollbarleftbutton + m_Normal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_horizontalScrollbarRightButton: + m_Name: horizontalscrollbarrightbutton + m_Normal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_verticalScrollbar: + m_Name: verticalscrollbar + m_Normal: + m_Background: {fileID: 11020, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 9 + m_Bottom: 9 + m_Margin: + m_Left: 1 + m_Right: 4 + m_Top: 4 + m_Bottom: 4 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 1 + m_Bottom: 1 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 15 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_verticalScrollbarThumb: + m_Name: verticalscrollbarthumb + m_Normal: + m_Background: {fileID: 11019, guid: 0000000000000000e000000000000000, type: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 6 + m_Right: 6 + m_Top: 6 + m_Bottom: 6 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 6 + m_Bottom: 6 + m_Overflow: + m_Left: -1 + m_Right: -1 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 2 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 15 + m_FixedHeight: 0 + m_StretchWidth: 0 + m_StretchHeight: 1 + m_verticalScrollbarUpButton: + m_Name: verticalscrollbarupbutton + m_Normal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_verticalScrollbarDownButton: + m_Name: verticalscrollbardownbutton + m_Normal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_ScrollView: + m_Name: scrollview + m_Normal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 1 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_CustomStyles: + - m_Name: + m_Normal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Hover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Active: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Focused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnNormal: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnHover: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnActive: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_OnFocused: + m_Background: {fileID: 0} + m_ScaledBackgrounds: [] + m_TextColor: {r: 0, g: 0, b: 0, a: 1} + m_Border: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Margin: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Overflow: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_Font: {fileID: 0} + m_FontSize: 0 + m_FontStyle: 0 + m_Alignment: 0 + m_WordWrap: 0 + m_RichText: 1 + m_TextClipping: 0 + m_ImagePosition: 0 + m_ContentOffset: {x: 0, y: 0} + m_FixedWidth: 0 + m_FixedHeight: 0 + m_StretchWidth: 1 + m_StretchHeight: 0 + m_Settings: + m_DoubleClickSelectsWord: 1 + m_TripleClickSelectsLine: 1 + m_CursorColor: {r: 1, g: 1, b: 1, a: 1} + m_CursorFlashSpeed: -1 + m_SelectionColor: {r: 1, g: 0.38403907, b: 0, a: 0.7} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerSkin.guiskin.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerSkin.guiskin.meta new file mode 100644 index 00000000..75177de5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/DebuggerSkin.guiskin.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b38f904eb09e4bd48a46a63750942109 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerManager.cs new file mode 100644 index 00000000..5c175c41 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerManager.cs @@ -0,0 +1,54 @@ +namespace TEngine +{ + /// + /// 调试器管理器接口。 + /// + public interface IDebuggerManager + { + /// + /// 获取或设置调试器窗口是否激活。 + /// + bool ActiveWindow + { + get; + set; + } + + /// + /// 调试器窗口根结点。 + /// + IDebuggerWindowGroup DebuggerWindowRoot + { + get; + } + + /// + /// 注册调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要注册的调试器窗口。 + /// 初始化调试器窗口参数。 + void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow, params object[] args); + + /// + /// 解除注册调试器窗口。 + /// + /// 调试器窗口路径。 + /// 是否解除注册调试器窗口成功。 + bool UnregisterDebuggerWindow(string path); + + /// + /// 获取调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要获取的调试器窗口。 + IDebuggerWindow GetDebuggerWindow(string path); + + /// + /// 选中调试器窗口。 + /// + /// 调试器窗口路径。 + /// 是否成功选中调试器窗口。 + bool SelectDebuggerWindow(string path); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerManager.cs.meta new file mode 100644 index 00000000..94b9727a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d27aae441b2a4e299c230c968c76e839 +timeCreated: 1680489597 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindow.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindow.cs new file mode 100644 index 00000000..b219e847 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindow.cs @@ -0,0 +1,41 @@ +namespace TEngine +{ + /// + /// 调试器窗口接口。 + /// + public interface IDebuggerWindow + { + /// + /// 初始化调试器窗口。 + /// + /// 初始化调试器窗口参数。 + void Initialize(params object[] args); + + /// + /// 关闭调试器窗口。 + /// + void Shutdown(); + + /// + /// 进入调试器窗口。 + /// + void OnEnter(); + + /// + /// 离开调试器窗口。 + /// + void OnLeave(); + + /// + /// 调试器窗口轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + void OnUpdate(float elapseSeconds, float realElapseSeconds); + + /// + /// 调试器窗口绘制。 + /// + void OnDraw(); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindow.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindow.cs.meta new file mode 100644 index 00000000..e201e37e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 41aa48cd603d432d8dffd4edc72f188d +timeCreated: 1680489597 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindowGroup.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindowGroup.cs new file mode 100644 index 00000000..cf438a54 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindowGroup.cs @@ -0,0 +1,52 @@ +namespace TEngine +{ + /// + /// 调试器窗口组接口。 + /// + public interface IDebuggerWindowGroup : IDebuggerWindow + { + /// + /// 获取调试器窗口数量。 + /// + int DebuggerWindowCount + { + get; + } + + /// + /// 获取或设置当前选中的调试器窗口索引。 + /// + int SelectedIndex + { + get; + set; + } + + /// + /// 获取当前选中的调试器窗口。 + /// + IDebuggerWindow SelectedWindow + { + get; + } + + /// + /// 获取调试组的调试器窗口名称集合。 + /// + string[] GetDebuggerWindowNames(); + + /// + /// 获取调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要获取的调试器窗口。 + IDebuggerWindow GetDebuggerWindow(string path); + + /// + /// 注册调试器窗口。 + /// + /// 调试器窗口路径。 + /// 要注册的调试器窗口。 + void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindowGroup.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindowGroup.cs.meta new file mode 100644 index 00000000..fda94bc5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/IDebuggerWindowGroup.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2fff84d86dd44f16b3bb44dfa29081c6 +timeCreated: 1680489597 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/SkipUnityLogo.cs b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/SkipUnityLogo.cs new file mode 100644 index 00000000..4ebe06c1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/SkipUnityLogo.cs @@ -0,0 +1,31 @@ +#if !UNITY_EDITOR +using UnityEngine; +using UnityEngine.Rendering; + +[UnityEngine.Scripting.Preserve] +public class SkipUnityLogo +{ + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)] + private static void BeforeSplashScreen() + { +#if UNITY_WEBGL + Application.focusChanged += Application_focusChanged; +#else + System.Threading.Tasks.Task.Run(AsyncSkip); +#endif + } + +#if UNITY_WEBGL + private static void Application_focusChanged(bool obj) + { + Application.focusChanged -= Application_focusChanged; + SplashScreen.Stop(SplashScreen.StopBehavior.StopImmediate); + } +#else + private static void AsyncSkip() + { + SplashScreen.Stop(SplashScreen.StopBehavior.StopImmediate); + } +#endif +} +#endif \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/SkipUnityLogo.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/SkipUnityLogo.cs.meta new file mode 100644 index 00000000..0f749a7d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/DebugerModule/SkipUnityLogo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2794217c34044c8bb21192636c5b15c6 +timeCreated: 1695126157 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule.meta b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule.meta new file mode 100644 index 00000000..20a97e3a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3910e2455debbf74a940960c6e435daf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/Fsm.cs b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/Fsm.cs new file mode 100644 index 00000000..4f4ccdff --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/Fsm.cs @@ -0,0 +1,505 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 有限状态机。 + /// + /// 有限状态机持有者类型。 + internal sealed class Fsm : FsmBase, IMemory, IFsm where T : class + { + private T _owner; + private readonly Dictionary> _states; + private Dictionary _dataMap; + private FsmState _currentState; + private float _currentStateTime; + private bool _isDestroyed; + + /// + /// 初始化有限状态机的新实例。 + /// + public Fsm() + { + _owner = null; + _states = new Dictionary>(); + _dataMap = null; + _currentState = null; + _currentStateTime = 0f; + _isDestroyed = true; + } + + /// + /// 获取有限状态机持有者。 + /// + public T Owner => _owner; + + /// + /// 获取有限状态机持有者类型。 + /// + public override Type OwnerType => typeof(T); + + /// + /// 获取有限状态机中状态的数量。 + /// + public override int FsmStateCount => _states.Count; + + /// + /// 获取有限状态机是否正在运行。 + /// + public override bool IsRunning => _currentState != null; + + /// + /// 获取有限状态机是否被销毁。 + /// + public override bool IsDestroyed => _isDestroyed; + + /// + /// 获取当前有限状态机状态。 + /// + public FsmState CurrentState => _currentState; + + /// + /// 获取当前有限状态机状态名称。 + /// + public override string CurrentStateName => _currentState?.GetType().FullName; + + /// + /// 获取当前有限状态机状态持续时间。 + /// + public override float CurrentStateTime => _currentStateTime; + + /// + /// 创建有限状态机。 + /// + /// 有限状态机名称。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 创建的有限状态机。 + public static Fsm Create(string name, T owner, params FsmState[] states) + { + if (owner == null) + { + throw new GameFrameworkException("FSM owner is invalid."); + } + + if (states == null || states.Length < 1) + { + throw new GameFrameworkException("FSM states is invalid."); + } + + Fsm fsm = MemoryPool.Acquire>(); + fsm.Name = name; + fsm._owner = owner; + fsm._isDestroyed = false; + foreach (FsmState state in states) + { + if (state == null) + { + throw new GameFrameworkException("FSM states is invalid."); + } + + Type stateType = state.GetType(); + if (fsm._states.ContainsKey(stateType)) + { + throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name), stateType.FullName)); + } + + fsm._states.Add(stateType, state); + state.OnInit(fsm); + } + + return fsm; + } + + /// + /// 创建有限状态机。 + /// + /// 有限状态机名称。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 创建的有限状态机。 + public static Fsm Create(string name, T owner, List> states) + { + if (owner == null) + { + throw new GameFrameworkException("FSM owner is invalid."); + } + + if (states == null || states.Count < 1) + { + throw new GameFrameworkException("FSM states is invalid."); + } + + Fsm fsm = MemoryPool.Acquire>(); + fsm.Name = name; + fsm._owner = owner; + fsm._isDestroyed = false; + foreach (FsmState state in states) + { + if (state == null) + { + throw new GameFrameworkException("FSM states is invalid."); + } + + Type stateType = state.GetType(); + if (fsm._states.ContainsKey(stateType)) + { + throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' state '{1}' is already exist.", new TypeNamePair(typeof(T), name), stateType.FullName)); + } + + fsm._states.Add(stateType, state); + state.OnInit(fsm); + } + + return fsm; + } + + /// + /// 清理有限状态机。 + /// + public void Clear() + { + if (_currentState != null) + { + _currentState.OnLeave(this, true); + } + + foreach (KeyValuePair> state in _states) + { + state.Value.OnDestroy(this); + } + + Name = null; + _owner = null; + _states?.Clear(); + _dataMap?.Clear(); + _currentState = null; + _currentStateTime = 0f; + _isDestroyed = true; + } + + /// + /// 开始有限状态机。 + /// + /// 要开始的有限状态机状态类型。 + public void Start() where TState : FsmState + { + if (IsRunning) + { + throw new GameFrameworkException("FSM is running, can not start again."); + } + + FsmState state = GetState(); + if (state == null) + { + throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), typeof(TState).FullName)); + } + + _currentStateTime = 0f; + _currentState = state; + _currentState.OnEnter(this); + } + + /// + /// 开始有限状态机。 + /// + /// 要开始的有限状态机状态类型。 + public void Start(Type stateType) + { + if (IsRunning) + { + throw new GameFrameworkException("FSM is running, can not start again."); + } + + if (stateType == null) + { + throw new GameFrameworkException("State type is invalid."); + } + + if (!typeof(FsmState).IsAssignableFrom(stateType)) + { + throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName)); + } + + FsmState state = GetState(stateType); + if (state == null) + { + throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not start state '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), stateType.FullName)); + } + + _currentStateTime = 0f; + _currentState = state; + _currentState.OnEnter(this); + } + + /// + /// 是否存在有限状态机状态。 + /// + /// 要检查的有限状态机状态类型。 + /// 是否存在有限状态机状态。 + public bool HasState() where TState : FsmState + { + return _states.ContainsKey(typeof(TState)); + } + + /// + /// 是否存在有限状态机状态。 + /// + /// 要检查的有限状态机状态类型。 + /// 是否存在有限状态机状态。 + public bool HasState(Type stateType) + { + if (stateType == null) + { + throw new GameFrameworkException("State type is invalid."); + } + + if (!typeof(FsmState).IsAssignableFrom(stateType)) + { + throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName)); + } + + return _states.ContainsKey(stateType); + } + + /// + /// 获取有限状态机状态。 + /// + /// 要获取的有限状态机状态类型。 + /// 要获取的有限状态机状态。 + public TState GetState() where TState : FsmState + { + FsmState state = null; + if (_states.TryGetValue(typeof(TState), out state)) + { + return (TState)state; + } + + return null; + } + + /// + /// 获取有限状态机状态。 + /// + /// 要获取的有限状态机状态类型。 + /// 要获取的有限状态机状态。 + public FsmState GetState(Type stateType) + { + if (stateType == null) + { + throw new GameFrameworkException("State type is invalid."); + } + + if (!typeof(FsmState).IsAssignableFrom(stateType)) + { + throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName)); + } + + FsmState state = null; + if (_states.TryGetValue(stateType, out state)) + { + return state; + } + + return null; + } + + /// + /// 获取有限状态机的所有状态。 + /// + /// 有限状态机的所有状态。 + public FsmState[] GetAllStates() + { + int index = 0; + FsmState[] results = new FsmState[_states.Count]; + foreach (KeyValuePair> state in _states) + { + results[index++] = state.Value; + } + + return results; + } + + /// + /// 获取有限状态机的所有状态。 + /// + /// 有限状态机的所有状态。 + public void GetAllStates(List> results) + { + if (results == null) + { + throw new GameFrameworkException("Results is invalid."); + } + + results.Clear(); + foreach (KeyValuePair> state in _states) + { + results.Add(state.Value); + } + } + + /// + /// 是否存在有限状态机数据。 + /// + /// 有限状态机数据名称。 + /// 有限状态机数据是否存在。 + public bool HasData(string name) + { + if (string.IsNullOrEmpty(name)) + { + throw new GameFrameworkException("Data name is invalid."); + } + + if (_dataMap == null) + { + return false; + } + + return _dataMap.ContainsKey(name); + } + + /// + /// 获取有限状态机数据。 + /// + /// 要获取的有限状态机数据的类型。 + /// 有限状态机数据名称。 + /// 要获取的有限状态机数据。 + public TData GetData(string name) + { + return (TData)GetData(name); + } + + /// + /// 获取有限状态机数据。 + /// + /// 有限状态机数据名称。 + /// 要获取的有限状态机数据。 + public object GetData(string name) + { + if (string.IsNullOrEmpty(name)) + { + throw new GameFrameworkException("Data name is invalid."); + } + + if (_dataMap == null) + { + return null; + } + + if (_dataMap.TryGetValue(name, out var data)) + { + return data; + } + + return null; + } + + /// + /// 设置有限状态机数据。 + /// + /// 要设置的有限状态机数据的类型。 + /// 有限状态机数据名称。 + /// 要设置的有限状态机数据。 + public void SetData(string name, TData data) + { + SetData(name, (object)data); + } + + /// + /// 设置有限状态机数据。 + /// + /// 有限状态机数据名称。 + /// 要设置的有限状态机数据。 + public void SetData(string name, object data) + { + if (string.IsNullOrEmpty(name)) + { + throw new GameFrameworkException("Data name is invalid."); + } + + if (_dataMap == null) + { + _dataMap = new Dictionary(StringComparer.Ordinal); + } + + _dataMap[name] = data; + } + + /// + /// 移除有限状态机数据。 + /// + /// 有限状态机数据名称。 + /// 是否移除有限状态机数据成功。 + public bool RemoveData(string name) + { + if (string.IsNullOrEmpty(name)) + { + throw new GameFrameworkException("Data name is invalid."); + } + + if (_dataMap == null) + { + return false; + } + + return _dataMap.Remove(name); + } + + /// + /// 有限状态机轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + if (_currentState == null) + { + return; + } + + _currentStateTime += elapseSeconds; + _currentState.OnUpdate(this, elapseSeconds, realElapseSeconds); + } + + /// + /// 关闭并清理有限状态机。 + /// + internal override void Shutdown() + { + MemoryPool.Release(this); + } + + /// + /// 切换当前有限状态机状态。 + /// + /// 要切换到的有限状态机状态类型。 + internal void ChangeState() where TState : FsmState + { + ChangeState(typeof(TState)); + } + + /// + /// 切换当前有限状态机状态。 + /// + /// 要切换到的有限状态机状态类型。 + internal void ChangeState(Type stateType) + { + if (_currentState == null) + { + throw new GameFrameworkException("Current state is invalid."); + } + + FsmState state = GetState(stateType); + if (state == null) + { + throw new GameFrameworkException(Utility.Text.Format("FSM '{0}' can not change state to '{1}' which is not exist.", new TypeNamePair(typeof(T), Name), stateType.FullName)); + } + + _currentState.OnLeave(this, false); + _currentStateTime = 0f; + _currentState = state; + _currentState.OnEnter(this); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/Fsm.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/Fsm.cs.meta new file mode 100644 index 00000000..e6441f29 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/Fsm.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3706fab38c144cd5a30f5b14946e22e5 +timeCreated: 1680503869 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmBase.cs b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmBase.cs new file mode 100644 index 00000000..8fd98af7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmBase.cs @@ -0,0 +1,94 @@ +using System; + +namespace TEngine +{ + /// + /// 有限状态机基类。 + /// + public abstract class FsmBase + { + private string _name; + + /// + /// 初始化有限状态机基类的新实例。 + /// + public FsmBase() + { + _name = string.Empty; + } + + /// + /// 获取有限状态机名称。 + /// + public string Name + { + get => _name; + protected set => _name = value ?? string.Empty; + } + + /// + /// 获取有限状态机完整名称。 + /// + public string FullName => new TypeNamePair(OwnerType, _name).ToString(); + + /// + /// 获取有限状态机持有者类型。 + /// + public abstract Type OwnerType + { + get; + } + + /// + /// 获取有限状态机中状态的数量。 + /// + public abstract int FsmStateCount + { + get; + } + + /// + /// 获取有限状态机是否正在运行。 + /// + public abstract bool IsRunning + { + get; + } + + /// + /// 获取有限状态机是否被销毁。 + /// + public abstract bool IsDestroyed + { + get; + } + + /// + /// 获取当前有限状态机状态名称。 + /// + public abstract string CurrentStateName + { + get; + } + + /// + /// 获取当前有限状态机状态持续时间。 + /// + public abstract float CurrentStateTime + { + get; + } + + /// + /// 有限状态机轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 当前已流逝时间,以秒为单位。 + internal abstract void Update(float elapseSeconds, float realElapseSeconds); + + /// + /// 关闭并清理有限状态机。 + /// + internal abstract void Shutdown(); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmBase.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmBase.cs.meta new file mode 100644 index 00000000..2c0e2b0c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmBase.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c9096cb538b149d08ca95c78f651c111 +timeCreated: 1680503870 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmManager.cs new file mode 100644 index 00000000..badef941 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmManager.cs @@ -0,0 +1,393 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 有限状态机管理器。 + /// + [UpdateModule] + internal sealed class FsmManager : ModuleImp, IFsmManager + { + private readonly Dictionary _fsmMap; + private readonly List _tempFsmList; + + /// + /// 初始化有限状态机管理器的新实例。 + /// + public FsmManager() + { + _fsmMap = new Dictionary(); + _tempFsmList = new List(); + } + + /// + /// 获取游戏框架模块优先级。 + /// + /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 + internal override int Priority => 1; + + /// + /// 获取有限状态机数量。 + /// + public int Count => _fsmMap.Count; + + /// + /// 有限状态机管理器轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + _tempFsmList.Clear(); + if (_fsmMap.Count <= 0) + { + return; + } + + foreach (KeyValuePair fsm in _fsmMap) + { + _tempFsmList.Add(fsm.Value); + } + + foreach (FsmBase fsm in _tempFsmList) + { + if (fsm.IsDestroyed) + { + continue; + } + + fsm.Update(elapseSeconds, realElapseSeconds); + } + } + + /// + /// 关闭并清理有限状态机管理器。 + /// + internal override void Shutdown() + { + foreach (KeyValuePair fsm in _fsmMap) + { + fsm.Value.Shutdown(); + } + + _fsmMap.Clear(); + _tempFsmList.Clear(); + } + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否存在有限状态机。 + public bool HasFsm() where T : class + { + return InternalHasFsm(new TypeNamePair(typeof(T))); + } + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否存在有限状态机。 + public bool HasFsm(Type ownerType) + { + if (ownerType == null) + { + throw new GameFrameworkException("Owner type is invalid."); + } + + return InternalHasFsm(new TypeNamePair(ownerType)); + } + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 是否存在有限状态机。 + public bool HasFsm(string name) where T : class + { + return InternalHasFsm(new TypeNamePair(typeof(T), name)); + } + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 是否存在有限状态机。 + public bool HasFsm(Type ownerType, string name) + { + if (ownerType == null) + { + throw new GameFrameworkException("Owner type is invalid."); + } + + return InternalHasFsm(new TypeNamePair(ownerType, name)); + } + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要获取的有限状态机。 + public IFsm GetFsm() where T : class + { + return (IFsm)InternalGetFsm(new TypeNamePair(typeof(T))); + } + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要获取的有限状态机。 + public FsmBase GetFsm(Type ownerType) + { + if (ownerType == null) + { + throw new GameFrameworkException("Owner type is invalid."); + } + + return InternalGetFsm(new TypeNamePair(ownerType)); + } + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 要获取的有限状态机。 + public IFsm GetFsm(string name) where T : class + { + return (IFsm)InternalGetFsm(new TypeNamePair(typeof(T), name)); + } + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 要获取的有限状态机。 + public FsmBase GetFsm(Type ownerType, string name) + { + if (ownerType == null) + { + throw new GameFrameworkException("Owner type is invalid."); + } + + return InternalGetFsm(new TypeNamePair(ownerType, name)); + } + + /// + /// 获取所有有限状态机。 + /// + /// 所有有限状态机。 + public FsmBase[] GetAllFsms() + { + int index = 0; + FsmBase[] results = new FsmBase[_fsmMap.Count]; + foreach (KeyValuePair fsm in _fsmMap) + { + results[index++] = fsm.Value; + } + + return results; + } + + /// + /// 获取所有有限状态机。 + /// + /// 所有有限状态机。 + public void GetAllFsms(List results) + { + if (results == null) + { + throw new GameFrameworkException("Results is invalid."); + } + + results.Clear(); + foreach (KeyValuePair fsm in _fsmMap) + { + results.Add(fsm.Value); + } + } + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + public IFsm CreateFsm(T owner, params FsmState[] states) where T : class + { + return CreateFsm(string.Empty, owner, states); + } + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + public IFsm CreateFsm(string name, T owner, params FsmState[] states) where T : class + { + TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name); + if (HasFsm(name)) + { + throw new GameFrameworkException(Utility.Text.Format("Already exist FSM '{0}'.", typeNamePair)); + } + + Fsm fsm = Fsm.Create(name, owner, states); + _fsmMap.Add(typeNamePair, fsm); + return fsm; + } + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + public IFsm CreateFsm(T owner, List> states) where T : class + { + return CreateFsm(string.Empty, owner, states); + } + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + public IFsm CreateFsm(string name, T owner, List> states) where T : class + { + TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name); + if (HasFsm(name)) + { + throw new GameFrameworkException(Utility.Text.Format("Already exist FSM '{0}'.", typeNamePair)); + } + + Fsm fsm = Fsm.Create(name, owner, states); + _fsmMap.Add(typeNamePair, fsm); + return fsm; + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm() where T : class + { + return InternalDestroyFsm(new TypeNamePair(typeof(T))); + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(Type ownerType) + { + if (ownerType == null) + { + throw new GameFrameworkException("Owner type is invalid."); + } + + return InternalDestroyFsm(new TypeNamePair(ownerType)); + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要销毁的有限状态机名称。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(string name) where T : class + { + return InternalDestroyFsm(new TypeNamePair(typeof(T), name)); + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要销毁的有限状态机名称。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(Type ownerType, string name) + { + if (ownerType == null) + { + throw new GameFrameworkException("Owner type is invalid."); + } + + return InternalDestroyFsm(new TypeNamePair(ownerType, name)); + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要销毁的有限状态机。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(IFsm fsm) where T : class + { + if (fsm == null) + { + throw new GameFrameworkException("FSM is invalid."); + } + + return InternalDestroyFsm(new TypeNamePair(typeof(T), fsm.Name)); + } + + /// + /// 销毁有限状态机。 + /// + /// 要销毁的有限状态机。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(FsmBase fsm) + { + if (fsm == null) + { + throw new GameFrameworkException("FSM is invalid."); + } + + return InternalDestroyFsm(new TypeNamePair(fsm.OwnerType, fsm.Name)); + } + + private bool InternalHasFsm(TypeNamePair typeNamePair) + { + return _fsmMap.ContainsKey(typeNamePair); + } + + private FsmBase InternalGetFsm(TypeNamePair typeNamePair) + { + FsmBase fsm = null; + if (_fsmMap.TryGetValue(typeNamePair, out fsm)) + { + return fsm; + } + + return null; + } + + private bool InternalDestroyFsm(TypeNamePair typeNamePair) + { + FsmBase fsm = null; + if (_fsmMap.TryGetValue(typeNamePair, out fsm)) + { + fsm.Shutdown(); + return _fsmMap.Remove(typeNamePair); + } + + return false; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmManager.cs.meta new file mode 100644 index 00000000..4711ad2f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 839a80bc3c4f454f9718609ca8cded3e +timeCreated: 1680503870 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmModule.cs new file mode 100644 index 00000000..df3f22f3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmModule.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine +{ + /// + /// 有限状态机模块。 + /// + [DisallowMultipleComponent] + public sealed class FsmModule : Module + { + private IFsmManager _fsmManager = null; + + /// + /// 获取有限状态机数量。 + /// + public int Count => _fsmManager.Count; + + /// + /// 游戏框架模块初始化。 + /// + protected override void Awake() + { + base.Awake(); + + _fsmManager = ModuleImpSystem.GetModule(); + if (_fsmManager == null) + { + Log.Fatal("FSM manager is invalid."); + return; + } + } + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否存在有限状态机。 + public bool HasFsm() where T : class + { + return _fsmManager.HasFsm(); + } + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否存在有限状态机。 + public bool HasFsm(Type ownerType) + { + return _fsmManager.HasFsm(ownerType); + } + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 是否存在有限状态机。 + public bool HasFsm(string name) where T : class + { + return _fsmManager.HasFsm(name); + } + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 是否存在有限状态机。 + public bool HasFsm(Type ownerType, string name) + { + return _fsmManager.HasFsm(ownerType, name); + } + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要获取的有限状态机。 + public IFsm GetFsm() where T : class + { + return _fsmManager.GetFsm(); + } + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要获取的有限状态机。 + public FsmBase GetFsm(Type ownerType) + { + return _fsmManager.GetFsm(ownerType); + } + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 要获取的有限状态机。 + public IFsm GetFsm(string name) where T : class + { + return _fsmManager.GetFsm(name); + } + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 要获取的有限状态机。 + public FsmBase GetFsm(Type ownerType, string name) + { + return _fsmManager.GetFsm(ownerType, name); + } + + /// + /// 获取所有有限状态机。 + /// + public FsmBase[] GetAllFsms() + { + return _fsmManager.GetAllFsms(); + } + + /// + /// 获取所有有限状态机。 + /// + /// 所有有限状态机。 + public void GetAllFsms(List results) + { + _fsmManager.GetAllFsms(results); + } + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + public IFsm CreateFsm(T owner, params FsmState[] states) where T : class + { + return _fsmManager.CreateFsm(owner, states); + } + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + public IFsm CreateFsm(string name, T owner, params FsmState[] states) where T : class + { + return _fsmManager.CreateFsm(name, owner, states); + } + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + public IFsm CreateFsm(T owner, List> states) where T : class + { + return _fsmManager.CreateFsm(owner, states); + } + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + public IFsm CreateFsm(string name, T owner, List> states) where T : class + { + return _fsmManager.CreateFsm(name, owner, states); + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm() where T : class + { + return _fsmManager.DestroyFsm(); + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(Type ownerType) + { + return _fsmManager.DestroyFsm(ownerType); + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要销毁的有限状态机名称。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(string name) where T : class + { + return _fsmManager.DestroyFsm(name); + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要销毁的有限状态机名称。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(Type ownerType, string name) + { + return _fsmManager.DestroyFsm(ownerType, name); + } + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要销毁的有限状态机。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(IFsm fsm) where T : class + { + return _fsmManager.DestroyFsm(fsm); + } + + /// + /// 销毁有限状态机。 + /// + /// 要销毁的有限状态机。 + /// 是否销毁有限状态机成功。 + public bool DestroyFsm(FsmBase fsm) + { + return _fsmManager.DestroyFsm(fsm); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmModule.cs.meta new file mode 100644 index 00000000..91eee924 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 351f97b231854e659f0b7af89d8478c6 +timeCreated: 1680504514 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmState.cs b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmState.cs new file mode 100644 index 00000000..1f87e2f5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmState.cs @@ -0,0 +1,103 @@ +using System; + +namespace TEngine +{ + /// + /// 有限状态机状态基类。 + /// + /// 有限状态机持有者类型。 + public abstract class FsmState where T : class + { + /// + /// 初始化有限状态机状态基类的新实例。 + /// + public FsmState() + { + } + + /// + /// 有限状态机状态初始化时调用。 + /// + /// 有限状态机引用。 + protected internal virtual void OnInit(IFsm fsm) + { + } + + /// + /// 有限状态机状态进入时调用。 + /// + /// 有限状态机引用。 + protected internal virtual void OnEnter(IFsm fsm) + { + } + + /// + /// 有限状态机状态轮询时调用。 + /// + /// 有限状态机引用。 + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + protected internal virtual void OnUpdate(IFsm fsm, float elapseSeconds, float realElapseSeconds) + { + } + + /// + /// 有限状态机状态离开时调用。 + /// + /// 有限状态机引用。 + /// 是否是关闭有限状态机时触发。 + protected internal virtual void OnLeave(IFsm fsm, bool isShutdown) + { + } + + /// + /// 有限状态机状态销毁时调用。 + /// + /// 有限状态机引用。 + protected internal virtual void OnDestroy(IFsm fsm) + { + } + + /// + /// 切换当前有限状态机状态。 + /// + /// 要切换到的有限状态机状态类型。 + /// 有限状态机引用。 + protected void ChangeState(IFsm fsm) where TState : FsmState + { + Fsm fsmImplement = (Fsm)fsm; + if (fsmImplement == null) + { + throw new GameFrameworkException("FSM is invalid."); + } + + fsmImplement.ChangeState(); + } + + /// + /// 切换当前有限状态机状态。 + /// + /// 有限状态机引用。 + /// 要切换到的有限状态机状态类型。 + protected void ChangeState(IFsm fsm, Type stateType) + { + Fsm fsmImplement = (Fsm)fsm; + if (fsmImplement == null) + { + throw new GameFrameworkException("FSM is invalid."); + } + + if (stateType == null) + { + throw new GameFrameworkException("State type is invalid."); + } + + if (!typeof(FsmState).IsAssignableFrom(stateType)) + { + throw new GameFrameworkException(Utility.Text.Format("State type '{0}' is invalid.", stateType.FullName)); + } + + fsmImplement.ChangeState(stateType); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmState.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmState.cs.meta new file mode 100644 index 00000000..25258053 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/FsmState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 45ba0a93666a491296ffd4abfaec75e8 +timeCreated: 1680503870 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsm.cs b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsm.cs new file mode 100644 index 00000000..7b41e2a0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsm.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 有限状态机接口。 + /// + /// 有限状态机持有者类型。 + public interface IFsm where T : class + { + /// + /// 获取有限状态机名称。 + /// + string Name + { + get; + } + + /// + /// 获取有限状态机完整名称。 + /// + string FullName + { + get; + } + + /// + /// 获取有限状态机持有者。 + /// + T Owner + { + get; + } + + /// + /// 获取有限状态机中状态的数量。 + /// + int FsmStateCount + { + get; + } + + /// + /// 获取有限状态机是否正在运行。 + /// + bool IsRunning + { + get; + } + + /// + /// 获取有限状态机是否被销毁。 + /// + bool IsDestroyed + { + get; + } + + /// + /// 获取当前有限状态机状态。 + /// + FsmState CurrentState + { + get; + } + + /// + /// 获取当前有限状态机状态持续时间。 + /// + float CurrentStateTime + { + get; + } + + /// + /// 开始有限状态机。 + /// + /// 要开始的有限状态机状态类型。 + void Start() where TState : FsmState; + + /// + /// 开始有限状态机。 + /// + /// 要开始的有限状态机状态类型。 + void Start(Type stateType); + + /// + /// 是否存在有限状态机状态。 + /// + /// 要检查的有限状态机状态类型。 + /// 是否存在有限状态机状态。 + bool HasState() where TState : FsmState; + + /// + /// 是否存在有限状态机状态。 + /// + /// 要检查的有限状态机状态类型。 + /// 是否存在有限状态机状态。 + bool HasState(Type stateType); + + /// + /// 获取有限状态机状态。 + /// + /// 要获取的有限状态机状态类型。 + /// 要获取的有限状态机状态。 + TState GetState() where TState : FsmState; + + /// + /// 获取有限状态机状态。 + /// + /// 要获取的有限状态机状态类型。 + /// 要获取的有限状态机状态。 + FsmState GetState(Type stateType); + + /// + /// 获取有限状态机的所有状态。 + /// + /// 有限状态机的所有状态。 + FsmState[] GetAllStates(); + + /// + /// 获取有限状态机的所有状态。 + /// + /// 有限状态机的所有状态。 + void GetAllStates(List> results); + + /// + /// 是否存在有限状态机数据。 + /// + /// 有限状态机数据名称。 + /// 有限状态机数据是否存在。 + bool HasData(string name); + + /// + /// 获取有限状态机数据。 + /// + /// 要获取的有限状态机数据的类型。 + /// 有限状态机数据名称。 + /// 要获取的有限状态机数据。 + TData GetData(string name); + + /// + /// 设置有限状态机数据。 + /// + /// 要设置的有限状态机数据的类型。 + /// 有限状态机数据名称。 + /// 要设置的有限状态机数据。 + void SetData(string name, TData data); + + /// + /// 移除有限状态机数据。 + /// + /// 有限状态机数据名称。 + /// 是否移除有限状态机数据成功。 + bool RemoveData(string name); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsm.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsm.cs.meta new file mode 100644 index 00000000..b0c94df1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsm.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 675620bfcf2643e4a58641c33ce1537e +timeCreated: 1680503870 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsmManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsmManager.cs new file mode 100644 index 00000000..1a06b804 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsmManager.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 有限状态机管理器。 + /// + public interface IFsmManager + { + /// + /// 获取有限状态机数量。 + /// + int Count + { + get; + } + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否存在有限状态机。 + bool HasFsm() where T : class; + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否存在有限状态机。 + bool HasFsm(Type ownerType); + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 是否存在有限状态机。 + bool HasFsm(string name) where T : class; + + /// + /// 检查是否存在有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 是否存在有限状态机。 + bool HasFsm(Type ownerType, string name); + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要获取的有限状态机。 + IFsm GetFsm() where T : class; + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要获取的有限状态机。 + FsmBase GetFsm(Type ownerType); + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 要获取的有限状态机。 + IFsm GetFsm(string name) where T : class; + + /// + /// 获取有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 要获取的有限状态机。 + FsmBase GetFsm(Type ownerType, string name); + + /// + /// 获取所有有限状态机。 + /// + /// 所有有限状态机。 + FsmBase[] GetAllFsms(); + + /// + /// 获取所有有限状态机。 + /// + /// 所有有限状态机。 + void GetAllFsms(List results); + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + IFsm CreateFsm(T owner, params FsmState[] states) where T : class; + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + IFsm CreateFsm(string name, T owner, params FsmState[] states) where T : class; + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + IFsm CreateFsm(T owner, List> states) where T : class; + + /// + /// 创建有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 有限状态机名称。 + /// 有限状态机持有者。 + /// 有限状态机状态集合。 + /// 要创建的有限状态机。 + IFsm CreateFsm(string name, T owner, List> states) where T : class; + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否销毁有限状态机成功。 + bool DestroyFsm() where T : class; + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 是否销毁有限状态机成功。 + bool DestroyFsm(Type ownerType); + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要销毁的有限状态机名称。 + /// 是否销毁有限状态机成功。 + bool DestroyFsm(string name) where T : class; + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要销毁的有限状态机名称。 + /// 是否销毁有限状态机成功。 + bool DestroyFsm(Type ownerType, string name); + + /// + /// 销毁有限状态机。 + /// + /// 有限状态机持有者类型。 + /// 要销毁的有限状态机。 + /// 是否销毁有限状态机成功。 + bool DestroyFsm(IFsm fsm) where T : class; + + /// + /// 销毁有限状态机。 + /// + /// 要销毁的有限状态机。 + /// 是否销毁有限状态机成功。 + bool DestroyFsm(FsmBase fsm); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsmManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsmManager.cs.meta new file mode 100644 index 00000000..807fd02d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/FsmModule/IFsmManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2c9f1536f7484d609c882586db2dc855 +timeCreated: 1680503870 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/GameModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/GameModule.cs new file mode 100644 index 00000000..8ef135bb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/GameModule.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace TEngine +{ + /// + /// 游戏模块。 + /// + public partial class GameModule : MonoBehaviour + { + private static readonly Dictionary _moduleMaps = new Dictionary(ModuleImpSystem.DesignModuleCount); + + private static GameObject _gameModuleRoot; + + #region 框架模块 + /// + /// 获取游戏基础模块。 + /// + public static RootModule Base + { + get => _base ??= Get(); + private set => _base = value; + } + + private static RootModule _base; + + /// + /// 获取调试模块。 + /// + public static DebuggerModule Debugger + { + get => _debugger ??= Get(); + private set => _debugger = value; + } + + + private static DebuggerModule _debugger; + + /// + /// 获取有限状态机模块。 + /// + public static FsmModule Fsm => _fsm ??= Get(); + + private static FsmModule _fsm; + + /// + /// 流程管理模块。 + /// + public static ProcedureModule Procedure => _procedure ??= Get(); + + private static ProcedureModule _procedure; + + /// + /// 获取对象池模块。 + /// + public static ObjectPoolModule ObjectPool => _objectPool ??= Get(); + + private static ObjectPoolModule _objectPool; + + /// + /// 获取资源模块。 + /// + public static ResourceModule Resource => _resource ??= Get(); + + private static ResourceModule _resource; + + /// + /// 获取音频模块。 + /// + public static AudioModule Audio => _audio ??= Get(); + + private static AudioModule _audio; + + /// + /// 获取配置模块。 + /// + public static SettingModule Setting => _setting ??= Get(); + + private static SettingModule _setting; + + /// + /// 获取UI模块。 + /// + public static UIModule UI => _ui ??= Get(); + + private static UIModule _ui; + + /// + /// 获取多语言模块。 + /// + public static LocalizationModule Localization => _localization ??= Get(); + + private static LocalizationModule _localization; + + /// + /// 获取场景模块。 + /// + public static SceneModule Scene => _scene ??= Get(); + + private static SceneModule _scene; + + /// + /// 获取计时器模块。 + /// + public static TimerModule Timer => _timer ??= Get(); + + private static TimerModule _timer; + + /// + /// 资源组件拓展。 + /// + public static ResourceExtComponent ResourceExt => _resourceExt ??= Get(); + + private static ResourceExtComponent _resourceExt; + #endregion + + /// + /// 获取游戏框架模块类。 + /// + /// 游戏框架模块类。 + /// 游戏框架模块实例。 + public static T Get() where T : Module + { + Type type = typeof(T); + + if (_moduleMaps.TryGetValue(type, out var ret)) + { + return ret as T; + } + + T module = ModuleSystem.GetModule(); + + Log.Assert(condition: module != null, $"{typeof(T)} is null"); + + _moduleMaps.Add(type, module); + + return module; + } + + private void Start() + { + Log.Info("GameModule Active"); + gameObject.name = $"[{nameof(GameModule)}]"; + _gameModuleRoot = gameObject; + DontDestroyOnLoad(gameObject); + } + + public static void Shutdown(ShutdownType shutdownType) + { + Log.Info("GameModule Shutdown"); + if (_gameModuleRoot != null) + { + Destroy(_gameModuleRoot); + _gameModuleRoot = null; + } + _moduleMaps.Clear(); + + _base = null; + _debugger = null; + _fsm = null; + _procedure = null; + _objectPool = null; + _resource = null; + _audio = null; + _setting = null; + _ui = null; + _localization = null; + _scene = null; + _timer = null; + _resourceExt = null; + } + + #region HandlePlayModeStateChanged + private void OnEnable() + { +#if UNITY_EDITOR + EditorApplication.playModeStateChanged += HandlePlayModeStateChanged; +#endif + } + + private void OnDisable() + { +#if UNITY_EDITOR + EditorApplication.playModeStateChanged -= HandlePlayModeStateChanged; +#endif + } + +#if UNITY_EDITOR + void HandlePlayModeStateChanged(PlayModeStateChange state) + { + if (state == PlayModeStateChange.ExitingPlayMode) + { + ModuleImpSystem.Shutdown(); + ModuleSystem.Shutdown(ShutdownType.Quit); + } + } +#endif + #endregion + + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/GameModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/GameModule.cs.meta new file mode 100644 index 00000000..db6c1617 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/GameModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 52c67ae7ae1743a09e764b172bd1edce +timeCreated: 1694835084 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Helper.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Helper.meta new file mode 100644 index 00000000..4fe33721 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Helper.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a046a4f2fc154316984e6adacbd2adc1 +timeCreated: 1695116119 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Helper/Helper.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Helper/Helper.cs new file mode 100644 index 00000000..3e2f1261 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Helper/Helper.cs @@ -0,0 +1,68 @@ +using TEngine; +using UnityEngine; + +namespace TEngine +{ + /// + /// 辅助器创建器相关的实用函数。 + /// + public static class Helper + { + /// + /// 创建辅助器。 + /// + /// 要创建的辅助器类型。 + /// 要创建的辅助器类型名称。 + /// 若要创建的辅助器类型为空时,使用的自定义辅助器类型。 + /// 创建的辅助器。 + public static T CreateHelper(string helperTypeName, T customHelper) where T : MonoBehaviour + { + return CreateHelper(helperTypeName, customHelper, 0); + } + + /// + /// 创建辅助器。 + /// + /// 要创建的辅助器类型。 + /// 要创建的辅助器类型名称。 + /// 若要创建的辅助器类型为空时,使用的自定义辅助器类型。 + /// 要创建的辅助器索引。 + /// 创建的辅助器。 + public static T CreateHelper(string helperTypeName, T customHelper, int index) where T : MonoBehaviour + { + T helper = null; + if (!string.IsNullOrEmpty(helperTypeName)) + { + System.Type helperType = Utility.Assembly.GetType(helperTypeName); + if (helperType == null) + { + Log.Warning("Can not find helper type '{0}'.", helperTypeName); + return null; + } + + if (!typeof(T).IsAssignableFrom(helperType)) + { + Log.Warning("Type '{0}' is not assignable from '{1}'.", typeof(T).FullName, helperType.FullName); + return null; + } + + helper = (T)new GameObject().AddComponent(helperType); + } + else if (customHelper == null) + { + Log.Warning("You must set custom helper with '{0}' type first.", typeof(T).FullName); + return null; + } + else if (customHelper.gameObject.InScene()) + { + helper = index > 0 ? Object.Instantiate(customHelper) : customHelper; + } + else + { + helper = Object.Instantiate(customHelper); + } + + return helper; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Helper/Helper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Helper/Helper.cs.meta new file mode 100644 index 00000000..3c62bf67 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Helper/Helper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 376bf8b0a9454a8da3b2113549c9dfd5 +timeCreated: 1695116131 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization.meta new file mode 100644 index 00000000..1e4d1d9f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b432fba7c84e874aa7774fcf01f8e18 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core.meta new file mode 100644 index 00000000..c4921acb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c593d66e0920d6a43a58e3cdc76e64f6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables.meta new file mode 100644 index 00000000..e6fb797e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8f9a3530624fd5c47a2dc16eb641ddb8 +folderAsset: yes +timeCreated: 1520745251 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables/PersistentStorage.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables/PersistentStorage.cs new file mode 100644 index 00000000..fcfce870 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Configurables/PersistentStorage.cs @@ -0,0 +1,286 @@ +using System; +using System.Globalization; +using System.IO; +using System.Text; +using UnityEngine; + +namespace TEngine.Localization +{ + public static class PersistentStorage + { + static I2CustomPersistentStorage mStorage; + + public enum eFileType { Raw, Persistent, Temporal, Streaming } + + #region PlayerPrefs + public static void SetSetting_String(string key, string value) + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + mStorage.SetSetting_String(key, value); + } + + public static string GetSetting_String(string key, string defaultValue) + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + return mStorage.GetSetting_String(key, defaultValue); + } + + public static void DeleteSetting(string key) + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + mStorage.DeleteSetting(key); + } + + public static bool HasSetting( string key ) + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + return mStorage.HasSetting(key); + } + + public static void ForceSaveSettings() + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + mStorage.ForceSaveSettings(); + } + + #endregion + + #region File Management + + public static bool CanAccessFiles() + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + return mStorage.CanAccessFiles(); + } + + public static bool SaveFile(eFileType fileType, string fileName, string data, bool logExceptions = true) + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + return mStorage.SaveFile(fileType, fileName, data, logExceptions); + } + + public static string LoadFile(eFileType fileType, string fileName, bool logExceptions=true) + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + return mStorage.LoadFile(fileType, fileName, logExceptions); + } + + public static bool DeleteFile(eFileType fileType, string fileName, bool logExceptions = true) + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + return mStorage.DeleteFile(fileType, fileName, logExceptions); + } + + public static bool HasFile(eFileType fileType, string fileName, bool logExceptions = true) + { + if (mStorage == null) mStorage = new I2CustomPersistentStorage(); + return mStorage.HasFile(fileType, fileName, logExceptions); + } + + #endregion + } + + public abstract class I2BasePersistentStorage + { + #region PlayerPrefs + public virtual void SetSetting_String(string key, string value) + { + try + { + // Use PlayerPrefs, but if the data is bigger than the limit, split it into multiple entries + var len = value.Length; + int maxLength = 8000; + if (len<=maxLength) + { + PlayerPrefs.SetString(key, value); + } + else + { + int numSections = Mathf.CeilToInt(len / (float)maxLength); + for (int i=0; i mSpecializationsFallbacks; + + public virtual void InitializeSpecializations() + { + mSpecializations = new[] { "Any", "PC", "Touch", "Controller", "VR", + "XBox", "PS4", "PS5", "OculusVR", "ViveVR", "GearVR", "Android", "IOS", + "Switch" + }; + mSpecializationsFallbacks = new Dictionary(System.StringComparer.Ordinal) + { + { "XBox", "Controller" }, { "PS4", "Controller" }, + { "OculusVR", "VR" }, { "ViveVR", "VR" }, { "GearVR", "VR" }, + { "Android", "Touch" }, { "IOS", "Touch" } + }; + } + + public virtual string GetCurrentSpecialization() + { + if (mSpecializations == null) + InitializeSpecializations(); + + #if UNITY_ANDROID + return "Android"; + #elif UNITY_IOS + return "IOS"; + #elif UNITY_PS4 + return "PS4"; + #elif UNITY_XBOXONE + return "XBox"; + #elif UNITY_SWITCH + return "Switch"; + #elif UNITY_STANDALONE || UNITY_WEBGL + return "PC"; + #else + return (IsTouchInputSupported() ? "Touch" : "PC"); + #endif + } + + bool IsTouchInputSupported() + { + #if ENABLE_INPUT_SYSTEM + return Touchscreen.current != null; + #else + return UnityEngine.Input.touchSupported; + #endif + } + + public virtual string GetFallbackSpecialization(string specialization) + { + if (mSpecializationsFallbacks == null) + InitializeSpecializations(); + + string fallback; + if (mSpecializationsFallbacks.TryGetValue(specialization, out fallback)) + return fallback; + return "Any"; + } + } + public class SpecializationManager : BaseSpecializationManager + { + public static SpecializationManager Singleton = new SpecializationManager(); + + private SpecializationManager() + { + InitializeSpecializations(); + } + + public static string GetSpecializedText(string text, string specialization = null) + { + var idxFirst = text.IndexOf("[i2s_", StringComparison.Ordinal); + if (idxFirst < 0) + return text; + + if (string.IsNullOrEmpty(specialization)) + specialization = Singleton.GetCurrentSpecialization(); + + while (!string.IsNullOrEmpty(specialization) && specialization != "Any") + { + var tag = "[i2s_" + specialization + "]"; + int idx = text.IndexOf(tag, StringComparison.Ordinal); + if (idx < 0) + { + specialization = Singleton.GetFallbackSpecialization(specialization); + continue; + } + + idx += tag.Length; + var idxEnd = text.IndexOf("[i2s_", idx, StringComparison.Ordinal); + if (idxEnd < 0) idxEnd = text.Length; + + return text.Substring(idx, idxEnd - idx); + } + + return text.Substring(0, idxFirst); + } + + public static string SetSpecializedText(string text, string newText, string specialization) + { + if (string.IsNullOrEmpty(specialization)) + specialization = "Any"; + if ((text==null || !text.Contains("[i2s_")) && specialization=="Any") + { + return newText; + } + + var dict = GetSpecializations(text); + dict[specialization] = newText; + + return SetSpecializedText(dict); + } + + public static string SetSpecializedText( Dictionary specializations ) + { + string text; + if (!specializations.TryGetValue("Any", out text)) + text = string.Empty; + + foreach (var kvp in specializations) + { + if (kvp.Key != "Any" && !string.IsNullOrEmpty(kvp.Value)) + text += "[i2s_" + kvp.Key + "]" + kvp.Value; + } + return text; + } + + public static Dictionary GetSpecializations(string text, Dictionary buffer = null) + { + if (buffer == null) + buffer = new Dictionary(StringComparer.Ordinal); + else + buffer.Clear(); + + if (text==null) + { + buffer["Any"] = ""; + return buffer; + } + + var idxFirst = 0; + var idxEnd = text.IndexOf("[i2s_", StringComparison.Ordinal); + if (idxEnd < 0) + idxEnd=text.Length; + + buffer["Any"] = text.Substring(0, idxEnd); + idxFirst = idxEnd; + + while (idxFirst list=null) + { + if (text == null) + return; + + if (list == null) + list = new List(); + + if (!list.Contains("Any")) + list.Add("Any"); + + var idxFirst = 0; + while (idxFirst Español", GUILayout.Height(100))) StartTranslating("en", "es"); + if (GUILayout.Button("Español -> English", GUILayout.Height(100))) StartTranslating("es", "en"); + GUILayout.EndHorizontal(); + + GUILayout.Space(10); + + GUILayout.BeginHorizontal(); + GUILayout.TextArea("Multiple Translation with 1 call:\n'This is an example' -> en,zh\n'Hola' -> en"); + if (GUILayout.Button("Multi Translate", GUILayout.ExpandHeight(true))) ExampleMultiTranslations_Async(); + GUILayout.EndHorizontal(); + + + GUILayout.TextArea(TranslatedText, GUILayout.Width(Screen.width)); + + GUILayout.Space(10); + + + if (IsTranslating) + { + GUILayout.Label("Contacting Google...."); + } + } + + public void StartTranslating(string fromCode, string toCode) + { + IsTranslating = true; + + // fromCode could be "auto" to autodetect the language + GoogleTranslation.Translate(OriginalText, fromCode, toCode, OnTranslationReady); + + // can also use the ForceTranslate version: (it will block the main thread until the translation is returned) + //var translation = GoogleTranslation.ForceTranslate(OriginalText, fromCode, toCode); + //Debug.Log(translation); + } + + void OnTranslationReady(string Translation, string errorMsg) + { + IsTranslating = false; + + if (errorMsg != null) + Debug.LogError(errorMsg); + else + TranslatedText = Translation; + } + + public void ExampleMultiTranslations_Blocking() + { + // This shows how to ask for many translations + var dict = new Dictionary(); + GoogleTranslation.AddQuery("This is an example", "en", "es", dict); + GoogleTranslation.AddQuery("This is an example", "auto", "zh", dict); + GoogleTranslation.AddQuery("Hola", "es", "en", dict); + + if (!GoogleTranslation.ForceTranslate(dict)) + return; + + Debug.Log(GoogleTranslation.GetQueryResult("This is an example", "en", dict)); + Debug.Log(GoogleTranslation.GetQueryResult("This is an example", "zh", dict)); + Debug.Log(GoogleTranslation.GetQueryResult("This is an example", "", dict)); // This returns ANY translation of that text (in this case, the first one 'en') + Debug.Log(dict["Hola"].Results[0]); // example of getting the translation directly from the Results + } + + public void ExampleMultiTranslations_Async() + { + IsTranslating = true; + + // This shows how to ask for many translations + var dict = new Dictionary(); + GoogleTranslation.AddQuery("This is an example", "en", "es", dict); + GoogleTranslation.AddQuery("This is an example", "auto", "zh", dict); + GoogleTranslation.AddQuery("Hola", "es", "en", dict); + + GoogleTranslation.Translate(dict, OnMultitranslationReady); + } + + void OnMultitranslationReady(Dictionary dict, string errorMsg) + { + if (!string.IsNullOrEmpty(errorMsg)) + { + Debug.LogError(errorMsg); + return; + } + + IsTranslating = false; + TranslatedText = ""; + + TranslatedText += GoogleTranslation.GetQueryResult("This is an example", "es", dict) + "\n"; + TranslatedText += GoogleTranslation.GetQueryResult("This is an example", "zh", dict) + "\n"; + TranslatedText += GoogleTranslation.GetQueryResult("This is an example", "", dict) + "\n"; // This returns ANY translation of that text (in this case, the first one 'en') + TranslatedText += dict["Hola"].Results[0]; // example of getting the translation directly from the Results + } + + #region This methods are used in the publisher's Unity Tests + + public bool IsWaitingForTranslation() + { + return IsTranslating; + } + + public string GetTranslatedText() + { + return TranslatedText; + } + + public void SetOriginalText( string text ) + { + OriginalText = text; + } + + #endregion + + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Extension/RealTimeTranslation.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Extension/RealTimeTranslation.cs.meta new file mode 100644 index 00000000..34c932c7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Extension/RealTimeTranslation.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c09397e14dc19fb4ab38f8216b0759a4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: -450 + icon: {instanceID: 0} + userData: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google.meta new file mode 100644 index 00000000..fc051a48 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: dda5008126b59ad4bad4c9d2626a2345 +folderAsset: yes +timeCreated: 1461137613 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleLanguages.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleLanguages.cs new file mode 100644 index 00000000..2818240e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleLanguages.cs @@ -0,0 +1,648 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine.Localization +{ + public enum ePluralType { Zero, One, Two, Few, Many, Plural } + + public static class GoogleLanguages + { + public static string GetLanguageCode(string Filter, bool ShowWarnings = false) + { + if (string.IsNullOrEmpty(Filter)) + return string.Empty; + + string[] Filters = Filter.ToLowerInvariant().Split(" /(),".ToCharArray()); + + foreach (var kvp in mLanguageDef) + if (LanguageMatchesFilter(kvp.Key, Filters)) + return kvp.Value.Code; + + if (ShowWarnings) + Debug.Log($"Language '{Filter}' not recognized. Please, add the language code to GoogleTranslation.cs"); + return string.Empty; + } + + + public static List GetLanguagesForDropdown(string Filter, string CodesToExclude) + { + string[] Filters = Filter.ToLowerInvariant().Split(" /(),".ToCharArray()); + + List Languages = new List(); + + foreach (var kvp in mLanguageDef) + if (string.IsNullOrEmpty(Filter) || LanguageMatchesFilter(kvp.Key, Filters)) + { + string code = string.Concat("[" + kvp.Value.Code + "]"); + if (!CodesToExclude.Contains(code)) + Languages.Add(kvp.Key + " " + code); + } + + // Add headers to variants (e.g. "English/English" before all English variants + for (int i = Languages.Count - 2; i >= 0; --i) + { + string Prefix = Languages[i].Substring(0, Languages[i].IndexOf(" [")); + if (Languages[i + 1].StartsWith(Prefix, StringComparison.Ordinal)) + { + Languages[i] = Prefix + "/" + Languages[i]; + Languages.Insert(i + 1, Prefix + "/"); + } + } + return Languages; + } + + // "Engl Unit" matches "English/United States" + static bool LanguageMatchesFilter(string Language, string[] Filters) + { + Language = Language.ToLowerInvariant(); + for (int i = 0, imax = Filters.Length; i < imax; ++i) + if (Filters[i] != "") + { + if (!Language.Contains(Filters[i].ToLower())) + return false; + Language = Language.Remove(Language.IndexOf(Filters[i], StringComparison.Ordinal), Filters[i].Length); + } + return true; + } + + + // "Arabic/Algeria [ar-XX]" returns "Arabic (Algeria)" + // "English/English [en]" returns "English" + public static string GetFormatedLanguageName(string Language) + { + string BaseLanguage = string.Empty; + + //-- Remove code -------- + int Index = Language.IndexOf(" [", StringComparison.Ordinal); + if (Index > 0) + Language = Language.Substring(0, Index); + + //-- Check for main language: "English/English [en]" returns "English" ----------- + Index = Language.IndexOf('/'); + if (Index > 0) + { + BaseLanguage = Language.Substring(0, Index); + if (Language == BaseLanguage + "/" + BaseLanguage) + return BaseLanguage; + + //-- Convert variants into right format + Language = Language.Replace("/", " (") + ")"; + } + + return Language; + } + + // English British -> "English Canada [en-CA]" + public static string GetCodedLanguage(string Language, string code) + { + string DefaultCode = GetLanguageCode(Language); + if (string.Compare(code, DefaultCode, StringComparison.OrdinalIgnoreCase) == 0) + return Language; + return string.Concat(Language, " [", code, "]"); + } + + // "English Canada [en-CA]" -> "English Canada", "en-CA" + public static void UnPackCodeFromLanguageName(string CodedLanguage, out string Language, out string code) + { + if (string.IsNullOrEmpty(CodedLanguage)) + { + Language = string.Empty; + code = string.Empty; + return; + } + int Index = CodedLanguage.IndexOf("[", StringComparison.Ordinal); + if (Index < 0) + { + Language = CodedLanguage; + code = GetLanguageCode(Language); + } + else + { + Language = CodedLanguage.Substring(0, Index).Trim(); + code = CodedLanguage.Substring(Index + 1, CodedLanguage.IndexOf("]", Index, StringComparison.Ordinal) - Index - 1); + } + } + + public static string GetGoogleLanguageCode(string InternationalCode) + { + foreach (var kvp in mLanguageDef) + if (InternationalCode == kvp.Value.Code) + { + if (kvp.Value.GoogleCode == "-") + return null; + return !string.IsNullOrEmpty(kvp.Value.GoogleCode) ? kvp.Value.GoogleCode : InternationalCode; + } + + return InternationalCode; + } + + public static string GetLanguageName(string code, bool useParenthesesForRegion=false, bool allowDiscardRegion=true) + { + foreach (var kvp in mLanguageDef) + if (code == kvp.Value.Code) + { + var langName = kvp.Key; + if (useParenthesesForRegion) + { + int idx = langName.IndexOf('/'); + if (idx > 0) + langName = langName.Substring(0, idx) + " (" + langName.Substring(idx + 1) + ")"; + } + return langName; + } + + if (allowDiscardRegion) + { + int iCode = code.IndexOf("-", StringComparison.Ordinal); + if (iCode > 0) + return GetLanguageName(code.Substring(0,iCode), useParenthesesForRegion, false); + } + return null; + } + + public static List GetAllInternationalCodes() + { + var set = new HashSet(StringComparer.Ordinal); + + foreach (var kvp in mLanguageDef) + set.Add(kvp.Value.Code); + + return new List(set); + } + + public static bool LanguageCode_HasJoinedWord(string languageCode) + { + foreach (var kvp in mLanguageDef) + if (languageCode == kvp.Value.GoogleCode || languageCode==kvp.Value.Code ) + return kvp.Value.HasJoinedWords; + + return false; + } + + public struct LanguageCodeDef + { + public string Code; // Language International Code + public string GoogleCode; // Google Translator doesn't support all languages, this is the code of closest supported language + public bool HasJoinedWords; // Some languages (e.g. Chinese, Japanese and Thai) don't add spaces to their words (all characters are placed toguether) + public int PluralRule; + } + + public static Dictionary mLanguageDef = new Dictionary(StringComparer.Ordinal) + { + /**/{"Abkhazian", new LanguageCodeDef {PluralRule=1, Code="ab", GoogleCode="-"}}, + /**/{"Afar", new LanguageCodeDef {PluralRule=1, Code="aa", GoogleCode="-"}}, + {"Afrikaans", new LanguageCodeDef {PluralRule=1, Code="af"}}, + /**/{"Akan", new LanguageCodeDef {PluralRule=1, Code="ak", GoogleCode="-"}}, + {"Albanian", new LanguageCodeDef {PluralRule=1, Code="sq"}}, + /**/{"Amharic", new LanguageCodeDef {PluralRule=1, Code="am"}}, + {"Arabic", new LanguageCodeDef {PluralRule=11, Code="ar"}}, + {"Arabic/Algeria", new LanguageCodeDef {PluralRule=11, Code="ar-DZ", GoogleCode="ar"}}, + {"Arabic/Bahrain", new LanguageCodeDef {PluralRule=11, Code="ar-BH", GoogleCode="ar"}}, + {"Arabic/Egypt", new LanguageCodeDef {PluralRule=11, Code="ar-EG", GoogleCode="ar"}}, + {"Arabic/Iraq", new LanguageCodeDef {PluralRule=11, Code="ar-IQ", GoogleCode="ar"}}, + {"Arabic/Jordan", new LanguageCodeDef {PluralRule=11, Code="ar-JO", GoogleCode="ar"}}, + {"Arabic/Kuwait", new LanguageCodeDef {PluralRule=11, Code="ar-KW", GoogleCode="ar"}}, + {"Arabic/Lebanon", new LanguageCodeDef {PluralRule=11, Code="ar-LB", GoogleCode="ar"}}, + {"Arabic/Libya", new LanguageCodeDef {PluralRule=11, Code="ar-LY", GoogleCode="ar"}}, + {"Arabic/Morocco", new LanguageCodeDef {PluralRule=11, Code="ar-MA", GoogleCode="ar"}}, + {"Arabic/Oman", new LanguageCodeDef {PluralRule=11, Code="ar-OM", GoogleCode="ar"}}, + {"Arabic/Qatar", new LanguageCodeDef {PluralRule=11, Code="ar-QA", GoogleCode="ar"}}, + {"Arabic/Saudi Arabia", new LanguageCodeDef {PluralRule=11, Code="ar-SA", GoogleCode="ar"}}, + {"Arabic/Syria", new LanguageCodeDef {PluralRule=11, Code="ar-SY", GoogleCode="ar"}}, + {"Arabic/Tunisia", new LanguageCodeDef {PluralRule=11, Code="ar-TN", GoogleCode="ar"}}, + {"Arabic/U.A.E.", new LanguageCodeDef {PluralRule=11, Code="ar-AE", GoogleCode="ar"}}, + {"Arabic/Yemen", new LanguageCodeDef {PluralRule=11, Code="ar-YE", GoogleCode="ar"}}, + /**/{"Aragonese", new LanguageCodeDef {PluralRule=1, Code="an", GoogleCode="-"}}, + {"Armenian", new LanguageCodeDef {PluralRule=1, Code="hy"}}, + /**/{"Assamese", new LanguageCodeDef {PluralRule=1, Code="as", GoogleCode="-"}}, + /**/{"Avaric", new LanguageCodeDef {PluralRule=1, Code="av", GoogleCode="-"}}, + /**/{"Avestan", new LanguageCodeDef {PluralRule=1, Code="ae", GoogleCode="-"}}, + /**/{"Aymara", new LanguageCodeDef {PluralRule=1, Code="ay", GoogleCode="-"}}, + {"Azerbaijani", new LanguageCodeDef {PluralRule=1, Code="az"}}, + /**/{"Bambara", new LanguageCodeDef {PluralRule=1, Code="bm", GoogleCode="-"}}, + /**/{"Bashkir", new LanguageCodeDef {PluralRule=1, Code="ba", GoogleCode="-"}}, + {"Basque", new LanguageCodeDef {PluralRule=1, Code="eu"}}, + {"Basque/Spain", new LanguageCodeDef {PluralRule=1, Code="eu-ES", GoogleCode="eu"}}, + {"Belarusian", new LanguageCodeDef {PluralRule=6, Code="be"}}, + /**/{"Bengali", new LanguageCodeDef {PluralRule=1, Code="bn"}}, + /**/{"Bihari", new LanguageCodeDef {PluralRule=1, Code="bh", GoogleCode="-"}}, + /**/{"Bislama", new LanguageCodeDef {PluralRule=1, Code="bi", GoogleCode="-"}}, + {"Bosnian", new LanguageCodeDef {PluralRule=6, Code="bs"}}, + /**/{"Breton", new LanguageCodeDef {PluralRule=1, Code="br", GoogleCode="-"}}, + {"Bulgariaa", new LanguageCodeDef {PluralRule=1, Code="bg"}}, + /**/{"Burmese", new LanguageCodeDef {PluralRule=1, Code="my"}}, + {"Catalan", new LanguageCodeDef {PluralRule=1, Code="ca"}}, + /**/{"Chamorro", new LanguageCodeDef {PluralRule=1, Code="ch", GoogleCode="-"}}, + /**/{"Chechen", new LanguageCodeDef {PluralRule=1, Code="ce", GoogleCode="-"}}, + /**/{"Chichewa", new LanguageCodeDef {PluralRule=1, Code="ny"}}, + {"Chinese", new LanguageCodeDef {PluralRule=0, Code="zh", GoogleCode="zh-CN", HasJoinedWords=true}}, + {"Chinese/Hong Kong", new LanguageCodeDef {PluralRule=0, Code="zh-HK", GoogleCode="zh-TW", HasJoinedWords=true}}, + {"Chinese/Macau", new LanguageCodeDef {PluralRule=0, Code="zh-MO", GoogleCode="zh-CN", HasJoinedWords=true}}, + {"Chinese/PRC", new LanguageCodeDef {PluralRule=0, Code="zh-CN", GoogleCode="zh-CN", HasJoinedWords=true}}, + {"Chinese/Simplified", new LanguageCodeDef {PluralRule=0, Code="zh-CN", GoogleCode="zh-CN", HasJoinedWords=true}}, + {"Chinese/Singapore", new LanguageCodeDef {PluralRule=0, Code="zh-SG", GoogleCode="zh-CN", HasJoinedWords=true}}, + {"Chinese/Taiwan", new LanguageCodeDef {PluralRule=0, Code="zh-TW", GoogleCode="zh-TW", HasJoinedWords=true}}, + {"Chinese/Traditional", new LanguageCodeDef {PluralRule=0, Code="zh-TW", GoogleCode="zh-TW", HasJoinedWords=true}}, + /**/{"Chuvash", new LanguageCodeDef {PluralRule=1, Code="cv", GoogleCode="-"}}, + /**/{"Cornish", new LanguageCodeDef {PluralRule=1, Code="kw", GoogleCode="-"}}, // Check plural + /**/{"Corsican", new LanguageCodeDef {PluralRule=1, Code="co"}}, + /**/{"Cree", new LanguageCodeDef {PluralRule=1, Code="cr", GoogleCode="-"}}, + {"Croatian", new LanguageCodeDef {PluralRule=6, Code="hr"}}, + {"Croatian/Bosnia and Herzegovina", new LanguageCodeDef {PluralRule=5, Code="hr-BA", GoogleCode="hr"}}, + {"Czech", new LanguageCodeDef {PluralRule=7, Code="cs"}}, + {"Danish", new LanguageCodeDef {PluralRule=1, Code="da"}}, + /**/{"Divehi", new LanguageCodeDef {PluralRule=1, Code="dv", GoogleCode="-"}}, + {"Dutch", new LanguageCodeDef {PluralRule=1, Code="nl"}}, + {"Dutch/Belgium", new LanguageCodeDef {PluralRule=1, Code="nl-BE", GoogleCode="nl"}}, + {"Dutch/Netherlands", new LanguageCodeDef {PluralRule=1, Code="nl-NL", GoogleCode="nl"}}, + /**/{"Dzongkha", new LanguageCodeDef {PluralRule=1, Code="dz", GoogleCode="-"}}, + {"English", new LanguageCodeDef {PluralRule=1, Code="en"}}, + {"English/Australia", new LanguageCodeDef {PluralRule=1, Code="en-AU", GoogleCode="en"}}, + {"English/Belize", new LanguageCodeDef {PluralRule=1, Code="en-BZ", GoogleCode="en"}}, + {"English/Canada", new LanguageCodeDef {PluralRule=1, Code="en-CA", GoogleCode="en"}}, + {"English/Caribbean", new LanguageCodeDef {PluralRule=1, Code="en-CB", GoogleCode="en"}}, + {"English/Ireland", new LanguageCodeDef {PluralRule=1, Code="en-IE", GoogleCode="en"}}, + {"English/Jamaica", new LanguageCodeDef {PluralRule=1, Code="en-JM", GoogleCode="en"}}, + {"English/New Zealand", new LanguageCodeDef {PluralRule=1, Code="en-NZ", GoogleCode="en"}}, + {"English/Republic of the Philippines", new LanguageCodeDef {PluralRule=1, Code="en-PH", GoogleCode="en"}}, + {"English/South Africa",new LanguageCodeDef {PluralRule=1, Code="en-ZA", GoogleCode="en"}}, + {"English/Trinidad", new LanguageCodeDef {PluralRule=1, Code="en-TT", GoogleCode="en"}}, + {"English/United Kingdom",new LanguageCodeDef {PluralRule=1, Code="en-GB", GoogleCode="en"}}, + {"English/United States",new LanguageCodeDef {PluralRule=1, Code="en-US", GoogleCode="en"}}, + {"English/Zimbabwe", new LanguageCodeDef {PluralRule=1, Code="en-ZW", GoogleCode="en"}}, + {"Esperanto", new LanguageCodeDef {PluralRule=1, Code="eo"}}, + {"Estonian", new LanguageCodeDef {PluralRule=1, Code="et"}}, + /**/{"Ewe", new LanguageCodeDef {PluralRule=1, Code="ee", GoogleCode="-"}}, + {"Faeroese", new LanguageCodeDef {PluralRule=1, Code="fo", GoogleCode="-"}}, + /**/{"Fijian", new LanguageCodeDef {PluralRule=1, Code="fj", GoogleCode="-"}}, + //{"Filipino", new LanguageCodeDef(){PluralRule=2, Code="tl"}}, + {"Finnish", new LanguageCodeDef {PluralRule=1, Code="fi"}}, + {"French", new LanguageCodeDef {PluralRule=2, Code="fr"}}, + {"French/Belgium", new LanguageCodeDef {PluralRule=2, Code="fr-BE", GoogleCode="fr"}}, + {"French/Canada", new LanguageCodeDef {PluralRule=2, Code="fr-CA", GoogleCode="fr"}}, + {"French/France", new LanguageCodeDef {PluralRule=2, Code="fr-FR", GoogleCode="fr"}}, + {"French/Luxembourg", new LanguageCodeDef {PluralRule=2, Code="fr-LU", GoogleCode="fr"}}, + {"French/Principality of Monaco", new LanguageCodeDef {PluralRule=2, Code="fr-MC", GoogleCode="fr"}}, + {"French/Switzerland", new LanguageCodeDef {PluralRule=2, Code="fr-CH", GoogleCode="fr"}}, + /**/{"Fulah", new LanguageCodeDef {PluralRule=1, Code="ff", GoogleCode="-"}}, + {"Galician", new LanguageCodeDef {PluralRule=1, Code="gl"}}, + {"Galician/Spain", new LanguageCodeDef {PluralRule=1, Code="gl-ES", GoogleCode="gl"}}, + {"Georgian", new LanguageCodeDef {PluralRule=0, Code="ka"}}, + {"German", new LanguageCodeDef {PluralRule=1, Code="de"}}, + {"German/Austria", new LanguageCodeDef {PluralRule=1, Code="de-AT", GoogleCode="de"}}, + {"German/Germany", new LanguageCodeDef {PluralRule=1, Code="de-DE", GoogleCode="de"}}, + {"German/Liechtenstein",new LanguageCodeDef {PluralRule=1, Code="de-LI", GoogleCode="de"}}, + {"German/Luxembourg", new LanguageCodeDef {PluralRule=1, Code="de-LU", GoogleCode="de"}}, + {"German/Switzerland", new LanguageCodeDef {PluralRule=1, Code="de-CH", GoogleCode="de"}}, + {"Greek", new LanguageCodeDef {PluralRule=1, Code="el"}}, + /**/{"Guaraní", new LanguageCodeDef {PluralRule=1, Code="gn", GoogleCode="-"}}, + {"Gujarati", new LanguageCodeDef {PluralRule=1, Code="gu"}}, + /**/{"Haitian", new LanguageCodeDef {PluralRule=1, Code="ht"}}, + /**/{"Hausa", new LanguageCodeDef {PluralRule=1, Code="ha"}}, + {"Hebrew", new LanguageCodeDef {PluralRule=1, Code="he", GoogleCode="iw"}}, + /**/{"Herero", new LanguageCodeDef {PluralRule=1, Code="hz", GoogleCode="-"}}, + {"Hindi", new LanguageCodeDef {PluralRule=1, Code="hi"}}, + /**/{"Hiri Motu", new LanguageCodeDef {PluralRule=1, Code="ho", GoogleCode="-"}}, + {"Hungarian", new LanguageCodeDef {PluralRule=1, Code="hu"}}, + /**/{"Interlingua", new LanguageCodeDef {PluralRule=1, Code="ia", GoogleCode="-"}}, + {"Indonesian", new LanguageCodeDef {PluralRule=0, Code="id"}}, + /**/{"Interlingue", new LanguageCodeDef {PluralRule=1, Code="ie", GoogleCode="-"}}, + {"Irish", new LanguageCodeDef {PluralRule=10, Code="ga"}}, + /**/{"Igbo", new LanguageCodeDef {PluralRule=1, Code="ig"}}, + /**/{"Inupiaq", new LanguageCodeDef {PluralRule=1, Code="ik", GoogleCode="-"}}, + /**/{"Ido", new LanguageCodeDef {PluralRule=1, Code="io", GoogleCode="-"}}, + {"Icelandic", new LanguageCodeDef {PluralRule=14, Code="is"}}, + {"Italian", new LanguageCodeDef {PluralRule=1, Code="it"}}, + {"Italian/Italy", new LanguageCodeDef {PluralRule=1, Code="it-IT", GoogleCode="it"}}, + {"Italian/Switzerland", new LanguageCodeDef {PluralRule=1, Code="it-CH", GoogleCode="it"}}, + /**/{"Inuktitut", new LanguageCodeDef {PluralRule=1, Code="iu", GoogleCode="-"}}, + {"Japanese", new LanguageCodeDef {PluralRule=0, Code="ja", HasJoinedWords=true}}, + /**/{"Javanese", new LanguageCodeDef {PluralRule=1, Code="jv"}}, + /**/{"Kalaallisut", new LanguageCodeDef {PluralRule=1, Code="kl", GoogleCode="-"}}, + {"Kannada", new LanguageCodeDef {PluralRule=1, Code="kn"}}, + /**/{"Kanuri", new LanguageCodeDef {PluralRule=1, Code="kr", GoogleCode="-"}}, + /**/{"Kashmiri", new LanguageCodeDef {PluralRule=1, Code="ks", GoogleCode="-"}}, + {"Kazakh", new LanguageCodeDef {PluralRule=1, Code="kk"}}, + /**/{"Central Khmer", new LanguageCodeDef {PluralRule=1, Code="km"}}, + /**/{"Kikuyu", new LanguageCodeDef {PluralRule=1, Code="ki", GoogleCode="-"}}, + /**/{"Kinyarwanda", new LanguageCodeDef {PluralRule=1, Code="rw", GoogleCode="-"}}, + /**/{"Kirghiz", new LanguageCodeDef {PluralRule=1, Code="ky"}}, + /**/{"Komi", new LanguageCodeDef {PluralRule=1, Code="kv", GoogleCode="-"}}, + /**/{"Kongo", new LanguageCodeDef {PluralRule=1, Code="kg", GoogleCode="-"}}, + {"Korean", new LanguageCodeDef {PluralRule=0, Code="ko"}}, + {"Kurdish", new LanguageCodeDef {PluralRule=1, Code="ku"}}, + /**/{"Kuanyama", new LanguageCodeDef {PluralRule=1, Code="kj", GoogleCode="-"}}, + {"Latin", new LanguageCodeDef {PluralRule=1, Code="la"}}, + /**/{"Luxembourgish", new LanguageCodeDef {PluralRule=1, Code="lb"}}, + /**/{"Ganda", new LanguageCodeDef {PluralRule=1, Code="lg", GoogleCode="-"}}, + /**/{"Limburgan", new LanguageCodeDef {PluralRule=1, Code="li", GoogleCode="-"}}, + /**/{"Lingala", new LanguageCodeDef {PluralRule=1, Code="ln", GoogleCode="-"}}, + /**/{"Lao", new LanguageCodeDef {PluralRule=1, Code="lo"}}, + {"Latvian", new LanguageCodeDef {PluralRule=5, Code="lv"}}, + /**/{"Luba-Katanga", new LanguageCodeDef {PluralRule=1, Code="lu", GoogleCode="-"}}, + {"Lithuanian", new LanguageCodeDef {PluralRule=5, Code="lt"}}, + /**/{"Manx", new LanguageCodeDef {PluralRule=1, Code="gv", GoogleCode="-"}}, + {"Macedonian", new LanguageCodeDef {PluralRule=13, Code="mk"}}, + /**/{"Malagasy", new LanguageCodeDef {PluralRule=1, Code="mg"}}, + {"Malay", new LanguageCodeDef {PluralRule=0, Code="ms"}}, + {"Malay/Brunei Darussalam", new LanguageCodeDef {PluralRule=0, Code="ms-BN", GoogleCode="ms"}}, + {"Malay/Malaysia", new LanguageCodeDef {PluralRule=0, Code="ms-MY", GoogleCode="ms"}}, + {"Malayalam", new LanguageCodeDef {PluralRule=1, Code="ml"}}, + {"Maltese", new LanguageCodeDef {PluralRule=12, Code="mt"}}, + {"Maori", new LanguageCodeDef {PluralRule=2, Code="mi"}}, + {"Marathi", new LanguageCodeDef {PluralRule=1, Code="mr"}}, + /**/{"Marshallese", new LanguageCodeDef {PluralRule=1, Code="mh", GoogleCode="-"}}, + {"Mongolian", new LanguageCodeDef {PluralRule=1, Code="mn"}}, + /**/{"Nauru", new LanguageCodeDef {PluralRule=1, Code="na", GoogleCode="-"}}, + /**/{"Navajo", new LanguageCodeDef {PluralRule=1, Code="nv", GoogleCode="-"}}, + /**/{"North Ndebele", new LanguageCodeDef {PluralRule=1, Code="nd", GoogleCode="-"}}, + /**/{"Nepali", new LanguageCodeDef {PluralRule=1, Code="ne"}}, + /**/{"Ndonga", new LanguageCodeDef {PluralRule=1, Code="ng", GoogleCode="-"}}, + {"Northern Sotho", new LanguageCodeDef {PluralRule=1, Code="ns", GoogleCode="st"}}, + {"Norwegian", new LanguageCodeDef {PluralRule=1, Code="nb", GoogleCode="no"}}, + {"Norwegian/Nynorsk", new LanguageCodeDef {PluralRule=1, Code="nn", GoogleCode="no"}}, + /**/{"Sichuan Yi", new LanguageCodeDef {PluralRule=1, Code="ii", GoogleCode="-"}}, + /**/{"South Ndebele", new LanguageCodeDef {PluralRule=1, Code="nr", GoogleCode="-"}}, + /**/{"Occitan", new LanguageCodeDef {PluralRule=1, Code="oc", GoogleCode="-"}}, + /**/{"Ojibwa", new LanguageCodeDef {PluralRule=1, Code="oj", GoogleCode="-"}}, + /**/{"Church Slavic", new LanguageCodeDef {PluralRule=1, Code="cu", GoogleCode="-"}}, + /**/{"Oromo", new LanguageCodeDef {PluralRule=1, Code="om", GoogleCode="-"}}, + /**/{"Oriya", new LanguageCodeDef {PluralRule=1, Code="or", GoogleCode="-"}}, + /**/{"Ossetian", new LanguageCodeDef {PluralRule=1, Code="os", GoogleCode="-"}}, + /**/{"Pali", new LanguageCodeDef {PluralRule=1, Code="pi", GoogleCode="-"}}, + {"Pashto", new LanguageCodeDef {PluralRule=1, Code="ps"}}, + {"Persian", new LanguageCodeDef {PluralRule=0, Code="fa"}}, + {"Polish", new LanguageCodeDef {PluralRule=8, Code="pl"}}, + {"Portuguese", new LanguageCodeDef {PluralRule=1, Code="pt"}}, + {"Portuguese/Brazil", new LanguageCodeDef {PluralRule=2, Code="pt-BR", GoogleCode="pt"}}, + {"Portuguese/Portugal", new LanguageCodeDef {PluralRule=1, Code="pt-PT", GoogleCode="pt"}}, + {"Punjabi", new LanguageCodeDef {PluralRule=1, Code="pa"}}, + {"Quechua", new LanguageCodeDef {PluralRule=1, Code="qu", GoogleCode="-"}}, + {"Quechua/Bolivia", new LanguageCodeDef {PluralRule=1, Code="qu-BO", GoogleCode="-"}}, + {"Quechua/Ecuador", new LanguageCodeDef {PluralRule=1, Code="qu-EC", GoogleCode="-"}}, + {"Quechua/Peru", new LanguageCodeDef {PluralRule=1, Code="qu-PE", GoogleCode="-"}}, + {"Rhaeto-Romanic", new LanguageCodeDef {PluralRule=1, Code="rm", GoogleCode="ro"}}, + {"Romanian", new LanguageCodeDef {PluralRule=4, Code="ro"}}, + /**/{"Rundi", new LanguageCodeDef {PluralRule=1, Code="rn", GoogleCode="-"}}, + {"Russian", new LanguageCodeDef {PluralRule=6, Code="ru"}}, + {"Russian/Republic of Moldova", new LanguageCodeDef {PluralRule=6, Code="ru-MO", GoogleCode="ru"}}, + /**/{"Sanskrit", new LanguageCodeDef {PluralRule=1, Code="sa", GoogleCode="-"}}, + /**/{"Sardinian", new LanguageCodeDef {PluralRule=1, Code="sc", GoogleCode="-"}}, + /**/{"Sindhi", new LanguageCodeDef {PluralRule=1, Code="sd"}}, + /**/{"Northern Sami", new LanguageCodeDef {PluralRule=1, Code="se", GoogleCode="-"}}, + /**/{"Samoan", new LanguageCodeDef {PluralRule=1, Code="sm"}}, + /**/{"Sango", new LanguageCodeDef {PluralRule=1, Code="sg", GoogleCode="-"}}, + {"Serbian", new LanguageCodeDef {PluralRule=6, Code="sr"}}, + {"Serbian/Bosnia and Herzegovina", new LanguageCodeDef {PluralRule=5, Code="sr-BA", GoogleCode="sr"}}, + {"Serbian/Serbia and Montenegro", new LanguageCodeDef {PluralRule=5, Code="sr-SP", GoogleCode="sr"}}, + /**/{"Scottish Gaelic", new LanguageCodeDef {PluralRule=1, Code="gd"}}, + /**/{"Shona", new LanguageCodeDef {PluralRule=1, Code="sn"}}, + /**/{"Sinhala", new LanguageCodeDef {PluralRule=1, Code="si"}}, + {"Slovak", new LanguageCodeDef {PluralRule=7, Code="sk"}}, + {"Slovenian", new LanguageCodeDef {PluralRule=9, Code="sl"}}, + /**/{"Somali", new LanguageCodeDef {PluralRule=1, Code="so"}}, + /**/{"Southern Sotho", new LanguageCodeDef {PluralRule=1, Code="st"}}, + {"Spanish", new LanguageCodeDef {PluralRule=1, Code="es"}}, + {"Spanish/Argentina", new LanguageCodeDef {PluralRule=1, Code="es-AR", GoogleCode="es"}}, + {"Spanish/Bolivia", new LanguageCodeDef {PluralRule=1, Code="es-BO", GoogleCode="es"}}, + {"Spanish/Castilian", new LanguageCodeDef {PluralRule=1, Code="es-ES", GoogleCode="es"}}, + {"Spanish/Chile", new LanguageCodeDef {PluralRule=1, Code="es-CL", GoogleCode="es"}}, + {"Spanish/Colombia", new LanguageCodeDef {PluralRule=1, Code="es-CO", GoogleCode="es"}}, + {"Spanish/Costa Rica", new LanguageCodeDef {PluralRule=1, Code="es-CR", GoogleCode="es"}}, + {"Spanish/Dominican Republic", new LanguageCodeDef {PluralRule=1, Code="es-DO", GoogleCode="es"}}, + {"Spanish/Ecuador", new LanguageCodeDef {PluralRule=1, Code="es-EC", GoogleCode="es"}}, + {"Spanish/El Salvador", new LanguageCodeDef {PluralRule=1, Code="es-SV", GoogleCode="es"}}, + {"Spanish/Guatemala", new LanguageCodeDef {PluralRule=1, Code="es-GT", GoogleCode="es"}}, + {"Spanish/Honduras", new LanguageCodeDef {PluralRule=1, Code="es-HN", GoogleCode="es"}}, + {"Spanish/Mexico", new LanguageCodeDef {PluralRule=1, Code="es-MX", GoogleCode="es"}}, + {"Spanish/Nicaragua", new LanguageCodeDef {PluralRule=1, Code="es-NI", GoogleCode="es"}}, + {"Spanish/Panama", new LanguageCodeDef {PluralRule=1, Code="es-PA", GoogleCode="es"}}, + {"Spanish/Paraguay", new LanguageCodeDef {PluralRule=1, Code="es-PY", GoogleCode="es"}}, + {"Spanish/Peru", new LanguageCodeDef {PluralRule=1, Code="es-PE", GoogleCode="es"}}, + {"Spanish/Puerto Rico", new LanguageCodeDef {PluralRule=1, Code="es-PR", GoogleCode="es"}}, + {"Spanish/Spain", new LanguageCodeDef {PluralRule=1, Code="es-ES", GoogleCode="es"}}, + {"Spanish/Uruguay", new LanguageCodeDef {PluralRule=1, Code="es-UY", GoogleCode="es"}}, + {"Spanish/Venezuela", new LanguageCodeDef {PluralRule=1, Code="es-VE", GoogleCode="es"}}, + {"Spanish/Latin Americas", new LanguageCodeDef {PluralRule=1, Code="es-US", GoogleCode="es"}}, + /**/{"Sundanese", new LanguageCodeDef {PluralRule=1, Code="su"}}, + {"Swahili", new LanguageCodeDef {Code="sw"}}, + /**/{"Swati", new LanguageCodeDef {PluralRule=1, Code="ss", GoogleCode="-"}}, + {"Swedish", new LanguageCodeDef {PluralRule=1, Code="sv"}}, + {"Swedish/Finland", new LanguageCodeDef {PluralRule=1, Code="sv-FI", GoogleCode="sv"}}, + {"Swedish/Sweden", new LanguageCodeDef {PluralRule=1, Code="sv-SE", GoogleCode="sv"}}, + {"Tamil", new LanguageCodeDef {PluralRule=1, Code="ta"}}, + {"Tatar", new LanguageCodeDef {PluralRule=0, Code="tt", GoogleCode="-"}}, + {"Telugu", new LanguageCodeDef {PluralRule=1, Code="te"}}, + /**/{"Tajik", new LanguageCodeDef {PluralRule=1, Code="tg"}}, + {"Thai", new LanguageCodeDef {PluralRule=0, Code="th", HasJoinedWords=true}}, + /**/{"Tigrinya", new LanguageCodeDef {PluralRule=1, Code="ti", GoogleCode="-"}}, + /**/{"Tibetan", new LanguageCodeDef {PluralRule=1, Code="bo", GoogleCode="-"}}, + /**/{"Turkmen", new LanguageCodeDef {PluralRule=1, Code="tk", GoogleCode="-"}}, + /**/{"Tagalog", new LanguageCodeDef {PluralRule=1, Code="tl"}}, + /**/{"Tswana", new LanguageCodeDef {PluralRule=1, Code="tn", GoogleCode="-"}}, + /**/{"Tonga", new LanguageCodeDef {PluralRule=1, Code="to", GoogleCode="-"}}, + {"Turkish", new LanguageCodeDef {PluralRule=0, Code="tr"}}, + /**/{"Tsonga", new LanguageCodeDef {PluralRule=1, Code="ts", GoogleCode="-"}}, + /**/{"Twi", new LanguageCodeDef {PluralRule=1, Code="tw", GoogleCode="-"}}, + /**/{"Tahitian", new LanguageCodeDef {PluralRule=1, Code="ty", GoogleCode="-"}}, + /**/{"Uighur", new LanguageCodeDef {PluralRule=1, Code="ug", GoogleCode="-"}}, + {"Ukrainian", new LanguageCodeDef {PluralRule=6, Code="uk"}}, + {"Urdu", new LanguageCodeDef {PluralRule=1, Code="ur"}}, + {"Uzbek", new LanguageCodeDef {PluralRule=2, Code="uz"}}, + /**/{"Venda", new LanguageCodeDef {PluralRule=1, Code="ve", GoogleCode="-"}}, + {"Vietnamese", new LanguageCodeDef {PluralRule=1, Code="vi"}}, + /**/{"Volapük", new LanguageCodeDef {PluralRule=1, Code="vo", GoogleCode="-"}}, + /**/{"Walloon", new LanguageCodeDef {PluralRule=1, Code="wa", GoogleCode="-"}}, + {"Welsh", new LanguageCodeDef {PluralRule=16, Code="cy"}}, + /**/{"Wolof", new LanguageCodeDef {PluralRule=1, Code="wo", GoogleCode="-"}}, + /**/{"Frisian", new LanguageCodeDef {PluralRule=1, Code="fy"}}, + {"Xhosa", new LanguageCodeDef {PluralRule=1, Code="xh"}}, + {"Yiddish", new LanguageCodeDef {PluralRule=1, Code="yi"}}, + /**/{"Yoruba", new LanguageCodeDef {PluralRule=1, Code="yo"}}, + /**/{"Zhuang", new LanguageCodeDef {PluralRule=1, Code="za", GoogleCode="-"}}, + {"Zulu", new LanguageCodeDef {PluralRule=1, Code="zu"}} + }; + + static int GetPluralRule( string langCode ) + { + if (langCode.Length > 2) + langCode = langCode.Substring(0, 2); + langCode = langCode.ToLower(); + + foreach (var kvp in mLanguageDef) + if (kvp.Value.Code == langCode) + { + return kvp.Value.PluralRule; + } + return 0; + } + + + //http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html + //http://cldr.unicode.org/cldr-features#TOC-Locale-specific-patterns-for-formatting-and-parsing: + //http://cldr.unicode.org/index/cldr-spec/plural-rules + public static bool LanguageHasPluralType( string langCode, string pluralType ) + { + if (pluralType == "Plural" || pluralType=="Zero" || pluralType=="One") + return true; + + int rule = GetPluralRule (langCode); + + switch (rule) + { + case 3: // Celtic (Scottish Gaelic) + return pluralType=="Two" || pluralType=="Few"; + + case 4: // Families: Romanic (Romanian) + case 5: // Families: Baltic (Latvian, Lithuanian) + case 6: // Families: Slavic (Belarusian, Bosnian, Croatian, Serbian, Russian, Ukrainian) + case 7: // Families: Slavic (Slovak, Czech) + case 8: // Families: Slavic (Polish) + return pluralType=="Few"; + + case 9: // Families: Slavic (Slovenian, Sorbian) + return pluralType=="Two" || pluralType=="Few"; + + case 10: // Families: Celtic (Irish Gaelic) + case 11: // Families: Semitic (Arabic) + case 15: // Families: Celtic (Breton) + case 16: // Families: (Welsh) + return pluralType=="Two" || pluralType=="Few" || pluralType=="Many"; + + case 12: // Families: Semitic (Maltese) + return pluralType=="Few" || pluralType=="Many"; + + case 13: // Families: Slavic (Macedonian) + return pluralType=="Two"; + } + + return false; + } + + // https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_and_Plurals + public static ePluralType GetPluralType( string langCode, int n ) + { + if (n == 0) return ePluralType.Zero; + if (n == 1) return ePluralType.One; + + int rule = GetPluralRule (langCode); + + switch (rule) + { + case 0: // Families: Asian (Chinese, Japanese, Korean), Persian, Turkic/Altaic (Turkish), Thai, Lao + return ePluralType.Plural; + + case 1: // Families: Germanic (Danish, Dutch, English, Faroese, Frisian, German, Norwegian, Swedish), Finno-Ugric (Estonian, Finnish, Hungarian), Language isolate (Basque), Latin/Greek (Greek), Semitic (Hebrew), Romanic (Italian, Portuguese, Spanish, Catalan), Vietnamese + return n==1 ? ePluralType.One : ePluralType.Plural; + + case 2: // Families: Romanic (French, Brazilian Portuguese) + return n<=1 ? ePluralType.One : ePluralType.Plural; + + case 3: // Celtic (Scottish Gaelic) + return n==1 || n==11 ? ePluralType.One : + n==2 || n==12 ? ePluralType.Two : + inRange(n,3,10) || inRange(n,13,19) ? ePluralType.Few : ePluralType.Plural; + + case 4: // Families: Romanic (Romanian) + return n==1 ? ePluralType.One : + inRange(n%100, 1, 19) ? ePluralType.Few : ePluralType.Plural; + + case 5: // Families: Baltic (Latvian, Lithuanian) + return n%10==1 && n%100!=11 ? ePluralType.One : + n%10>=2 && (n%100<10 || n%100>=20) ? ePluralType.Few : ePluralType.Plural; + + case 6: // Families: Slavic (Belarusian, Bosnian, Croatian, Serbian, Russian, Ukrainian) + return n % 10 == 1 && n % 100 != 11 ? ePluralType.One : + inRange (n%10,2,4) && !inRange (n%100,12,14) ? ePluralType.Few : ePluralType.Plural; + + case 7: // Families: Slavic (Slovak, Czech) + return n==1 ? ePluralType.One : + inRange(n,2,4) ? ePluralType.Few : ePluralType.Plural; + + case 8: // Families: Slavic (Polish) + return n==1 ? ePluralType.One : + inRange (n%10,2,4) && !inRange (n%100,12,14) ? ePluralType.Few : ePluralType.Plural; + + case 9: // Families: Slavic (Slovenian, Sorbian) + return n%100==1 ? ePluralType.One : + n%100==2 ? ePluralType.Two : + inRange(n%100,3,4) ? ePluralType.Few : ePluralType.Plural; + + case 10: // Families: Celtic (Irish Gaelic) + return n==1 ? ePluralType.One : + n==2 ? ePluralType.Two : + inRange(n, 3,6) ? ePluralType.Few : + inRange(n, 7,10)? ePluralType.Many : ePluralType.Plural; + + case 11: // Families: Semitic (Arabic) + return n==0 ? ePluralType.Zero : + n==1 ? ePluralType.One : + n==2 ? ePluralType.Two : + inRange(n%100,3,10) ? ePluralType.Few : + n%100>=11 ? ePluralType.Many : ePluralType.Plural; + + case 12: // Families: Semitic (Maltese) + return n==1 ? ePluralType.One : + inRange(n%100, 1, 10) ? ePluralType.Few : + inRange(n%100, 11,19) ? ePluralType.Many : ePluralType.Plural; + + case 13: // Families: Slavic (Macedonian) + return n % 10 == 1 ? ePluralType.One : + n % 10 == 2 ? ePluralType.Two : ePluralType.Plural; + + case 14: // Plural rule #15 (2 forms) + return n%10==1 && n%100!=11 ? ePluralType.One : ePluralType.Plural; + + case 15: // Families: Celtic (Breton) + return n % 10 == 1 && n % 100 != 11 && n % 100 != 71 && n % 100 != 91 ? ePluralType.One : + n % 10 == 2 && n % 100 != 12 && n % 100 != 72 && n % 100 != 92 ? ePluralType.Two : + (n % 10 == 3 || n % 10 == 4 || n % 10 == 9) && n % 100 != 13 && n % 100 != 14 && n % 100 != 19 && n % 100 != 73 && n % 100 != 74 && n % 100 != 79 && n % 100 != 93 && n % 100 != 94 && n % 100 != 99 ? ePluralType.Few : + n%1000000==0 ? ePluralType.Many : ePluralType.Plural; + + case 16: // Families: (Welsh) + return n==0 ? ePluralType.Zero : + n==1 ? ePluralType.One : + n==2 ? ePluralType.Two : + n==3 ? ePluralType.Few : + n==6 ? ePluralType.Many : ePluralType.Plural; + + } + + return ePluralType.Plural; + } + + // A number that belong to the pluralType form + public static int GetPluralTestNumber( string langCode, ePluralType pluralType ) + { + switch (pluralType) + { + case ePluralType.Zero: + return 0; + + case ePluralType.One: + return 1; + + case ePluralType.Few: + return 3; + + case ePluralType.Many: + { + int rule = GetPluralRule (langCode); + if (rule == 10) return 8; + if (rule == 11 || rule==12) return 13; + if (rule == 15) return 1000000; + return 6; + } + + default: + return 936; + } + } + + static bool inRange(int amount, int min, int max) + { + return amount >= min && amount <= max; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleLanguages.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleLanguages.cs.meta new file mode 100644 index 00000000..d4aa9145 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleLanguages.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 26e29b3e77176de4cbb64a3ec85beee6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation.cs new file mode 100644 index 00000000..cf30c1ea --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; + +namespace TEngine.Localization +{ + using TranslationDictionary = Dictionary; + + public static partial class GoogleTranslation + { + public delegate void fnOnTranslated(string Translation, string Error); + + public static bool CanTranslate () + { + return LocalizationManager.Sources.Count > 0 && + !string.IsNullOrEmpty (LocalizationManager.GetWebServiceURL()); + } + + + // LanguageCodeFrom can be "auto" + // After the translation is returned from Google, it will call OnTranslationReady(TranslationResult, ErrorMsg) + // TranslationResult will be null if translation failed + public static void Translate( string text, string LanguageCodeFrom, string LanguageCodeTo, fnOnTranslated OnTranslationReady ) + { + LocalizationManager.InitializeIfNeeded(); + if (!CanTranslate()) + { + OnTranslationReady(null, "WebService is not set correctly or needs to be reinstalled"); + return; + } + //LanguageCodeTo = GoogleLanguages.GetGoogleLanguageCode(LanguageCodeTo); + + if (LanguageCodeTo==LanguageCodeFrom) + { + OnTranslationReady(text, null); + return; + } + + TranslationDictionary queries = new TranslationDictionary(System.StringComparer.Ordinal); + + + // Unsupported language + if (string.IsNullOrEmpty(LanguageCodeTo)) + { + OnTranslationReady(string.Empty, null); + return; + } + CreateQueries(text, LanguageCodeFrom, LanguageCodeTo, queries); // can split plurals and specializations into several queries + + Translate(queries, (results,error)=> + { + if (!string.IsNullOrEmpty(error) || results.Count==0) + { + OnTranslationReady(null, error); + return; + } + + string result = RebuildTranslation( text, queries, LanguageCodeTo); // gets the result from google and rebuilds the text from multiple queries if its is plurals + OnTranslationReady( result, null ); + }); + } + + // Query google for the translation and waits until google returns + // On some Unity versions (e.g. 2017.1f1) unity doesn't handle well waiting for WWW in the main thread, so this call can fail + // In those cases, its advisable to use the Async version (GoogleTranslation.Translate(....)) + public static string ForceTranslate ( string text, string LanguageCodeFrom, string LanguageCodeTo ) + { + TranslationDictionary dict = new TranslationDictionary(System.StringComparer.Ordinal); + AddQuery(text, LanguageCodeFrom, LanguageCodeTo, dict); + + var job = new TranslationJob_Main(dict, null); + while (true) + { + var state = job.GetState(); + if (state == TranslationJob.eJobState.Running) + continue; + + if (state == TranslationJob.eJobState.Failed) + return null; + + //TranslationJob.eJobState.Succeeded + return GetQueryResult( text, "", dict); + } + } + + } +} + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation.cs.meta new file mode 100644 index 00000000..4acd6858 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: cc4d0073f9e452047bd31b01de2bbd82 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Post.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Post.cs new file mode 100644 index 00000000..0d9e958e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Post.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine.Networking; + +namespace TEngine.Localization +{ + using TranslationDictionary = Dictionary; + + + public static partial class GoogleTranslation + { + static List mCurrentTranslations = new List(); + static List mTranslationJobs = new List(); + + public delegate void fnOnTranslationReady(TranslationDictionary dict, string error); + +#region Multiple Translations + + public static void Translate( TranslationDictionary requests, fnOnTranslationReady OnTranslationReady, bool usePOST = true ) + { + //WWW www = GetTranslationWWW( requests, usePOST ); + //I2.Loc.CoroutineManager.Start(WaitForTranslation(www, OnTranslationReady, requests)); + AddTranslationJob( new TranslationJob_Main(requests, OnTranslationReady) ); + } + + public static bool ForceTranslate(TranslationDictionary requests, bool usePOST = true) + { + var job = new TranslationJob_Main(requests, null); + while (true) + { + var state = job.GetState(); + if (state == TranslationJob.eJobState.Running) + continue; + + if (state == TranslationJob.eJobState.Failed) + return false; + + //TranslationJob.eJobState.Succeeded + return true; + } + } + + public static List ConvertTranslationRequest(TranslationDictionary requests, bool encodeGET) + { + List results = new List(); + var sb = new StringBuilder(); + + foreach (var kvp in requests) + { + var request = kvp.Value; + if (sb.Length > 0) + sb.Append(""); + + sb.Append(GoogleLanguages.GetGoogleLanguageCode(request.LanguageCode)); + sb.Append(":"); + for (int i = 0; i < request.TargetLanguagesCode.Length; ++i) + { + if (i != 0) sb.Append(","); + sb.Append(GoogleLanguages.GetGoogleLanguageCode(request.TargetLanguagesCode[i])); + } + sb.Append("="); + + var text = TitleCase(request.Text) == request.Text ? request.Text.ToLowerInvariant() : request.Text; + + if (!encodeGET) + { + sb.Append(text); + } + else + { + sb.Append(Uri.EscapeDataString(text)); + if (sb.Length > 4000) + { + results.Add(sb.ToString()); + sb.Length = 0; + } + } + } + results.Add(sb.ToString()); + return results; + } + + static void AddTranslationJob( TranslationJob job ) + { + mTranslationJobs.Add(job); + if (mTranslationJobs.Count==1) + { + CoroutineManager.Start(WaitForTranslations()); + } + } + + static IEnumerator WaitForTranslations() + { + while (mTranslationJobs.Count > 0) + { + var jobs = mTranslationJobs.ToArray(); + foreach (var job in jobs) + { + if (job.GetState() != TranslationJob.eJobState.Running) + mTranslationJobs.Remove(job); + } + yield return null; + } + } + + + + public static string ParseTranslationResult( string html, TranslationDictionary requests ) + { + //Debug.Log(html); + // Handle google restricting the webservice to run + if (html.StartsWith("") || html.StartsWith("")) + { + if (html.Contains("The script completed but did not return anything")) + return "The current Google WebService is not supported.\nPlease, delete the WebService from the Google Drive and Install the latest version."; + if (html.Contains("Service invoked too many times in a short time")) + return ""; // ignore and try again + return "There was a problem contacting the WebService. Please try again later\n" + html; + } + + string[] texts = html.Split (new[]{""}, StringSplitOptions.None); + string[] splitter = {""}; + int i = 0; + + var Keys = requests.Keys.ToArray(); + foreach (var text in Keys) + { + var temp = FindQueryFromOrigText(text, requests); + var fullText = texts[i++]; + if (temp.Tags != null) + { + //for (int j = 0, jmax = temp.Tags.Length; j < jmax; ++j) + for (int j = temp.Tags.Length-1; j>=0; --j) + { + fullText = fullText.Replace(GetGoogleNoTranslateTag(j), temp.Tags[j]); + //fullText = fullText.Replace( /*"{[" + j + "]}"*/ ((char)(0x2600+j)).ToString(), temp.Tags[j]); + } + } + + temp.Results = fullText.Split (splitter, StringSplitOptions.None); + + // Google has problem translating this "This Is An Example" but not this "this is an example" + if (TitleCase(text)==text) + { + for (int j=0; j0 || mTranslationJobs.Count > 0; + } + + public static void CancelCurrentGoogleTranslations() + { + mCurrentTranslations.Clear (); + foreach (var job in mTranslationJobs) + { + job.Dispose(); + } + mTranslationJobs.Clear(); + } + +#endregion + } +} + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Post.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Post.cs.meta new file mode 100644 index 00000000..61a1aeb2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Post.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 94b94d27ab6931c4abee1e4d3655b660 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Queries.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Queries.cs new file mode 100644 index 00000000..9d3af139 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/GoogleTranslation_Queries.cs @@ -0,0 +1,375 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace TEngine.Localization +{ + using TranslationDictionary = Dictionary; + + public struct TranslationQuery + { + public string OrigText; + public string Text; // Text without Tags + public string LanguageCode; + public string[] TargetLanguagesCode; + public string[] Results; // This is filled google returns the translations + public string[] Tags; // This are the sections of the orignal text that shoudn't be translated + } + + public static partial class GoogleTranslation + { + public static void CreateQueries(string text, string LanguageCodeFrom, string LanguageCodeTo, TranslationDictionary dict) + { + if (!text.Contains("[i2s_")) + { + CreateQueries_Plurals(text, LanguageCodeFrom, LanguageCodeTo, dict); + return; + } + + var variants = SpecializationManager.GetSpecializations(text); + foreach (var kvp in variants) + { + CreateQueries_Plurals(kvp.Value, LanguageCodeFrom, LanguageCodeTo, dict); + } + } + + static void CreateQueries_Plurals(string text, string LanguageCodeFrom, string LanguageCodeTo, TranslationDictionary dict) + { + bool hasPluralParams = text.Contains("{[#"); + bool hasPluralTypes = text.Contains("[i2p_"); + if (!HasParameters(text) || !hasPluralParams && !hasPluralTypes) + { + AddQuery(text, LanguageCodeFrom, LanguageCodeTo, dict); + return; + } + + bool forcePluralParam = hasPluralParams; + + for (var i = (ePluralType)0; i <= ePluralType.Plural; ++i) + { + var pluralType = i.ToString(); + if (!GoogleLanguages.LanguageHasPluralType(LanguageCodeTo, pluralType)) + continue; + + var newText = GetPluralText(text, pluralType); + int testNumber = GoogleLanguages.GetPluralTestNumber(LanguageCodeTo, i); + + var parameter = GetPluralParameter(newText, forcePluralParam); + if (!string.IsNullOrEmpty(parameter)) + newText = newText.Replace(parameter, testNumber.ToString()); + + //Debug.Log("Translate: " + newText); + + AddQuery(newText, LanguageCodeFrom, LanguageCodeTo, dict); + } + } + + public static void AddQuery(string text, string LanguageCodeFrom, string LanguageCodeTo, TranslationDictionary dict) + { + if (string.IsNullOrEmpty(text)) + return; + + + if (!dict.ContainsKey(text)) + { + var query = new TranslationQuery { OrigText = text, LanguageCode = LanguageCodeFrom, TargetLanguagesCode = new[] { LanguageCodeTo } }; + query.Text = text; + ParseNonTranslatableElements(ref query); + dict[text] = query; + } + else + { + var query = dict[text]; + if (Array.IndexOf(query.TargetLanguagesCode, LanguageCodeTo) < 0) + { + query.TargetLanguagesCode = query.TargetLanguagesCode.Concat(new[] { LanguageCodeTo }).Distinct().ToArray(); + } + dict[text] = query; + } + } + + static string GetTranslation(string text, string LanguageCodeTo, TranslationDictionary dict) + { + if (!dict.ContainsKey(text)) + return null; + var query = dict[text]; + + int langIdx = Array.IndexOf(query.TargetLanguagesCode, LanguageCodeTo); + if (langIdx < 0) + return ""; + + if (query.Results == null) + return ""; + return query.Results[langIdx]; + } + + static TranslationQuery FindQueryFromOrigText(string origText, TranslationDictionary dict) + { + foreach (var kvp in dict) + { + if (kvp.Value.OrigText == origText) + return kvp.Value; + } + return default(TranslationQuery); + } + + public static bool HasParameters( string text ) + { + int idx = text.IndexOf("{[", StringComparison.Ordinal); + if (idx < 0) return false; + return text.IndexOf("]}", idx, StringComparison.Ordinal) > 0; + } + + public static string GetPluralParameter(string text, bool forceTag) // force tag requires that the parameter has the form {[#param]} + { + // Try finding the "plural parameter" that has the form {[#name]} + // this allows using the second parameter as plural: "Player {[name1]} has {[#value]} points" + int idx0 = text.IndexOf("{[#", StringComparison.Ordinal); + if (idx0 < 0) + { + if (forceTag) return null; + idx0 = text.IndexOf("{[", StringComparison.Ordinal); // fallback to the first paremeter if no one has the # tag + } + if (idx0 < 0) + return null; + + int idx1 = text.IndexOf("]}", idx0+2, StringComparison.Ordinal); + if (idx1 < 0) + return null; // no closing parameter tag + + return text.Substring(idx0, idx1 - idx0 + 2); + } + + public static string GetPluralText( string text, string pluralType ) + { + pluralType = "[i2p_" + pluralType + "]"; + int idx0 = text.IndexOf(pluralType, StringComparison.Ordinal); + if (idx0>=0) + { + idx0 += pluralType.Length; + int idx1 = text.IndexOf("[i2p_",idx0, StringComparison.Ordinal); + if (idx1 < 0) idx1 = text.Length; + + return text.Substring(idx0, idx1 - idx0); + } + + // PluralType not found, fallback to the first one + idx0 = text.IndexOf("[i2p_", StringComparison.Ordinal); + if (idx0 < 0) + return text; // No plural tags: "my text" + + if (idx0>0) + return text.Substring(0, idx0); // Case: "my text[i2p_zero]hello" + + // Case: "[i2p_plural]my text[i2p_zero]hello" + idx0 = text.IndexOf("]", StringComparison.Ordinal); + if (idx0 < 0) return text; // starts like a plural, but has none + + idx0 += 1; + int idx2 = text.IndexOf("[i2p_", idx0, StringComparison.Ordinal); + if (idx2 < 0) idx2 = text.Length; + return text.Substring(idx0, idx2 - idx0); + } + + static int FindClosingTag(string tag, MatchCollection matches, int startIndex) + { + for (int i = startIndex, imax = matches.Count; i < imax; ++i) + { + var newTag = I2Utils.GetCaptureMatch(matches[i]); + if (newTag[0]=='/' && tag.StartsWith(newTag.Substring(1), StringComparison.Ordinal)) + return i; + } + return -1; + } + + static string GetGoogleNoTranslateTag(int tagNumber) + { + //return " I2NT" + tagNumber; + if (tagNumber < 70) + return "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++".Substring(0, tagNumber+1); + + string s = ""; + for (int i = -1; i < tagNumber; ++i) + s += "+"; + return s; + } + + + static void ParseNonTranslatableElements( ref TranslationQuery query ) + { + //\[i2nt].*\[\/i2nt] + var matches = Regex.Matches( query.Text, @"\{\[(.*?)]}|\[(.*?)]|\<(.*?)>"); + if (matches == null || matches.Count == 0) + return; + + string finalText = query.Text; + List finalTags = new List(); + for (int i=0, imax=matches.Count; i + + if (iClosingTag < 0) + { + // Its not a tag, its a parameter + var fulltag = matches[i].ToString(); + if (fulltag.StartsWith("{[", StringComparison.Ordinal) && fulltag.EndsWith("]}", StringComparison.Ordinal)) + { + finalText = finalText.Replace(fulltag, GetGoogleNoTranslateTag(finalTags.Count)+" "); // 0x2600 is the start of the UNICODE Miscellaneous Symbols table, so they are not going to be translated by google + //finalText = finalText.Replace(fulltag, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString()); // 0x2600 is the start of the UNICODE Miscellaneous Symbols table, so they are not going to be translated by google + finalTags.Add(fulltag); + } + continue; + } + + if (tag == "i2nt") + { + var tag1 = query.Text.Substring(matches[i].Index, matches[iClosingTag].Index-matches[i].Index + matches[iClosingTag].Length); + finalText = finalText.Replace(tag1, GetGoogleNoTranslateTag(finalTags.Count)+" "); + //finalText = finalText.Replace(tag1, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString()); + + finalTags.Add(tag1); + } + else + { + var tag1 = matches[i].ToString(); + finalText = finalText.Replace(tag1, GetGoogleNoTranslateTag(finalTags.Count)+" "); + //finalText = finalText.Replace(tag1, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString()); + finalTags.Add(tag1); + + var tag2 = matches[iClosingTag].ToString(); + finalText = finalText.Replace(tag2, GetGoogleNoTranslateTag(finalTags.Count)+" "); + //finalText = finalText.Replace(tag2, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString()); + finalTags.Add(tag2); + } + } + + query.Text = finalText; + query.Tags = finalTags.ToArray(); + } + + public static string GetQueryResult(string text, string LanguageCodeTo, TranslationDictionary dict) + { + if (!dict.ContainsKey(text)) + return null; + + var query = dict[text]; + if (query.Results == null || query.Results.Length < 0) + return null; + + if (string.IsNullOrEmpty(LanguageCodeTo)) + return query.Results[0]; + + int idx = Array.IndexOf(query.TargetLanguagesCode, LanguageCodeTo); + if (idx < 0) + return null; + + return query.Results[idx]; + } + + public static string RebuildTranslation(string text, TranslationDictionary dict, string LanguageCodeTo) + { + if (!text.Contains("[i2s_")) + { + return RebuildTranslation_Plural(text, dict, LanguageCodeTo); + } + + var variants = SpecializationManager.GetSpecializations(text); + var results = new Dictionary(StringComparer.Ordinal); + + foreach (var kvp in variants) + { + results[kvp.Key] = RebuildTranslation_Plural(kvp.Value, dict, LanguageCodeTo); + } + return SpecializationManager.SetSpecializedText(results); + } + + static string RebuildTranslation_Plural( string text, TranslationDictionary dict, string LanguageCodeTo ) + { + bool hasPluralParams = text.Contains("{[#"); + bool hasPluralTypes = text.Contains("[i2p_"); + if (!HasParameters(text) || !hasPluralParams && !hasPluralTypes) + { + return GetTranslation (text, LanguageCodeTo, dict); + } + + var sb = new StringBuilder(); + + string pluralTranslation = null; + bool forcePluralParam = hasPluralParams; + + + for (var i = ePluralType.Plural; i >= 0; --i) + { + var pluralType = i.ToString(); + if (!GoogleLanguages.LanguageHasPluralType(LanguageCodeTo, pluralType)) + continue; + + var newText = GetPluralText(text, pluralType); + int testNumber = GoogleLanguages.GetPluralTestNumber(LanguageCodeTo, i); + + var parameter = GetPluralParameter(newText, forcePluralParam); + if (!string.IsNullOrEmpty(parameter)) + newText = newText.Replace(parameter, testNumber.ToString()); + + var translation = GetTranslation(newText, LanguageCodeTo, dict); + //Debug.LogFormat("from: {0} -> {1}", newText, translation); + if (!string.IsNullOrEmpty(parameter)) + translation = translation.Replace(testNumber.ToString(), parameter); + + if (i==ePluralType.Plural) + { + pluralTranslation = translation; + } + else + { + if (translation == pluralTranslation) + continue; + sb.AppendFormat("[i2p_{0}]", pluralType); + } + sb.Append(translation); + } + + return sb.ToString (); + } + + + + public static string UppercaseFirst(string s) + { + if (string.IsNullOrEmpty(s)) + { + return string.Empty; + } + char[] a = s.ToLower().ToCharArray(); + a[0] = char.ToUpper(a[0]); + return new string(a); + } + public static string TitleCase(string s) + { + if (string.IsNullOrEmpty(s)) + { + return string.Empty; + } + +#if NETFX_CORE + var sb = new StringBuilder(s); + sb[0] = char.ToUpper(sb[0]); + for (int i = 1, imax=s.Length; i Childs { get { yield break;} } + public IEnumerable DeepChilds + { + get + { + foreach (var C in Childs) + foreach (var D in C.DeepChilds) + yield return D; + } + } + + public override string ToString() + { + return "JSONNode"; + } + public virtual string ToString(string aPrefix) + { + return "JSONNode"; + } + + #endregion common interface + + #region typecasting properties + public virtual int AsInt + { + get + { + int v = 0; + if (int.TryParse(Value,out v)) + return v; + return 0; + } + set + { + Value = value.ToString(); + } + } + public virtual float AsFloat + { + get + { + float v = 0.0f; + if (float.TryParse(Value,out v)) + return v; + return 0.0f; + } + set + { + Value = value.ToString(); + } + } + public virtual double AsDouble + { + get + { + double v = 0.0; + if (double.TryParse(Value,out v)) + return v; + return 0.0; + } + set + { + Value = value.ToString(); + } + } + public virtual bool AsBool + { + get + { + bool v = false; + if (bool.TryParse(Value,out v)) + return v; + return !string.IsNullOrEmpty(Value); + } + set + { + Value = value?"true":"false"; + } + } + public virtual JSONArray AsArray + { + get + { + return this as JSONArray; + } + } + public virtual JSONClass AsObject + { + get + { + return this as JSONClass; + } + } + + + #endregion typecasting properties + + #region operators + public static implicit operator JSONNode(string s) + { + return new JSONData(s); + } + public static implicit operator string(JSONNode d) + { + return d == null?null:d.Value; + } + public static bool operator ==(JSONNode a, object b) + { + if (b == null && a is JSONLazyCreator) + return true; + return ReferenceEquals(a,b); + } + + public static bool operator !=(JSONNode a, object b) + { + return !(a == b); + } + public override bool Equals (object obj) + { + return ReferenceEquals(this, obj); + } + public override int GetHashCode () + { + return base.GetHashCode(); + } + + + #endregion operators + + internal static string Escape(string aText) + { + string result = ""; + foreach(char c in aText) + { + switch(c) + { + case '\\' : result += "\\\\"; break; + case '\"' : result += "\\\""; break; + case '\n' : result += "\\n" ; break; + case '\r' : result += "\\r" ; break; + case '\t' : result += "\\t" ; break; + case '\b' : result += "\\b" ; break; + case '\f' : result += "\\f" ; break; + default : result += c ; break; + } + } + return result; + } + + public static JSONNode Parse(string aJSON) + { + Stack stack = new Stack(); + JSONNode ctx = null; + int i = 0; + string Token = ""; + string TokenName = ""; + bool QuoteMode = false; + while (i < aJSON.Length) + { + switch (aJSON[i]) + { + case '{': + if (QuoteMode) + { + Token += aJSON[i]; + break; + } + stack.Push(new JSONClass()); + if (ctx != null) + { + TokenName = TokenName.Trim(); + if (ctx is JSONArray) + ctx.Add(stack.Peek()); + else if (TokenName != "") + ctx.Add(TokenName,stack.Peek()); + } + TokenName = ""; + Token = ""; + ctx = stack.Peek(); + break; + + case '[': + if (QuoteMode) + { + Token += aJSON[i]; + break; + } + + stack.Push(new JSONArray()); + if (ctx != null) + { + TokenName = TokenName.Trim(); + if (ctx is JSONArray) + ctx.Add(stack.Peek()); + else if (TokenName != "") + ctx.Add(TokenName,stack.Peek()); + } + TokenName = ""; + Token = ""; + ctx = stack.Peek(); + break; + + case '}': + case ']': + if (QuoteMode) + { + Token += aJSON[i]; + break; + } + if (stack.Count == 0) + throw new Exception("JSON Parse: Too many closing brackets"); + + stack.Pop(); + if (Token != "") + { + TokenName = TokenName.Trim(); + if (ctx is JSONArray) + ctx.Add(Token); + else if (TokenName != "") + ctx.Add(TokenName,Token); + } + TokenName = ""; + Token = ""; + if (stack.Count>0) + ctx = stack.Peek(); + break; + + case ':': + if (QuoteMode) + { + Token += aJSON[i]; + break; + } + TokenName = Token; + Token = ""; + break; + + case '"': + QuoteMode ^= true; + break; + + case ',': + if (QuoteMode) + { + Token += aJSON[i]; + break; + } + if (Token != "") + { + if (ctx is JSONArray) + ctx.Add(Token); + else if (TokenName != "") + ctx.Add(TokenName, Token); + } + TokenName = ""; + Token = ""; + break; + + case '\r': + case '\n': + break; + + case ' ': + case '\t': + if (QuoteMode) + Token += aJSON[i]; + break; + + case '\\': + ++i; + if (QuoteMode) + { + char C = aJSON[i]; + switch (C) + { + case 't' : Token += '\t'; break; + case 'r' : Token += '\r'; break; + case 'n' : Token += '\n'; break; + case 'b' : Token += '\b'; break; + case 'f' : Token += '\f'; break; + case 'u': + { + string s = aJSON.Substring(i+1,4); + Token += (char)int.Parse(s, NumberStyles.AllowHexSpecifier); + i += 4; + break; + } + default : Token += C; break; + } + } + break; + + default: + Token += aJSON[i]; + break; + } + ++i; + } + if (QuoteMode) + { + throw new Exception("JSON Parse: Quotation marks seems to be messed up."); + } + return ctx; + } + + public virtual void Serialize(BinaryWriter aWriter) {} + + public void SaveToStream(Stream aData) + { + var W = new BinaryWriter(aData); + Serialize(W); + } + + #if USE_SharpZipLib + public void SaveToCompressedStream(System.IO.Stream aData) + { + using (var gzipOut = new ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream(aData)) + { + gzipOut.IsStreamOwner = false; + SaveToStream(gzipOut); + gzipOut.Close(); + } + } + + public void SaveToCompressedFile(string aFileName) + { + #if USE_FileIO + System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName); + using(var F = System.IO.File.OpenWrite(aFileName)) + { + SaveToCompressedStream(F); + } + #else + throw new Exception("Can't use File IO stuff in webplayer"); + #endif + } + public string SaveToCompressedBase64() + { + using (var stream = new System.IO.MemoryStream()) + { + SaveToCompressedStream(stream); + stream.Position = 0; + return System.Convert.ToBase64String(stream.ToArray()); + } + } + + #else + public void SaveToCompressedStream(Stream aData) + { + throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); + } + public void SaveToCompressedFile(string aFileName) + { + throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); + } + public string SaveToCompressedBase64() + { + throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); + } + #endif + + public void SaveToFile(string aFileName) + { + #if USE_FileIO + Directory.CreateDirectory(new FileInfo(aFileName).Directory.FullName); + using(var F = File.OpenWrite(aFileName)) + { + SaveToStream(F); + } + #else + throw new Exception("Can't use File IO stuff in webplayer"); + #endif + } + public string SaveToBase64() + { + using (var stream = new MemoryStream()) + { + SaveToStream(stream); + stream.Position = 0; + return Convert.ToBase64String(stream.ToArray()); + } + } + public static JSONNode Deserialize(BinaryReader aReader) + { + JSONBinaryTag type = (JSONBinaryTag)aReader.ReadByte(); + switch(type) + { + case JSONBinaryTag.Array: + { + int count = aReader.ReadInt32(); + JSONArray tmp = new JSONArray(); + for(int i = 0; i < count; i++) + tmp.Add(Deserialize(aReader)); + return tmp; + } + case JSONBinaryTag.Class: + { + int count = aReader.ReadInt32(); + JSONClass tmp = new JSONClass(); + for(int i = 0; i < count; i++) + { + string key = aReader.ReadString(); + var val = Deserialize(aReader); + tmp.Add(key, val); + } + return tmp; + } + case JSONBinaryTag.Value: + { + return new JSONData(aReader.ReadString()); + } + case JSONBinaryTag.IntValue: + { + return new JSONData(aReader.ReadInt32()); + } + case JSONBinaryTag.DoubleValue: + { + return new JSONData(aReader.ReadDouble()); + } + case JSONBinaryTag.BoolValue: + { + return new JSONData(aReader.ReadBoolean()); + } + case JSONBinaryTag.FloatValue: + { + return new JSONData(aReader.ReadSingle()); + } + + default: + { + throw new Exception("Error deserializing JSON. Unknown tag: " + type); + } + } + } + + #if USE_SharpZipLib + public static JSONNode LoadFromCompressedStream(System.IO.Stream aData) + { + var zin = new ICSharpCode.SharpZipLib.BZip2.BZip2InputStream(aData); + return LoadFromStream(zin); + } + public static JSONNode LoadFromCompressedFile(string aFileName) + { + #if USE_FileIO + using(var F = System.IO.File.OpenRead(aFileName)) + { + return LoadFromCompressedStream(F); + } + #else + throw new Exception("Can't use File IO stuff in webplayer"); + #endif + } + public static JSONNode LoadFromCompressedBase64(string aBase64) + { + var tmp = System.Convert.FromBase64String(aBase64); + var stream = new System.IO.MemoryStream(tmp); + stream.Position = 0; + return LoadFromCompressedStream(stream); + } + #else + public static JSONNode LoadFromCompressedFile(string aFileName) + { + throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); + } + public static JSONNode LoadFromCompressedStream(Stream aData) + { + throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); + } + public static JSONNode LoadFromCompressedBase64(string aBase64) + { + throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON"); + } + #endif + + public static JSONNode LoadFromStream(Stream aData) + { + using(var R = new BinaryReader(aData)) + { + return Deserialize(R); + } + } + public static JSONNode LoadFromFile(string aFileName) + { + #if USE_FileIO + using(var F = File.OpenRead(aFileName)) + { + return LoadFromStream(F); + } + #else + throw new Exception("Can't use File IO stuff in webplayer"); + #endif + } + public static JSONNode LoadFromBase64(string aBase64) + { + var tmp = Convert.FromBase64String(aBase64); + var stream = new MemoryStream(tmp); + stream.Position = 0; + return LoadFromStream(stream); + } + } // End of JSONNode + + public class JSONArray : JSONNode, IEnumerable + { + private List m_List = new List(); + public override JSONNode this[int aIndex] + { + get + { + if (aIndex<0 || aIndex >= m_List.Count) + return new JSONLazyCreator(this); + return m_List[aIndex]; + } + set + { + if (aIndex<0 || aIndex >= m_List.Count) + m_List.Add(value); + else + m_List[aIndex] = value; + } + } + public override JSONNode this[string aKey] + { + get{ return new JSONLazyCreator(this);} + set{ m_List.Add(value); } + } + public override int Count + { + get { return m_List.Count; } + } + public override void Add(string aKey, JSONNode aItem) + { + m_List.Add(aItem); + } + public override JSONNode Remove(int aIndex) + { + if (aIndex < 0 || aIndex >= m_List.Count) + return null; + JSONNode tmp = m_List[aIndex]; + m_List.RemoveAt(aIndex); + return tmp; + } + public override JSONNode Remove(JSONNode aNode) + { + m_List.Remove(aNode); + return aNode; + } + public override IEnumerable Childs + { + get + { + foreach(JSONNode N in m_List) + yield return N; + } + } + public IEnumerator GetEnumerator() + { + foreach(JSONNode N in m_List) + yield return N; + } + public override string ToString() + { + string result = "[ "; + foreach (JSONNode N in m_List) + { + if (result.Length > 2) + result += ", "; + result += N.ToString(); + } + result += " ]"; + return result; + } + public override string ToString(string aPrefix) + { + string result = "[ "; + foreach (JSONNode N in m_List) + { + if (result.Length > 3) + result += ", "; + result += "\n" + aPrefix + " "; + result += N.ToString(aPrefix+" "); + } + result += "\n" + aPrefix + "]"; + return result; + } + public override void Serialize (BinaryWriter aWriter) + { + aWriter.Write((byte)JSONBinaryTag.Array); + aWriter.Write(m_List.Count); + for(int i = 0; i < m_List.Count; i++) + { + m_List[i].Serialize(aWriter); + } + } + } // End of JSONArray + + public class JSONClass : JSONNode, IEnumerable + { + private Dictionary m_Dict = new Dictionary(StringComparer.Ordinal); + public override JSONNode this[string aKey] + { + get + { + if (m_Dict.ContainsKey(aKey)) + return m_Dict[aKey]; + return new JSONLazyCreator(this, aKey); + } + set + { + if (m_Dict.ContainsKey(aKey)) + m_Dict[aKey] = value; + else + m_Dict.Add(aKey,value); + } + } + public override JSONNode this[int aIndex] + { + get + { + if (aIndex < 0 || aIndex >= m_Dict.Count) + return null; + +#if DISABLE_LINQ_EXT + foreach (var kvp in m_Dict) + { + if (aIndex==0) + return kvp.Value; + aIndex--; + } + return null; +#else + return m_Dict.ElementAt(aIndex).Value; +#endif + } + set + { + if (aIndex < 0 || aIndex >= m_Dict.Count) + return; +#if DISABLE_LINQ_EXT + string[] keys = new string[m_Dict.Keys.Count]; + m_Dict.Keys.CopyTo(keys,0); + string key = keys[aIndex]; +#else + string key = m_Dict.ElementAt(aIndex).Key; +#endif + m_Dict[key] = value; + } + } + public override int Count + { + get { return m_Dict.Count; } + } + + + public override void Add(string aKey, JSONNode aItem) + { + if (!string.IsNullOrEmpty(aKey)) + { + if (m_Dict.ContainsKey(aKey)) + m_Dict[aKey] = aItem; + else + m_Dict.Add(aKey, aItem); + } + else + m_Dict.Add(Guid.NewGuid().ToString(), aItem); + } + + public override JSONNode Remove(string aKey) + { + if (!m_Dict.ContainsKey(aKey)) + return null; + JSONNode tmp = m_Dict[aKey]; + m_Dict.Remove(aKey); + return tmp; + } + public override JSONNode Remove(int aIndex) + { + if (aIndex < 0 || aIndex >= m_Dict.Count) + return null; + +#if DISABLE_LINQ_EXT + string[] keys = new string[m_Dict.Keys.Count]; + m_Dict.Keys.CopyTo(keys,0); + string key = keys[aIndex]; + var value = m_Dict[key]; + m_Dict.Remove(key); + return value; +#else + var item = m_Dict.ElementAt(aIndex); + m_Dict.Remove(item.Key); + return item.Value; +#endif + } + public override JSONNode Remove(JSONNode aNode) + { + try + { +#if DISABLE_LINQ_EXT + foreach (var kvp in m_Dict) + if (kvp.Value == aNode) + { + m_Dict.Remove(kvp.Key); + break; + } + return aNode; +#else + var item = m_Dict.Where(k => k.Value == aNode).First(); + m_Dict.Remove(item.Key); + return aNode; +#endif + } + catch + { + return null; + } + } + + public override IEnumerable Childs + { + get + { + foreach(KeyValuePair N in m_Dict) + yield return N.Value; + } + } + + public IEnumerator GetEnumerator() + { + foreach(KeyValuePair N in m_Dict) + yield return N; + } + public override string ToString() + { + string result = "{"; + foreach (KeyValuePair N in m_Dict) + { + if (result.Length > 2) + result += ", "; + result += "\"" + Escape(N.Key) + "\":" + N.Value; + } + result += "}"; + return result; + } + public override string ToString(string aPrefix) + { + string result = "{ "; + foreach (KeyValuePair N in m_Dict) + { + if (result.Length > 3) + result += ", "; + result += "\n" + aPrefix + " "; + result += "\"" + Escape(N.Key) + "\" : " + N.Value.ToString(aPrefix+" "); + } + result += "\n" + aPrefix + "}"; + return result; + } + public override void Serialize (BinaryWriter aWriter) + { + aWriter.Write((byte)JSONBinaryTag.Class); + aWriter.Write(m_Dict.Count); + foreach(string K in m_Dict.Keys) + { + aWriter.Write(K); + m_Dict[K].Serialize(aWriter); + } + } + } // End of JSONClass + + public class JSONData : JSONNode + { + private string m_Data; + public override string Value + { + get { return m_Data; } + set { m_Data = value; } + } + public JSONData(string aData) + { + m_Data = aData; + } + public JSONData(float aData) + { + AsFloat = aData; + } + public JSONData(double aData) + { + AsDouble = aData; + } + public JSONData(bool aData) + { + AsBool = aData; + } + public JSONData(int aData) + { + AsInt = aData; + } + + public override string ToString() + { + return "\"" + Escape(m_Data) + "\""; + } + public override string ToString(string aPrefix) + { + return "\"" + Escape(m_Data) + "\""; + } + public override void Serialize (BinaryWriter aWriter) + { + var tmp = new JSONData(""); + + tmp.AsInt = AsInt; + if (tmp.m_Data == m_Data) + { + aWriter.Write((byte)JSONBinaryTag.IntValue); + aWriter.Write(AsInt); + return; + } + tmp.AsFloat = AsFloat; + if (tmp.m_Data == m_Data) + { + aWriter.Write((byte)JSONBinaryTag.FloatValue); + aWriter.Write(AsFloat); + return; + } + tmp.AsDouble = AsDouble; + if (tmp.m_Data == m_Data) + { + aWriter.Write((byte)JSONBinaryTag.DoubleValue); + aWriter.Write(AsDouble); + return; + } + + tmp.AsBool = AsBool; + if (tmp.m_Data == m_Data) + { + aWriter.Write((byte)JSONBinaryTag.BoolValue); + aWriter.Write(AsBool); + return; + } + aWriter.Write((byte)JSONBinaryTag.Value); + aWriter.Write(m_Data); + } + } // End of JSONData + + internal class JSONLazyCreator : JSONNode + { + private JSONNode m_Node; + private string m_Key; + + public JSONLazyCreator(JSONNode aNode) + { + m_Node = aNode; + m_Key = null; + } + public JSONLazyCreator(JSONNode aNode, string aKey) + { + m_Node = aNode; + m_Key = aKey; + } + + private void Set(JSONNode aVal) + { + if (m_Key == null) + { + m_Node.Add(aVal); + } + else + { + m_Node.Add(m_Key, aVal); + } + m_Node = null; // Be GC friendly. + } + + public override JSONNode this[int aIndex] + { + get + { + return new JSONLazyCreator(this); + } + set + { + var tmp = new JSONArray(); + tmp.Add(value); + Set(tmp); + } + } + + public override JSONNode this[string aKey] + { + get + { + return new JSONLazyCreator(this, aKey); + } + set + { + var tmp = new JSONClass(); + tmp.Add(aKey, value); + Set(tmp); + } + } + public override void Add (JSONNode aItem) + { + var tmp = new JSONArray(); + tmp.Add(aItem); + Set(tmp); + } + public override void Add (string aKey, JSONNode aItem) + { + var tmp = new JSONClass(); + tmp.Add(aKey, aItem); + Set(tmp); + } + public static bool operator ==(JSONLazyCreator a, object b) + { + if (b == null) + return true; + return ReferenceEquals(a,b); + } + + public static bool operator !=(JSONLazyCreator a, object b) + { + return !(a == b); + } + public override bool Equals (object obj) + { + if (obj == null) + return true; + return ReferenceEquals(this, obj); + } + public override int GetHashCode () + { + return base.GetHashCode(); + } + + public override string ToString() + { + return ""; + } + public override string ToString(string aPrefix) + { + return ""; + } + + public override int AsInt + { + get + { + JSONData tmp = new JSONData(0); + Set(tmp); + return 0; + } + set + { + JSONData tmp = new JSONData(value); + Set(tmp); + } + } + public override float AsFloat + { + get + { + JSONData tmp = new JSONData(0.0f); + Set(tmp); + return 0.0f; + } + set + { + JSONData tmp = new JSONData(value); + Set(tmp); + } + } + public override double AsDouble + { + get + { + JSONData tmp = new JSONData(0.0); + Set(tmp); + return 0.0; + } + set + { + JSONData tmp = new JSONData(value); + Set(tmp); + } + } + public override bool AsBool + { + get + { + JSONData tmp = new JSONData(false); + Set(tmp); + return false; + } + set + { + JSONData tmp = new JSONData(value); + Set(tmp); + } + } + public override JSONArray AsArray + { + get + { + JSONArray tmp = new JSONArray(); + Set(tmp); + return tmp; + } + } + public override JSONClass AsObject + { + get + { + JSONClass tmp = new JSONClass(); + Set(tmp); + return tmp; + } + } + } // End of JSONLazyCreator + + public static class JSON + { + public static JSONNode Parse(string aJSON) + { + return JSONNode.Parse(aJSON); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/SimpleJSON.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/SimpleJSON.cs.meta new file mode 100644 index 00000000..a86ec175 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/SimpleJSON.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c6bd173cd8524b04daa3dabce666b456 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob.cs new file mode 100644 index 00000000..786e0e2f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using UnityEngine.Networking; + +namespace TEngine.Localization +{ + using TranslationDictionary = Dictionary; + + + public class TranslationJob : IDisposable + { + public eJobState mJobState = eJobState.Running; + + public enum eJobState { Running, Succeeded, Failed } + + public virtual eJobState GetState() { return mJobState; } + + public virtual void Dispose() { } + + } + + public class TranslationJob_WWW : TranslationJob + { + public UnityWebRequest www; + + public override void Dispose() + { + if (www!=null) + www.Dispose(); + www = null; + } + + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob.cs.meta new file mode 100644 index 00000000..3dd1594d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 7dae211a5bb44db46a568fb70fca3296 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_GET.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_GET.cs new file mode 100644 index 00000000..db294862 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_GET.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Text; +using UnityEngine.Networking; + +namespace TEngine.Localization +{ + using TranslationDictionary = Dictionary; + + public class TranslationJob_GET : TranslationJob_WWW + { + TranslationDictionary _requests; + GoogleTranslation.fnOnTranslationReady _OnTranslationReady; + List mQueries; + public string mErrorMessage; + + public TranslationJob_GET(TranslationDictionary requests, GoogleTranslation.fnOnTranslationReady OnTranslationReady) + { + _requests = requests; + _OnTranslationReady = OnTranslationReady; + + mQueries = GoogleTranslation.ConvertTranslationRequest(requests, true); + + GetState(); + } + + void ExecuteNextQuery() + { + if (mQueries.Count == 0) + { + mJobState = eJobState.Succeeded; + return; + } + + int lastQuery = mQueries.Count - 1; + var query = mQueries[lastQuery]; + mQueries.RemoveAt(lastQuery); + + string url = $"{LocalizationManager.GetWebServiceURL()}?action=Translate&list={query}"; + www = UnityWebRequest.Get(url); + I2Utils.SendWebRequest(www); + } + + public override eJobState GetState() + { + if (www != null && www.isDone) + { + ProcessResult(www.downloadHandler.data, www.error); + www.Dispose(); + www = null; + } + + if (www==null) + { + ExecuteNextQuery(); + } + + return mJobState; + } + + public void ProcessResult(byte[] bytes, string errorMsg) + { + if (string.IsNullOrEmpty(errorMsg)) + { + var wwwText = Encoding.UTF8.GetString(bytes, 0, bytes.Length); //www.text + errorMsg = GoogleTranslation.ParseTranslationResult(wwwText, _requests); + + if (string.IsNullOrEmpty(errorMsg)) + { + if (_OnTranslationReady!=null) + _OnTranslationReady(_requests, null); + return; + } + } + + mJobState = eJobState.Failed; + mErrorMessage = errorMsg; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_GET.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_GET.cs.meta new file mode 100644 index 00000000..7835a839 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_GET.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 13df42f7287eccc4399bc757d577030e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_Main.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_Main.cs new file mode 100644 index 00000000..9f4d6f96 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_Main.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; + +namespace TEngine.Localization +{ + using TranslationDictionary = Dictionary; + + public class TranslationJob_Main : TranslationJob + { + TranslationJob_WEB mWeb; + TranslationJob_POST mPost; + TranslationJob_GET mGet; + + TranslationDictionary _requests; + GoogleTranslation.fnOnTranslationReady _OnTranslationReady; + public string mErrorMessage; + + public TranslationJob_Main(TranslationDictionary requests, GoogleTranslation.fnOnTranslationReady OnTranslationReady) + { + _requests = requests; + _OnTranslationReady = OnTranslationReady; + + //mWeb = new TranslationJob_WEB(requests, OnTranslationReady); + mPost = new TranslationJob_POST(requests, OnTranslationReady); + } + + public override eJobState GetState() + { + if (mWeb != null) + { + var state = mWeb.GetState(); + switch (state) + { + case eJobState.Running: return eJobState.Running; + case eJobState.Succeeded: + { + mJobState = eJobState.Succeeded; + break; + } + case eJobState.Failed: + { + mWeb.Dispose(); + mWeb = null; + mPost = new TranslationJob_POST(_requests, _OnTranslationReady); + break; + } + } + } + if (mPost != null) + { + var state = mPost.GetState(); + switch (state) + { + case eJobState.Running: return eJobState.Running; + case eJobState.Succeeded: + { + mJobState = eJobState.Succeeded; + break; + } + case eJobState.Failed: + { + mPost.Dispose(); + mPost = null; + mGet = new TranslationJob_GET(_requests, _OnTranslationReady); + break; + } + } + } + if (mGet != null) + { + var state = mGet.GetState(); + switch (state) + { + case eJobState.Running: return eJobState.Running; + case eJobState.Succeeded: + { + mJobState = eJobState.Succeeded; + break; + } + case eJobState.Failed: + { + mErrorMessage = mGet.mErrorMessage; + if (_OnTranslationReady != null) + _OnTranslationReady(_requests, mErrorMessage); + mGet.Dispose(); + mGet = null; + break; + } + } + } + + return mJobState; + } + + public override void Dispose() + { + if (mPost != null) mPost.Dispose(); + if (mGet != null) mGet.Dispose(); + mPost = null; + mGet = null; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_Main.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_Main.cs.meta new file mode 100644 index 00000000..43390b4a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_Main.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b6aed7ae05f9c254596b3728c5811bdb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_POST.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_POST.cs new file mode 100644 index 00000000..4f111681 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_POST.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Text; +using UnityEngine; +using UnityEngine.Networking; + +namespace TEngine.Localization +{ + using TranslationDictionary = Dictionary; + + public class TranslationJob_POST : TranslationJob_WWW + { + TranslationDictionary _requests; + GoogleTranslation.fnOnTranslationReady _OnTranslationReady; + + public TranslationJob_POST(TranslationDictionary requests, GoogleTranslation.fnOnTranslationReady OnTranslationReady) + { + _requests = requests; + _OnTranslationReady = OnTranslationReady; + + var data = GoogleTranslation.ConvertTranslationRequest(requests, false); + + WWWForm form = new WWWForm(); + form.AddField("action", "Translate"); + form.AddField("list", data[0]); + + www = UnityWebRequest.Post(LocalizationManager.GetWebServiceURL(), form); + I2Utils.SendWebRequest(www); + } + + public override eJobState GetState() + { + if (www != null && www.isDone) + { + ProcessResult(www.downloadHandler.data, www.error); + www.Dispose(); + www = null; + } + + return mJobState; + } + + public void ProcessResult(byte[] bytes, string errorMsg) + { + if (!string.IsNullOrEmpty(errorMsg)) + { + // check for + //if (errorMsg.Contains("rewind")) // "necessary data rewind wasn't possible" + mJobState = eJobState.Failed; + } + else + { + var wwwText = Encoding.UTF8.GetString(bytes, 0, bytes.Length); //www.text + errorMsg = GoogleTranslation.ParseTranslationResult(wwwText, _requests); + if (_OnTranslationReady!=null) + _OnTranslationReady(_requests, errorMsg); + mJobState = eJobState.Succeeded; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_POST.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_POST.cs.meta new file mode 100644 index 00000000..abc2d46f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_POST.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3450e33294f339348ae4e52731974230 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_WEB.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_WEB.cs new file mode 100644 index 00000000..93f1448c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_WEB.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; +using UnityEngine; +using UnityEngine.Networking; + +namespace TEngine.Localization +{ + using TranslationDictionary = Dictionary; + + public class TranslationJob_WEB : TranslationJob_WWW + { + TranslationDictionary _requests; + GoogleTranslation.fnOnTranslationReady _OnTranslationReady; + public string mErrorMessage; + + string mCurrentBatch_ToLanguageCode; + string mCurrentBatch_FromLanguageCode; + List mCurrentBatch_Text; + + List> mQueries; + + public TranslationJob_WEB(TranslationDictionary requests, GoogleTranslation.fnOnTranslationReady OnTranslationReady) + { + _requests = requests; + _OnTranslationReady = OnTranslationReady; + + FindAllQueries(); + ExecuteNextBatch(); + } + + void FindAllQueries() + { + mQueries = new List>(); + foreach (var kvp in _requests) + { + foreach (var langCode in kvp.Value.TargetLanguagesCode) + { + mQueries.Add(new KeyValuePair(kvp.Value.OrigText, kvp.Value.LanguageCode+":"+langCode)); + } + } + + mQueries.Sort((a, b) => a.Value.CompareTo(b.Value)); + } + + void ExecuteNextBatch() + { + if (mQueries.Count==0) + { + mJobState = eJobState.Succeeded; + return; + } + mCurrentBatch_Text = new List(); + + string lastLangCode = null; + int maxLength = 200; + + var sb = new StringBuilder(); + int i; + for (i=0; i maxLength) + break; + } + mQueries.RemoveRange(0, i); + + var fromtoLang = lastLangCode.Split(':'); + mCurrentBatch_FromLanguageCode = fromtoLang[0]; + mCurrentBatch_ToLanguageCode = fromtoLang[1]; + + string url = string.Format ("http://www.google.com/translate_t?hl=en&vi=c&ie=UTF8&oe=UTF8&submit=Translate&langpair={0}|{1}&text={2}", mCurrentBatch_FromLanguageCode, mCurrentBatch_ToLanguageCode, Uri.EscapeUriString( sb.ToString() )); + Debug.Log(url); + + www = UnityWebRequest.Get(url); + I2Utils.SendWebRequest(www); + } + + public override eJobState GetState() + { + if (www != null && www.isDone) + { + ProcessResult(www.downloadHandler.data, www.error); + www.Dispose(); + www = null; + } + + if (www == null) + { + ExecuteNextBatch(); + } + + return mJobState; + } + + public void ProcessResult(byte[] bytes, string errorMsg) + { + if (string.IsNullOrEmpty(errorMsg)) + { + var wwwText = Encoding.UTF8.GetString(bytes, 0, bytes.Length); //www.text + var result = ParseTranslationResult(wwwText, "aab"); + //errorMsg = GoogleTranslation.ParseTranslationResult(wwwText, _requests); + Debug.Log(result); + + if (string.IsNullOrEmpty(errorMsg)) + { + if (_OnTranslationReady != null) + _OnTranslationReady(_requests, null); + return; + } + } + + mJobState = eJobState.Failed; + mErrorMessage = errorMsg; + } + + string ParseTranslationResult( string html, string OriginalText ) + { + try + { + // This is a Hack for reading Google Translation while Google doens't change their response format + int iStart = html.IndexOf("TRANSLATED_TEXT='", StringComparison.Ordinal) + "TRANSLATED_TEXT='".Length; + int iEnd = html.IndexOf("';var", iStart, StringComparison.Ordinal); + + string Translation = html.Substring( iStart, iEnd-iStart); + + // Convert to normalized HTML + Translation = Regex.Replace(Translation, @"\\x([a-fA-F0-9]{2})", + match => char.ConvertFromUtf32(int.Parse(match.Groups[1].Value, NumberStyles.HexNumber))); + + // Convert ASCII Characters + Translation = Regex.Replace(Translation, @"&#(\d+);", + match => char.ConvertFromUtf32(int.Parse(match.Groups[1].Value))); + + Translation = Translation.Replace("
", "\n"); + + if (OriginalText.ToUpper()==OriginalText) + Translation = Translation.ToUpper(); + else + if (GoogleTranslation.UppercaseFirst(OriginalText)==OriginalText) + Translation = GoogleTranslation.UppercaseFirst(Translation); + else + if (GoogleTranslation.TitleCase(OriginalText)==OriginalText) + Translation = GoogleTranslation.TitleCase(Translation); + + return Translation; + } + catch (Exception ex) + { + Debug.LogError(ex.Message); + return string.Empty; + } + } + } + + } \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_WEB.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_WEB.cs.meta new file mode 100644 index 00000000..408e6adb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Google/TranslationJob_WEB.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3b72399bd2ff39042b1320bb943e0a20 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageData.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageData.cs new file mode 100644 index 00000000..ae62a361 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageData.cs @@ -0,0 +1,43 @@ +using System; + +namespace TEngine.Localization +{ + public enum eLanguageDataFlags + { + DISABLED = 1, + KEEP_LOADED = 2, + NOT_LOADED = 4 + } + [Serializable] + public class LanguageData + { + public string Name; + public string Code; + public byte Flags; // eLanguageDataFlags + + [NonSerialized] + public bool Compressed = false; // This will be used in the next version for only loading used Languages + + public bool IsEnabled () { return (Flags & (int)eLanguageDataFlags.DISABLED) == 0; } + + public void SetEnabled( bool bEnabled ) + { + if (bEnabled) Flags = (byte)(Flags & ~(int)eLanguageDataFlags.DISABLED); + else Flags = (byte)(Flags | (int)eLanguageDataFlags.DISABLED); + } + + public bool IsLoaded () { return (Flags & (int)eLanguageDataFlags.NOT_LOADED) == 0; } + public bool CanBeUnloaded () { return (Flags & (int)eLanguageDataFlags.KEEP_LOADED) == 0; } + + public void SetLoaded ( bool loaded ) + { + if (loaded) Flags = (byte)(Flags & ~(int)eLanguageDataFlags.NOT_LOADED); + else Flags = (byte)(Flags | (int)eLanguageDataFlags.NOT_LOADED); + } + public void SetCanBeUnLoaded(bool allowUnloading) + { + if (allowUnloading) Flags = (byte)(Flags & ~(int)eLanguageDataFlags.KEEP_LOADED); + else Flags = (byte)(Flags | (int)eLanguageDataFlags.KEEP_LOADED); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageData.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageData.cs.meta new file mode 100644 index 00000000..6ce04567 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageData.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: cde54ba5e482bec4c88b52e618b81cc9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource.meta new file mode 100644 index 00000000..f6447daf --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 75c7654f6d20207418b4cbce1b29906d +folderAsset: yes +timeCreated: 1518833279 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSource.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSource.cs new file mode 100644 index 00000000..f478c481 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSource.cs @@ -0,0 +1,179 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + [AddComponentMenu("I2/Localization/Source")] + [ExecuteInEditMode] + public class LanguageSource : MonoBehaviour, ISerializationCallbackReceiver, ILanguageSource + { + public LanguageSourceData SourceData + { + get { return mSource; } + set { mSource = value; } + } + public LanguageSourceData mSource = new LanguageSourceData(); + + // Because of Unity2018.3 change in Prefabs, now all the source variables are moved into LanguageSourceData + // But to avoid loosing previously serialized data, these vars are copied into mSource.XXXX when deserializing) + // These are going to be removed once everyone port their projects to the new I2L version. + #region Legacy Variables + + // TODO: also copy public string name; and owner + + public int version; + public bool NeverDestroy; // Keep between scenes (will call DontDestroyOnLoad ) + + public bool UserAgreesToHaveItOnTheScene; + public bool UserAgreesToHaveItInsideThePluginsFolder; + public bool GoogleLiveSyncIsUptoDate = true; + + public List Assets = new List(); // References to Fonts, Atlasses and other objects the localization may need + + public string Google_WebServiceURL; + public string Google_SpreadsheetKey; + public string Google_SpreadsheetName; + public string Google_LastUpdatedVersion; + + + public LanguageSourceData.eGoogleUpdateFrequency GoogleUpdateFrequency = LanguageSourceData.eGoogleUpdateFrequency.Weekly; + + public float GoogleUpdateDelay = 5; // How many second to delay downloading data from google (to avoid lag on the startup) + + public delegate void fnOnSourceUpdated(LanguageSourceData source, bool ReceivedNewData, string errorMsg); + public event fnOnSourceUpdated Event_OnSourceUpdateFromGoogle; + + public List mLanguages = new List(); + + public bool IgnoreDeviceLanguage; // If false, it will use the Device's language as the initial Language, otherwise it will use the first language in the source. + + public LanguageSourceData.eAllowUnloadLanguages _AllowUnloadingLanguages = LanguageSourceData.eAllowUnloadLanguages.Never; + + public List mTerms = new List(); + + public bool CaseInsensitiveTerms; + + public LanguageSourceData.MissingTranslationAction OnMissingTranslation = LanguageSourceData.MissingTranslationAction.Fallback; + + public string mTerm_AppName; + + #endregion + + #region EditorVariables + #if UNITY_EDITOR + + public string Spreadsheet_LocalFileName; + public string Spreadsheet_LocalCSVSeparator = ","; + public string Spreadsheet_LocalCSVEncoding = "utf-8"; + public bool Spreadsheet_SpecializationAsRows = true; + public bool Spreadsheet_SortRows = true; + + public string Google_Password = "change_this"; + public LanguageSourceData.eGoogleUpdateFrequency GoogleInEditorCheckFrequency = LanguageSourceData.eGoogleUpdateFrequency.Daily; +#endif + #endregion + + void Awake() + { + #if UNITY_EDITOR + if (BuildPipeline.isBuildingPlayer) + return; + #endif + // NeverDestroy = false; + + // if (NeverDestroy) + //{ + // if (mSource.ManagerHasASimilarSource()) + // { + // Object.Destroy (this); + // return; + // } + // else + // { + // if (Application.isPlaying) + // DontDestroyOnLoad (gameObject); + // } + //} + mSource.owner = this; + mSource.Awake(); + } + + private void OnDestroy() + { + NeverDestroy = false; + + if (!NeverDestroy) + { + mSource.OnDestroy(); + } + } + + public string GetSourceName() + { + string s = gameObject.name; + Transform tr = transform.parent; + while (tr) + { + s = string.Concat(tr.name, "_", s); + tr = tr.parent; + } + return s; + } + + public void OnBeforeSerialize() + { + version = 1; + } + + public void OnAfterDeserialize() + { + if (version==0 || mSource==null) + { + mSource = new LanguageSourceData(); + mSource.owner = this; + mSource.UserAgreesToHaveItOnTheScene = UserAgreesToHaveItOnTheScene; + mSource.UserAgreesToHaveItInsideThePluginsFolder = UserAgreesToHaveItInsideThePluginsFolder; + mSource.IgnoreDeviceLanguage = IgnoreDeviceLanguage; + mSource._AllowUnloadingLanguages = _AllowUnloadingLanguages; + mSource.CaseInsensitiveTerms = CaseInsensitiveTerms; + mSource.OnMissingTranslation = OnMissingTranslation; + mSource.mTerm_AppName = mTerm_AppName; + + mSource.GoogleLiveSyncIsUptoDate = GoogleLiveSyncIsUptoDate; + mSource.Google_WebServiceURL = Google_WebServiceURL; + mSource.Google_SpreadsheetKey = Google_SpreadsheetKey; + mSource.Google_SpreadsheetName = Google_SpreadsheetName; + mSource.Google_LastUpdatedVersion = Google_LastUpdatedVersion; + mSource.GoogleUpdateFrequency = GoogleUpdateFrequency; + mSource.GoogleUpdateDelay = GoogleUpdateDelay; + + mSource.Event_OnSourceUpdateFromGoogle += Event_OnSourceUpdateFromGoogle; + + if (mLanguages != null && mLanguages.Count>0) + { + mSource.mLanguages.Clear(); + mSource.mLanguages.AddRange(mLanguages); + mLanguages.Clear(); + } + if (Assets != null && Assets.Count > 0) + { + mSource.Assets.Clear(); + mSource.Assets.AddRange(Assets); + Assets.Clear(); + } + if (mTerms != null && mTerms.Count>0) + { + mSource.mTerms.Clear(); + for (int i=0; i mTerms = new List(); + + public bool CaseInsensitiveTerms; + + //This is used to overcome the issue with Unity not serializing Dictionaries + [NonSerialized] public Dictionary mDictionary = new Dictionary(StringComparer.Ordinal); + + public enum MissingTranslationAction { Empty, Fallback, ShowWarning, ShowTerm } + public MissingTranslationAction OnMissingTranslation = MissingTranslationAction.Fallback; + + public string mTerm_AppName; + + #endregion + + #region Variables : Languages + + public List mLanguages = new List(); + + public bool IgnoreDeviceLanguage; // If false, it will use the Device's language as the initial Language, otherwise it will use the first language in the source. + + public enum eAllowUnloadLanguages { Never, OnlyInDevice, EditorAndDevice } + public eAllowUnloadLanguages _AllowUnloadingLanguages = eAllowUnloadLanguages.Never; + + #endregion + + #region Variables : Google + + public string Google_WebServiceURL; + public string Google_SpreadsheetKey; + public string Google_SpreadsheetName; + public string Google_LastUpdatedVersion; + +#if UNITY_EDITOR + public string Google_Password = "change_this"; +#endif + + public enum eGoogleUpdateFrequency { Always, Never, Daily, Weekly, Monthly, OnlyOnce, EveryOtherDay } + public eGoogleUpdateFrequency GoogleUpdateFrequency = eGoogleUpdateFrequency.Weekly; + public eGoogleUpdateFrequency GoogleInEditorCheckFrequency = eGoogleUpdateFrequency.Daily; + + // When Manual, the user has to call LocalizationManager.ApplyDownloadedDataFromGoogle() during a loading screen or similar + public enum eGoogleUpdateSynchronization { Manual, OnSceneLoaded, AsSoonAsDownloaded } + public eGoogleUpdateSynchronization GoogleUpdateSynchronization = eGoogleUpdateSynchronization.OnSceneLoaded; + + public float GoogleUpdateDelay; // How many second to delay downloading data from google (to avoid lag on the startup) + + public event LanguageSource.fnOnSourceUpdated Event_OnSourceUpdateFromGoogle; // (LanguageSource, bool ReceivedNewData, string errorMsg) + + #endregion + + #region Variables : Assets + + public List Assets = new List(); // References to Fonts, Atlasses and other objects the localization may need + + //This is used to overcome the issue with Unity not serializing Dictionaries + [NonSerialized] public Dictionary mAssetDictionary = new Dictionary(StringComparer.Ordinal); + + #endregion + + #region EditorVariables +#if UNITY_EDITOR + + public string Spreadsheet_LocalFileName; + public string Spreadsheet_LocalCSVSeparator = ","; + public string Spreadsheet_LocalCSVEncoding = "utf-8"; + public bool Spreadsheet_SpecializationAsRows = true; + public bool Spreadsheet_SortRows = true; + +#endif + #endregion + + #region Language + + public void Awake() + { + LocalizationManager.AddSource (this); + UpdateDictionary(); + UpdateAssetDictionary(); + LocalizationManager.LocalizeAll(true); + } + + public void OnDestroy() + { + LocalizationManager.RemoveSource(this); + } + + + + public bool IsEqualTo( LanguageSourceData Source ) + { + if (Source.mLanguages.Count != mLanguages.Count) + return false; + + for (int i=0, imax=mLanguages.Count; i x == null); + mAssetDictionary = Assets.Distinct() + .GroupBy(o => o.name, System.StringComparer.Ordinal) + .ToDictionary(g => g.Key, g => g.First(), System.StringComparer.Ordinal); + } + + public Object FindAsset( string Name ) + { + if (Assets!=null) + { + if (mAssetDictionary==null || mAssetDictionary.Count!=Assets.Count) + { + UpdateAssetDictionary(); + } + Object obj; + if (mAssetDictionary.TryGetValue(Name, out obj)) + { + return obj; + } + //for (int i=0, imax=Assets.Length; i 0) + sb.Append("[i2t]"); + var term = mTerms[i]; + sb.Append(term.Term); + sb.Append("="); + + var translation = term.Languages[langIndex]; + if (OnMissingTranslation == MissingTranslationAction.Fallback && string.IsNullOrEmpty(translation)) + if (TryGetFallbackTranslation(term, out translation, langIndex, skipDisabled: true)) + { + sb.Append("[i2fb]"); + if (fillTermWithFallback) term.Languages[langIndex] = translation; + } + + if (!string.IsNullOrEmpty(translation)) + sb.Append(translation); + } + + return sb.ToString(); + } + + #endregion + + #region I2CSV format + + public string Export_I2CSV(string Category, char Separator = ',', bool specializationsAsRows = true, bool sortRows=true) + { + var Builder = new StringBuilder(); + + //--[ Header ]---------------------------------- + Builder.Append("Key[*]Type[*]Desc"); + foreach (var langData in mLanguages) + { + Builder.Append("[*]"); + if (!langData.IsEnabled()) + Builder.Append('$'); + Builder.Append(GoogleLanguages.GetCodedLanguage(langData.Name, langData.Code)); + } + + Builder.Append("[ln]"); + + if (sortRows) + { + mTerms.Sort((a, b) => string.CompareOrdinal(a.Term, b.Term)); + } + + var nLanguages = mLanguages.Count; + var firstLine = true; + foreach (var termData in mTerms) + { + string Term; + + if (string.IsNullOrEmpty(Category) || + Category == EmptyCategory && termData.Term.IndexOfAny(CategorySeparators) < 0) + Term = termData.Term; + else if (termData.Term.StartsWith(Category + @"/", StringComparison.Ordinal) && + Category != termData.Term) + Term = termData.Term.Substring(Category.Length + 1); + else + continue; // Term doesn't belong to this category + + + if (!firstLine) Builder.Append("[ln]"); + firstLine = false; + + if (!specializationsAsRows) + { + AppendI2Term(Builder, nLanguages, Term, termData, Separator, null); + } + else + { + var allSpecializations = termData.GetAllSpecializations(); + for (var i = 0; i < allSpecializations.Count; ++i) + { + if (i != 0) + Builder.Append("[ln]"); + var specialization = allSpecializations[i]; + AppendI2Term(Builder, nLanguages, Term, termData, Separator, specialization); + } + } + } + + return Builder.ToString(); + } + + private static void AppendI2Term(StringBuilder Builder, int nLanguages, string Term, TermData termData, + char Separator, string forceSpecialization) + { + //--[ Key ] -------------- + AppendI2Text(Builder, Term); + if (!string.IsNullOrEmpty(forceSpecialization) && forceSpecialization != "Any") + { + Builder.Append("["); + Builder.Append(forceSpecialization); + Builder.Append("]"); + } + + Builder.Append("[*]"); + + //--[ Type and Description ] -------------- + Builder.Append(termData.TermType.ToString()); + Builder.Append("[*]"); + Builder.Append(termData.Description); + + //--[ Languages ] -------------- + for (var i = 0; i < Mathf.Min(nLanguages, termData.Languages.Length); ++i) + { + Builder.Append("[*]"); + + var translation = termData.Languages[i]; + if (!string.IsNullOrEmpty(forceSpecialization)) + translation = termData.GetTranslation(i, forceSpecialization); + + //bool isAutoTranslated = ((termData.Flags[i]&FlagBitMask)>0); + + /*if (translation == null) + translation = string.Empty; + else + if (translation == "") + translation = "-";*/ + //if (isAutoTranslated) Builder.Append("[i2auto]"); + AppendI2Text(Builder, translation); + } + } + + private static void AppendI2Text(StringBuilder Builder, string text) + { + if (string.IsNullOrEmpty(text)) + return; + + if (text.StartsWith("\'", StringComparison.Ordinal) || text.StartsWith("=", StringComparison.Ordinal)) + Builder.Append('\''); + Builder.Append(text); + } + + #endregion + + #region CSV format + + public string Export_CSV(string Category, char Separator = ',', bool specializationsAsRows = true, bool sortRows=true) + { + var Builder = new StringBuilder(); + + var nLanguages = mLanguages.Count; + Builder.AppendFormat("Key{0}Type{0}Desc", Separator); + + foreach (var langData in mLanguages) + { + Builder.Append(Separator); + if (!langData.IsEnabled()) + Builder.Append('$'); + AppendString(Builder, GoogleLanguages.GetCodedLanguage(langData.Name, langData.Code), Separator); + } + + Builder.Append("\n"); + + + if (sortRows) + { + mTerms.Sort((a, b) => string.CompareOrdinal(a.Term, b.Term)); + } + + foreach (var termData in mTerms) + { + string Term; + + if (string.IsNullOrEmpty(Category) || + Category == EmptyCategory && termData.Term.IndexOfAny(CategorySeparators) < 0) + Term = termData.Term; + else if (termData.Term.StartsWith(Category + @"/", StringComparison.Ordinal) && + Category != termData.Term) + Term = termData.Term.Substring(Category.Length + 1); + else + continue; // Term doesn't belong to this category + + if (specializationsAsRows) + foreach (var specialization in termData.GetAllSpecializations()) + AppendTerm(Builder, nLanguages, Term, termData, specialization, Separator); + else + AppendTerm(Builder, nLanguages, Term, termData, null, Separator); + } + + return Builder.ToString(); + } + + private static void AppendTerm(StringBuilder Builder, int nLanguages, string Term, TermData termData, + string specialization, char Separator) + { + //--[ Key ] -------------- + AppendString(Builder, Term, Separator); + + if (!string.IsNullOrEmpty(specialization) && specialization != "Any") + Builder.AppendFormat("[{0}]", specialization); + + //--[ Type and Description ] -------------- + Builder.Append(Separator); + Builder.Append(termData.TermType.ToString()); + Builder.Append(Separator); + AppendString(Builder, termData.Description, Separator); + + //--[ Languages ] -------------- + for (var i = 0; i < Mathf.Min(nLanguages, termData.Languages.Length); ++i) + { + Builder.Append(Separator); + + var translation = termData.Languages[i]; + if (!string.IsNullOrEmpty(specialization)) + translation = termData.GetTranslation(i, specialization); + + //bool isAutoTranslated = ((termData.Flags[i]&FlagBitMask)>0); + + //if (string.IsNullOrEmpty(s)) + // s = "-"; + + AppendTranslation(Builder, translation, Separator, /*isAutoTranslated ? "[i2auto]" : */null); + } + + Builder.Append("\n"); + } + + + private static void AppendString(StringBuilder Builder, string Text, char Separator) + { + if (string.IsNullOrEmpty(Text)) + return; + Text = Text.Replace("\\n", "\n"); + if (Text.IndexOfAny((Separator + "\n\"").ToCharArray()) >= 0) + { + Text = Text.Replace("\"", "\"\""); + Builder.AppendFormat("\"{0}\"", Text); + } + else + { + Builder.Append(Text); + } + } + + private static void AppendTranslation(StringBuilder Builder, string Text, char Separator, string tags) + { + if (string.IsNullOrEmpty(Text)) + return; + Text = Text.Replace("\\n", "\n"); + if (Text.IndexOfAny((Separator + "\n\"").ToCharArray()) >= 0) + { + Text = Text.Replace("\"", "\"\""); + Builder.AppendFormat("\"{0}{1}\"", tags, Text); + } + else + { + Builder.Append(tags); + Builder.Append(Text); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_CSV.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_CSV.cs.meta new file mode 100644 index 00000000..39b942db --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_CSV.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 7a375153c79873c469c79a5b4f9027f3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_Google.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_Google.cs new file mode 100644 index 00000000..9496ffe1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_Google.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Text; +using UnityEngine; +using UnityEngine.Networking; + +namespace TEngine.Localization +{ + public enum eSpreadsheetUpdateMode { None, Replace, Merge, AddNewTerms } + + public partial class LanguageSourceData + { + public UnityWebRequest Export_Google_CreateWWWcall( eSpreadsheetUpdateMode UpdateMode = eSpreadsheetUpdateMode.Replace ) + { + #if UNITY_WEBPLAYER + Debug.Log ("Contacting google translation is not yet supported on WebPlayer" ); + return null; +#else + string Data = Export_Google_CreateData(); + + WWWForm form = new WWWForm(); + form.AddField("key", Google_SpreadsheetKey); + form.AddField("action", "SetLanguageSource"); + form.AddField("data", Data); + form.AddField("updateMode", UpdateMode.ToString()); + + #if UNITY_EDITOR + form.AddField("password", Google_Password); +#endif + + + UnityWebRequest www = UnityWebRequest.Post(LocalizationManager.GetWebServiceURL(this), form); + I2Utils.SendWebRequest(www); + return www; + #endif + } + + string Export_Google_CreateData() + { + List Categories = GetCategories(true); + StringBuilder Builder = new StringBuilder(); + + bool bFirst = true; + foreach (string category in Categories) + { + if (bFirst) + bFirst = false; + else + Builder.Append(""); + + #if !UNITY_EDITOR + bool Spreadsheet_SpecializationAsRows = true; + bool Spreadsheet_SortRows = true; + #endif + + string CSV = Export_I2CSV(category, specializationsAsRows:Spreadsheet_SpecializationAsRows, sortRows:Spreadsheet_SortRows); + Builder.Append(category); + Builder.Append(""); + Builder.Append(CSV); + } + return Builder.ToString(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_Google.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_Google.cs.meta new file mode 100644 index 00000000..65aa2700 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Export_Google.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 86f9d1c7a0c3815419fc67a9d657ce40 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_CSV.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_CSV.cs new file mode 100644 index 00000000..982d2b6a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_CSV.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine.Localization +{ + public partial class LanguageSourceData + { + public string Import_CSV( string Category, string CSVstring, eSpreadsheetUpdateMode UpdateMode = eSpreadsheetUpdateMode.Replace, char Separator = ',' ) + { + List CSV = LocalizationReader.ReadCSV (CSVstring, Separator); + return Import_CSV( Category, CSV, UpdateMode ); + } + + public string Import_I2CSV( string Category, string I2CSVstring, eSpreadsheetUpdateMode UpdateMode = eSpreadsheetUpdateMode.Replace ) + { + List CSV = LocalizationReader.ReadI2CSV (I2CSVstring); + return Import_CSV( Category, CSV, UpdateMode ); + } + + public string Import_CSV( string Category, List CSV, eSpreadsheetUpdateMode UpdateMode = eSpreadsheetUpdateMode.Replace ) + { + string[] Tokens = CSV[0]; + + int LanguagesStartIdx = 1; + int TypeColumnIdx = -1; + int DescColumnIdx = -1; + + var ValidColumnName_Key = new[]{ "Key" }; + var ValidColumnName_Type = new[]{ "Type" }; + var ValidColumnName_Desc = new[]{ "Desc", "Description" }; + + if (Tokens.Length>1 && ArrayContains(Tokens[0], ValidColumnName_Key)) + { + if (UpdateMode == eSpreadsheetUpdateMode.Replace) + ClearAllData(); + + if (Tokens.Length>2) + { + if (ArrayContains(Tokens[1], ValidColumnName_Type)) + { + TypeColumnIdx = 1; + LanguagesStartIdx = 2; + } + if (ArrayContains(Tokens[1], ValidColumnName_Desc)) + { + DescColumnIdx = 1; + LanguagesStartIdx = 2; + } + + } + if (Tokens.Length>3) + { + if (ArrayContains(Tokens[2], ValidColumnName_Type)) + { + TypeColumnIdx = 2; + LanguagesStartIdx = 3; + } + if (ArrayContains(Tokens[2], ValidColumnName_Desc)) + { + DescColumnIdx = 2; + LanguagesStartIdx = 3; + } + } + } + else + return "Bad Spreadsheet Format.\nFirst columns should be 'Key', 'Type' and 'Desc'"; + + int nLanguages = Mathf.Max (Tokens.Length-LanguagesStartIdx, 0); + int[] LanIndices = new int[nLanguages]; + for (int i=0; i0) + { + specialization = sKey.Substring(idx + 1, sKey.Length - idx - 2); + if (specialization == "touch") specialization = "Touch"; + sKey = sKey.Remove(idx); + } + } + ValidateFullTerm(ref sKey); + if (string.IsNullOrEmpty(sKey)) + continue; + + TermData termData = GetTermData(sKey); + + // Check to see if its a new term + if (termData==null) + { + termData = new TermData(); + termData.Term = sKey; + + termData.Languages = new string[ mLanguages.Count ]; + termData.Flags = new byte[ mLanguages.Count ]; + for (int j=0; j0) + termData.TermType = GetTermType(Tokens[TypeColumnIdx]); + + if (DescColumnIdx>0) + termData.Description = Tokens[DescColumnIdx]; + + for (int j = 0; j < LanIndices.Length && j < Tokens.Length - LanguagesStartIdx; ++j) + if (!string.IsNullOrEmpty(Tokens[j + LanguagesStartIdx])) // Only change the translation if there is a new value + { + var lanIdx = LanIndices[j]; + if (lanIdx < 0) + continue; + var value = Tokens[j + LanguagesStartIdx]; + + if (value == "-") + value = string.Empty; + else + if (value == "") + value = null; + + termData.SetTranslation(lanIdx, value, specialization); + } + } + if (Application.isPlaying) + { + SaveLanguages(HasUnloadedLanguages()); + } + return string.Empty; + } + + bool ArrayContains( string MainText, params string[] texts ) + { + for (int i=0, imax=texts.Length; i=0) + return true; + return false; + } + + public static eTermType GetTermType( string type ) + { + for (int i=0, imax=(int)eTermType.Object; i<=imax; ++i) + if (string.Equals( ((eTermType)i).ToString(), type, StringComparison.OrdinalIgnoreCase)) + return (eTermType)i; + + return eTermType.Text; + } + + #region Language Cache format + + void Import_Language_from_Cache(int langIndex, string langData, bool useFallback, bool onlyCurrentSpecialization) + { + int index = 0; + while (index < langData.Length) + { + int nextIndex = langData.IndexOf("[i2t]", index, StringComparison.Ordinal); + if (nextIndex < 0) nextIndex = langData.Length; + + // check for errors + int termNameEnd = langData.IndexOf("=", index, StringComparison.Ordinal); + if (termNameEnd >= nextIndex) + return; + + string termName = langData.Substring(index, termNameEnd - index); + index = termNameEnd+1; + + var termData = GetTermData(termName); + if (termData != null) + { + string translation = null; + + if (index != nextIndex) + { + translation = langData.Substring(index, nextIndex - index); + if (translation.StartsWith("[i2fb]", StringComparison.Ordinal)) + { + translation = useFallback ? translation.Substring(6) : null; + } + if (onlyCurrentSpecialization && translation != null) + { + translation = SpecializationManager.GetSpecializedText(translation); + } + } + termData.Languages[langIndex] = translation; + } + index = nextIndex + 5; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_CSV.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_CSV.cs.meta new file mode 100644 index 00000000..7c86dd83 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_CSV.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6dfd98b5473aa1a49b82726182b50d08 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_Google.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_Google.cs new file mode 100644 index 00000000..e5d6cd8c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_Google.cs @@ -0,0 +1,385 @@ +using System; +using System.Collections; +using System.Text; +using UnityEditor; +using UnityEngine; +using UnityEngine.Networking; +using UnityEngine.SceneManagement; +using Object = UnityEngine.Object; + +namespace TEngine.Localization +{ + public partial class LanguageSourceData + { + private string mDelayedGoogleData; // Data that was downloaded and is waiting for a levelLoaded event to apply the localization without a lag in performance + #region Connection to Web Service + + public static void FreeUnusedLanguages() + { + var source = LocalizationManager.Sources[0]; + int langIndex = source.GetLanguageIndex(LocalizationManager.CurrentLanguage); + + for (int i=0; i 19) // Check for corruption from previous versions + savedSpreadsheetVersion = string.Empty; + Google_LastUpdatedVersion = savedSpreadsheetVersion; + + //Debug.Log ("[I2Loc] Using Saved (PlayerPref) data in 'I2Source_"+PlayerPrefName+"'" ); + Import_Google_Result(I2SavedData, eSpreadsheetUpdateMode.Replace); + } + + bool IsNewerVersion( string currentVersion, string newVersion ) + { + if (string.IsNullOrEmpty (newVersion)) // if no new version + return false; + if (string.IsNullOrEmpty (currentVersion)) // there is a new version, but not a current one + return true; + + long currentV, newV; + if (!long.TryParse (newVersion, out newV) || !long.TryParse (currentVersion, out currentV)) // if can't parse either, then force get the new one + return true; + + return newV > currentV; + } + + // When JustCheck is true, importing from google will not download any data, just detect if the Spreadsheet is up-to-date + public void Import_Google( bool ForceUpdate, bool justCheck) + { + if (!ForceUpdate && GoogleUpdateFrequency==eGoogleUpdateFrequency.Never) + return; + + if (!I2Utils.IsPlaying()) + return; + + #if UNITY_EDITOR + if (justCheck && GoogleInEditorCheckFrequency==eGoogleUpdateFrequency.Never) + return; + #endif + + #if UNITY_EDITOR + var updateFrequency = GoogleInEditorCheckFrequency; + #else + var updateFrequency = GoogleUpdateFrequency; + #endif + + string PlayerPrefName = GetSourcePlayerPrefName(); + + if (!ForceUpdate && updateFrequency != eGoogleUpdateFrequency.Always) + { + #if UNITY_EDITOR + string sTimeOfLastUpdate = EditorPrefs.GetString("LastGoogleUpdate_"+PlayerPrefName, ""); + #else + string sTimeOfLastUpdate = PersistentStorage.GetSetting_String("LastGoogleUpdate_"+PlayerPrefName, ""); + #endif + DateTime TimeOfLastUpdate; + try + { + if (DateTime.TryParse( sTimeOfLastUpdate, out TimeOfLastUpdate )) + { + double TimeDifference = (DateTime.Now-TimeOfLastUpdate).TotalDays; + switch (updateFrequency) + { + case eGoogleUpdateFrequency.Daily: if (TimeDifference<1) return; + break; + case eGoogleUpdateFrequency.Weekly: if (TimeDifference<8) return; + break; + case eGoogleUpdateFrequency.Monthly: if (TimeDifference<31) return; + break; + case eGoogleUpdateFrequency.OnlyOnce: return; + case eGoogleUpdateFrequency.EveryOtherDay : if (TimeDifference < 2) return; + break; + } + } + } + catch(Exception) + { } + } + #if UNITY_EDITOR + EditorPrefs.SetString("LastGoogleUpdate_" + PlayerPrefName, DateTime.Now.ToString()); + #else + PersistentStorage.SetSetting_String("LastGoogleUpdate_"+PlayerPrefName, DateTime.Now.ToString()); + #endif + + //--[ Checking google for updated data ]----------------- + CoroutineManager.Start(Import_Google_Coroutine(ForceUpdate, justCheck)); + } + + string GetSourcePlayerPrefName() + { + if (owner == null) + return null; + string sourceName = (owner as Object).name; + if (!string.IsNullOrEmpty(Google_SpreadsheetKey)) + { + sourceName += Google_SpreadsheetKey; + } + // If its a global source, use its name, otherwise, use the name and the level it is in + if (Array.IndexOf(LocalizationManager.GlobalSources, (owner as Object).name)>=0) + return sourceName; +#if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 + return Application.loadedLevelName + "_" + sourceName; +#else + return SceneManager.GetActiveScene().name+"_"+ sourceName; +#endif + } + + IEnumerator Import_Google_Coroutine(bool forceUpdate, bool JustCheck) + { + UnityWebRequest www = Import_Google_CreateWWWcall(forceUpdate, JustCheck); + if (www==null) + yield break; + + while (!www.isDone) + yield return null; + + //Debug.Log ("Google Result: " + www.text); + byte[] bytes = www.downloadHandler.data; + bool notError = string.IsNullOrEmpty(www.error) && bytes!=null; + + if (notError) + { + string wwwText = Encoding.UTF8.GetString(bytes, 0, bytes.Length); + + bool isEmpty = string.IsNullOrEmpty(wwwText) || wwwText == "\"\""; + + if (JustCheck) + { + if (!isEmpty) + { + Debug.LogWarning("Spreadsheet is not up-to-date and Google Live Synchronization is enabled\nWhen playing in the device the Spreadsheet will be downloaded and translations may not behave as what you see in the editor.\nTo fix this, Import or Export replace to Google"); + GoogleLiveSyncIsUptoDate = false; + } + + yield break; + } + + if (!isEmpty) + { + mDelayedGoogleData = wwwText; + + switch (GoogleUpdateSynchronization) + { + case eGoogleUpdateSynchronization.AsSoonAsDownloaded: + { + ApplyDownloadedDataFromGoogle(); + break; + } + case eGoogleUpdateSynchronization.Manual: + break; + case eGoogleUpdateSynchronization.OnSceneLoaded: + { + SceneManager.sceneLoaded += ApplyDownloadedDataOnSceneLoaded; + break; + } + } + + yield break; + } + } + + if (Event_OnSourceUpdateFromGoogle != null) + Event_OnSourceUpdateFromGoogle(this, false, www.error); + + Debug.Log("Language Source was up-to-date with Google Spreadsheet"); + } + + void ApplyDownloadedDataOnSceneLoaded(UnityEngine.SceneManagement.Scene scene, LoadSceneMode mode) + { + SceneManager.sceneLoaded -= ApplyDownloadedDataOnSceneLoaded; + ApplyDownloadedDataFromGoogle(); + } + + public void ApplyDownloadedDataFromGoogle() + { + if (string.IsNullOrEmpty(mDelayedGoogleData)) + return; + + var errorMsg = Import_Google_Result(mDelayedGoogleData, eSpreadsheetUpdateMode.Replace, true); + if (string.IsNullOrEmpty(errorMsg)) + { + if (Event_OnSourceUpdateFromGoogle != null) + Event_OnSourceUpdateFromGoogle(this, true, ""); + + LocalizationManager.LocalizeAll(true); + Debug.Log("Done Google Sync"); + } + else + { + if (Event_OnSourceUpdateFromGoogle != null) + Event_OnSourceUpdateFromGoogle(this, false, ""); + + Debug.Log("Done Google Sync: source was up-to-date"); + } + } + + public UnityWebRequest Import_Google_CreateWWWcall( bool ForceUpdate, bool justCheck ) + { + if (!HasGoogleSpreadsheet()) + return null; + + string savedVersion = PersistentStorage.GetSetting_String("I2SourceVersion_"+GetSourcePlayerPrefName(), Google_LastUpdatedVersion); + if (savedVersion.Length > 19) // Check for corruption + savedVersion= string.Empty; + +#if !UNITY_EDITOR + if (IsNewerVersion(savedVersion, Google_LastUpdatedVersion)) + Google_LastUpdatedVersion = savedVersion; +#endif + + string query = string.Format("{0}?key={1}&action=GetLanguageSource&version={2}", + LocalizationManager.GetWebServiceURL(this), + Google_SpreadsheetKey, + ForceUpdate ? "0" : Google_LastUpdatedVersion); +#if UNITY_EDITOR + if (justCheck) + { + query += "&justcheck=true"; + } +#endif + UnityWebRequest www = UnityWebRequest.Get(query); + I2Utils.SendWebRequest(www); + return www; + } + + public bool HasGoogleSpreadsheet() + { + return !string.IsNullOrEmpty(Google_WebServiceURL) && !string.IsNullOrEmpty(Google_SpreadsheetKey) && + !string.IsNullOrEmpty(LocalizationManager.GetWebServiceURL(this)); + } + + public string Import_Google_Result( string JsonString, eSpreadsheetUpdateMode UpdateMode, bool saveInPlayerPrefs = false ) + { + try + { + string ErrorMsg = string.Empty; + if (string.IsNullOrEmpty(JsonString) || JsonString == "\"\"") + { + return ErrorMsg; + } + + int idxV = JsonString.IndexOf("version=", StringComparison.Ordinal); + int idxSV = JsonString.IndexOf("script_version=", StringComparison.Ordinal); + if (idxV < 0 || idxSV < 0) + { + return "Invalid Response from Google, Most likely the WebService needs to be updated"; + } + + idxV += "version=".Length; + idxSV += "script_version=".Length; + + string newSpreadsheetVersion = JsonString.Substring(idxV, JsonString.IndexOf(",", idxV, StringComparison.Ordinal) - idxV); + var scriptVersion = int.Parse(JsonString.Substring(idxSV, JsonString.IndexOf(",", idxSV, StringComparison.Ordinal) - idxSV)); + + if (newSpreadsheetVersion.Length > 19) // Check for corruption + newSpreadsheetVersion = string.Empty; + + if (scriptVersion != LocalizationManager.GetRequiredWebServiceVersion()) + { + return "The current Google WebService is not supported.\nPlease, delete the WebService from the Google Drive and Install the latest version."; + } + + //Debug.Log (Google_LastUpdatedVersion + " - " + newSpreadsheetVersion); + if (saveInPlayerPrefs && !IsNewerVersion(Google_LastUpdatedVersion, newSpreadsheetVersion)) +#if UNITY_EDITOR + return ""; +#else + return "LanguageSource is up-to-date"; +#endif + + if (saveInPlayerPrefs) + { + string PlayerPrefName = GetSourcePlayerPrefName(); + PersistentStorage.SaveFile(PersistentStorage.eFileType.Persistent, "I2Source_" + PlayerPrefName + ".loc", "[i2e]" + StringObfucator.Encode(JsonString)); + PersistentStorage.SetSetting_String("I2SourceVersion_" + PlayerPrefName, newSpreadsheetVersion); + PersistentStorage.ForceSaveSettings(); + } + Google_LastUpdatedVersion = newSpreadsheetVersion; + + if (UpdateMode == eSpreadsheetUpdateMode.Replace) + ClearAllData(); + + int CSVstartIdx = JsonString.IndexOf("[i2category]", StringComparison.Ordinal); + while (CSVstartIdx > 0) + { + CSVstartIdx += "[i2category]".Length; + int endCat = JsonString.IndexOf("[/i2category]", CSVstartIdx, StringComparison.Ordinal); + string category = JsonString.Substring(CSVstartIdx, endCat - CSVstartIdx); + endCat += "[/i2category]".Length; + + int endCSV = JsonString.IndexOf("[/i2csv]", endCat, StringComparison.Ordinal); + string csv = JsonString.Substring(endCat, endCSV - endCat); + + CSVstartIdx = JsonString.IndexOf("[i2category]", endCSV, StringComparison.Ordinal); + + Import_I2CSV(category, csv, UpdateMode); + + // Only the first CSV should clear the Data + if (UpdateMode == eSpreadsheetUpdateMode.Replace) + UpdateMode = eSpreadsheetUpdateMode.Merge; + } + + GoogleLiveSyncIsUptoDate = true; + if (I2Utils.IsPlaying()) + { + SaveLanguages(true); + } + + if (!string.IsNullOrEmpty(ErrorMsg)) + Editor_SetDirty(); + return ErrorMsg; + } + catch (Exception e) + { + Debug.LogWarning(e); + return e.ToString(); + } + } + +#endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_Google.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_Google.cs.meta new file mode 100644 index 00000000..336c8739 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Import_Google.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 637497c3e1b8b944e9a645fe50e27401 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Languages.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Languages.cs new file mode 100644 index 00000000..85fe3df2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Languages.cs @@ -0,0 +1,335 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace TEngine.Localization +{ + public partial class LanguageSourceData + { + #region Language + + public int GetLanguageIndex( string language, bool AllowDiscartingRegion = true, bool SkipDisabled = true) + { + // First look for an exact match + for (int i=0, imax=mLanguages.Count; iBestSimilitud) + { + BestSimilitud = commonWords; + MostSimilar = i; + } + //if (AreTheSameLanguage(mLanguages[i].Name, language)) + // return i; + } + if (MostSimilar>=0) + return MostSimilar; + } + return -1; + } + + public LanguageData GetLanguageData(string language, bool AllowDiscartingRegion = true) + { + int idx = GetLanguageIndex(language, AllowDiscartingRegion, false); + return idx < 0 ? null : mLanguages[idx]; + } + + // TODO: Fix IsCurrentLanguage when current=English and there are two variants in the source (English Canada, English US) + public bool IsCurrentLanguage( int languageIndex ) + { + return LocalizationManager.CurrentLanguage == mLanguages[languageIndex].Name; + } + + public int GetLanguageIndexFromCode( string Code, bool exactMatch=true, bool ignoreDisabled = false) + { + for (int i = 0, imax = mLanguages.Count; i < imax; ++i) + { + if (ignoreDisabled && !mLanguages[i].IsEnabled()) + continue; + + if (string.Compare(mLanguages[i].Code, Code, StringComparison.OrdinalIgnoreCase) == 0) + return i; + } + + if (!exactMatch) + { + // Find any match without using the Regions + for (int i = 0, imax = mLanguages.Count; i < imax; ++i) + { + if (ignoreDisabled && !mLanguages[i].IsEnabled()) + continue; + + if (string.Compare(mLanguages[i].Code, 0, Code, 0, 2, StringComparison.OrdinalIgnoreCase) == 0) + return i; + } + } + + return -1; + } + + public static int GetCommonWordInLanguageNames(string Language1, string Language2) + { + if (string.IsNullOrEmpty (Language1) || string.IsNullOrEmpty (Language2)) + return 0; + var separators = "( )-/\\".ToCharArray(); + string[] Words1 = Language1.ToLower().Split(separators); + string[] Words2 = Language2.ToLower().Split(separators); + + int similitud = 0; + foreach (var word in Words1) + if (!string.IsNullOrEmpty(word) && Words2.Contains(word)) + similitud++; + + foreach (var word in Words2) + if (!string.IsNullOrEmpty(word) && Words1.Contains(word)) + similitud++; + + return similitud; + } + + public static bool AreTheSameLanguage(string Language1, string Language2) + { + Language1 = GetLanguageWithoutRegion(Language1); + Language2 = GetLanguageWithoutRegion(Language2); + return string.Compare(Language1, Language2, StringComparison.OrdinalIgnoreCase)==0; + } + + public static string GetLanguageWithoutRegion(string Language) + { + int Index = Language.IndexOfAny("(/\\[,{".ToCharArray()); + if (Index<0) + return Language; + return Language.Substring(0, Index).Trim(); + } + + public void AddLanguage(string LanguageName) + { + AddLanguage(LanguageName, GoogleLanguages.GetLanguageCode(LanguageName)); + } + + public void AddLanguage( string LanguageName, string LanguageCode ) + { + if (GetLanguageIndex(LanguageName, false)>=0) + return; + + LanguageData Lang = new LanguageData(); + Lang.Name = LanguageName; + Lang.Code = LanguageCode; + mLanguages.Add (Lang); + + int NewSize = mLanguages.Count; + for (int i=0, imax=mTerms.Count; i GetLanguages( bool skipDisabled = true) + { + List Languages = new List(); + for (int j = 0, jmax = mLanguages.Count; j < jmax; ++j) + { + if (!skipDisabled || mLanguages[j].IsEnabled()) + Languages.Add(mLanguages[j].Name); + } + return Languages; + } + + public List GetLanguagesCode(bool allowRegions = true, bool skipDisabled = true) + { + List Languages = new List(); + for (int j = 0, jmax = mLanguages.Count; j < jmax; ++j) + { + if (skipDisabled && !mLanguages[j].IsEnabled()) + continue; + + var code = mLanguages[j].Code; + + if (!allowRegions && code != null && code.Length > 2) + code = code.Substring(0, 2); + + if (!string.IsNullOrEmpty(code) && !Languages.Contains(code)) + Languages.Add(code); + } + return Languages; + } + + public bool IsLanguageEnabled(string Language) + { + int idx = GetLanguageIndex(Language, false); + return idx >= 0 && mLanguages[idx].IsEnabled(); + } + + public void EnableLanguage(string Language, bool bEnabled) + { + int idx = GetLanguageIndex(Language, false, false); + if (idx >= 0) + mLanguages[idx].SetEnabled(bEnabled); + } + + #endregion + + #region Save/Load Language + + public bool AllowUnloadingLanguages() + { + #if UNITY_EDITOR + return _AllowUnloadingLanguages==eAllowUnloadLanguages.EditorAndDevice; + #else + return _AllowUnloadingLanguages!=eAllowUnloadLanguages.Never; + #endif + } + + string GetSavedLanguageFileName(int languageIndex) + { + if (languageIndex < 0) + return null; + + return "LangSource_" + GetSourcePlayerPrefName() + "_" + mLanguages[languageIndex].Name + ".loc"; + } + public void LoadLanguage( int languageIndex, bool UnloadOtherLanguages, bool useFallback, bool onlyCurrentSpecialization, bool forceLoad ) + { + if (!AllowUnloadingLanguages()) + return; + + // Some consoles don't allow IO access + if (!PersistentStorage.CanAccessFiles()) + return; + + if (languageIndex >= 0 && (forceLoad || !mLanguages[languageIndex].IsLoaded())) + { + var tempPath = GetSavedLanguageFileName(languageIndex); + var langData = PersistentStorage.LoadFile(PersistentStorage.eFileType.Temporal, tempPath, false); + + if (!string.IsNullOrEmpty(langData)) + { + Import_Language_from_Cache(languageIndex, langData, useFallback, onlyCurrentSpecialization); + mLanguages[languageIndex].SetLoaded(true); + } + } + if (UnloadOtherLanguages && I2Utils.IsPlaying()) + { + for (int lan = 0; lan < mLanguages.Count; ++lan) + { + if (lan != languageIndex) + UnloadLanguage(lan); + } + } + } + + // if forceLoad, then the language is loaded from the cache even if its already loaded + // this is needed to cleanup fallbacks + public void LoadAllLanguages(bool forceLoad=false) + { + for (int i = 0; i < mLanguages.Count; ++i) + { + LoadLanguage(i, false, false, false, forceLoad); + } + } + + public void UnloadLanguage(int languageIndex) + { + if (!AllowUnloadingLanguages()) + return; + + // Some consoles don't allow IO access + if (!PersistentStorage.CanAccessFiles()) + return; + + if (!I2Utils.IsPlaying() || + !mLanguages[languageIndex].IsLoaded() || + !mLanguages[languageIndex].CanBeUnloaded() || + IsCurrentLanguage(languageIndex) || + !PersistentStorage.HasFile(PersistentStorage.eFileType.Temporal, GetSavedLanguageFileName(languageIndex))) + { + return; + } + + foreach (var termData in mTerms) + { + termData.Languages[languageIndex] = null; + } + mLanguages[languageIndex].SetLoaded(false); + } + + public void SaveLanguages( bool unloadAll, PersistentStorage.eFileType fileLocation = PersistentStorage.eFileType.Temporal) + { + if (!AllowUnloadingLanguages()) + return; + + // Some consoles don't allow IO access + if (!PersistentStorage.CanAccessFiles()) + return; + + for (int i = 0; i < mLanguages.Count; ++i) + { + if (string.IsNullOrEmpty(mLanguages[i].Name)) + { + Debug.LogError($"Language {i} has no name, please assign a name to the language or it may not show on a build"); + continue; + } + var data = Export_Language_to_Cache(i, IsCurrentLanguage(i)); + if (string.IsNullOrEmpty(data)) + continue; + + PersistentStorage.SaveFile(PersistentStorage.eFileType.Temporal, GetSavedLanguageFileName(i), data); + } + + if (unloadAll) + { + for (int i = 0; i < mLanguages.Count; ++i) + { + if (unloadAll && !IsCurrentLanguage(i)) + UnloadLanguage(i); + } + } + } + + public bool HasUnloadedLanguages() + { + for (int i = 0; i < mLanguages.Count; ++i) + { + if (!mLanguages[i].IsLoaded()) + return true; + } + return false; + + } +#endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Languages.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Languages.cs.meta new file mode 100644 index 00000000..c8f0b8c8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Languages.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3c8d05bf03c50f64eb591ea1499fae82 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Misc.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Misc.cs new file mode 100644 index 00000000..d3ca8843 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Misc.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; + +namespace TEngine.Localization +{ + public partial class LanguageSourceData + { + public static string EmptyCategory = "Default"; + public static char[] CategorySeparators = "/\\".ToCharArray(); + + #region Keys + + public List GetCategories( bool OnlyMainCategory = false, List Categories = null ) + { + if (Categories==null) + Categories = new List(); + + foreach (TermData data in mTerms) + { + string sCategory = GetCategoryFromFullTerm( data.Term, OnlyMainCategory ); + if (!Categories.Contains(sCategory)) + Categories.Add(sCategory); + } + Categories.Sort(); + return Categories; + } + + public static string GetKeyFromFullTerm( string FullTerm, bool OnlyMainCategory = false ) + { + int Index = OnlyMainCategory ? FullTerm.IndexOfAny(CategorySeparators) : + FullTerm.LastIndexOfAny(CategorySeparators); + + return Index<0 ? FullTerm :FullTerm.Substring(Index+1); + } + + public static string GetCategoryFromFullTerm( string FullTerm, bool OnlyMainCategory = false ) + { + int Index = OnlyMainCategory ? FullTerm.IndexOfAny(CategorySeparators) : + FullTerm.LastIndexOfAny(CategorySeparators); + + return Index<0 ? EmptyCategory : FullTerm.Substring(0, Index); + } + + public static void DeserializeFullTerm( string FullTerm, out string Key, out string Category, bool OnlyMainCategory = false ) + { + int Index = OnlyMainCategory ? FullTerm.IndexOfAny(CategorySeparators) : + FullTerm.LastIndexOfAny(CategorySeparators); + + if (Index<0) + { + Category = EmptyCategory; + Key = FullTerm; + } + else + { + Category = FullTerm.Substring(0, Index); + Key = FullTerm.Substring(Index+1); + } + } + + #endregion + + #region Misc + + #endregion + + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Misc.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Misc.cs.meta new file mode 100644 index 00000000..47ca03b3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Misc.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: eaa919dd06da3464082b8f16759a5b16 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Terms.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Terms.cs new file mode 100644 index 00000000..61e3a612 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Terms.cs @@ -0,0 +1,255 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public partial class LanguageSourceData + { + #region Language + + public void UpdateDictionary(bool force = false) + { + if (!force && mDictionary != null && mDictionary.Count == mTerms.Count) + return; + + StringComparer comparer = CaseInsensitiveTerms ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal; + if (mDictionary.Comparer != comparer) + mDictionary = new Dictionary(comparer); + else + mDictionary.Clear(); + + for (int i = 0, imax = mTerms.Count; i < imax; ++i) + { + var termData = mTerms[i]; + ValidateFullTerm(ref termData.Term); + + mDictionary[termData.Term]= mTerms[i]; + mTerms[i].Validate(); + } + + if (I2Utils.IsPlaying()) + { + SaveLanguages(true); + } + } + + public string GetTranslation (string term, string overrideLanguage = null, string overrideSpecialization = null, bool skipDisabled = false, bool allowCategoryMistmatch = false) + { + TryGetTranslation(term, out string translation, overrideLanguage:overrideLanguage, overrideSpecialization:overrideSpecialization, skipDisabled:skipDisabled, allowCategoryMistmatch:allowCategoryMistmatch); + return translation; + } + + public bool TryGetTranslation (string term, out string Translation, string overrideLanguage=null, string overrideSpecialization=null, bool skipDisabled=false, bool allowCategoryMistmatch=false) + { + int Index = GetLanguageIndex( overrideLanguage==null ? LocalizationManager.CurrentLanguage : overrideLanguage, SkipDisabled: false ); + + if (Index>=0 && (!skipDisabled || mLanguages[Index].IsEnabled())) + { + TermData data = GetTermData(term, allowCategoryMistmatch:allowCategoryMistmatch); + if (data!=null) + { + Translation = data.GetTranslation(Index, overrideSpecialization, editMode:true); + + // "---" is a code to define that the translation is meant to be empty + if (Translation == "---") + { + Translation = string.Empty; + return true; + } + + if (!string.IsNullOrEmpty(Translation)) + { + // has a valid translation + return true; + } + + Translation = null; + } + + if (OnMissingTranslation == MissingTranslationAction.ShowWarning) + { + Translation = $""; + Debug.LogWarning($"Missing Translation for '{term}'", Localize.CurrentLocalizeComponent); + return false; + } + + if (OnMissingTranslation == MissingTranslationAction.Fallback && data!=null) + { + return TryGetFallbackTranslation(data, out Translation, Index, overrideSpecialization, skipDisabled); + } + + if (OnMissingTranslation == MissingTranslationAction.Empty) + { + Translation = string.Empty; + return false; + } + + if (OnMissingTranslation == MissingTranslationAction.ShowTerm) + { + Translation = term; + return false; + } + + } + + Translation = null; + return false; + } + + bool TryGetFallbackTranslation(TermData termData, out string Translation, int langIndex, string overrideSpecialization = null, bool skipDisabled = false) + { + // Find base Language Code + string baseLanguage = mLanguages[langIndex].Code; + if (!string.IsNullOrEmpty(baseLanguage)) + { + if (baseLanguage.Contains("-")) + { + baseLanguage = baseLanguage.Substring(0, baseLanguage.IndexOf('-')); + } + + // Try finding in any of the Region of the base language + for (int i = 0; i < mLanguages.Count; ++i) + { + if (i != langIndex && + mLanguages[i].Code.StartsWith(baseLanguage, StringComparison.Ordinal) && + (!skipDisabled || mLanguages[i].IsEnabled()) ) + { + Translation = termData.GetTranslation(i, overrideSpecialization, editMode: true); + if (!string.IsNullOrEmpty(Translation)) + return true; + } + } + } + + + // Otherwise, Try finding the first active language with a valid translation + for (int i = 0; i < mLanguages.Count; ++i) + { + if (i!=langIndex && + (!skipDisabled || mLanguages[i].IsEnabled()) && + (baseLanguage==null || !mLanguages[i].Code.StartsWith(baseLanguage, StringComparison.Ordinal))) + { + Translation = termData.GetTranslation(i, overrideSpecialization, editMode: true); + if (!string.IsNullOrEmpty(Translation)) + return true; + } + } + Translation = null; + return false; + } + + public TermData AddTerm( string term ) + { + return AddTerm (term, eTermType.Text); + } + + public TermData GetTermData( string term, bool allowCategoryMistmatch = false) + { + if (string.IsNullOrEmpty(term)) + return null; + + if (mDictionary.Count==0)// != mTerms.Count) + UpdateDictionary(); + + TermData data; + if (mDictionary.TryGetValue(term, out data)) + return data; + + TermData d = null; + if (allowCategoryMistmatch) + { + var keyPart = GetKeyFromFullTerm (term); + foreach (var kvp in mDictionary) + if (kvp.Value.IsTerm (keyPart, true)) + { + if (d == null) + d = kvp.Value; + else + return null; + } + } + return d; + } + + public bool ContainsTerm(string term) + { + return GetTermData(term)!=null; + } + + public List GetTermsList ( string Category = null ) + { + if (mDictionary.Count != mTerms.Count) + UpdateDictionary(); + if (string.IsNullOrEmpty( Category )) + return new List( mDictionary.Keys ); + var terms = new List(); + for (int i=0; iEmptyCategory.Length && Term[EmptyCategory.Length]=='/') + Term = Term.Substring(EmptyCategory.Length+1); + } + Term = I2Utils.GetValidTermName(Term, true); + } + + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Terms.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Terms.cs.meta new file mode 100644 index 00000000..640162a8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LanguageSource/LanguageSourceData_Terms.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f55c00558b2b4f94086c04e47d98a645 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizationReader.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizationReader.cs new file mode 100644 index 00000000..d0d6ab41 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizationReader.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEngine; + +namespace TEngine.Localization +{ + public class LocalizationReader + { + #region Dictionary Assets + + public static Dictionary ReadTextAsset( TextAsset asset ) + { + string Text = Encoding.UTF8.GetString (asset.bytes, 0, asset.bytes.Length); + Text = Text.Replace("\r\n", "\n"); + Text = Text.Replace("\r", "\n"); + StringReader reader = new StringReader(Text); + + string s; + Dictionary Dict = new Dictionary(StringComparer.Ordinal); + while ( (s=reader.ReadLine()) != null ) + { + string Key, Value, Category, TermType, Comment; + if (!TextAsset_ReadLine(s, out Key, out Value, out Category, out Comment, out TermType)) + continue; + + if (!string.IsNullOrEmpty(Key) && !string.IsNullOrEmpty(Value)) + Dict[Key]=Value; + } + return Dict; + } + + public static bool TextAsset_ReadLine( string line, out string key, out string value, out string category, out string comment, out string termType ) + { + key = string.Empty; + category= string.Empty; + comment = string.Empty; + termType= string.Empty; + value = string.Empty; + + //--[ Comment ]----------------------- + int iComment = line.LastIndexOf("//", StringComparison.Ordinal); + if (iComment>=0) + { + comment = line.Substring(iComment+2).Trim(); + comment = DecodeString(comment); + line = line.Substring(0, iComment); + } + + //--[ Key ]----------------------------- + int iKeyEnd = line.IndexOf("=", StringComparison.Ordinal); + if (iKeyEnd<0) + { + return false; + } + + key = line.Substring(0, iKeyEnd).Trim(); + value = line.Substring(iKeyEnd+1).Trim(); + value = value.Replace ("\r\n", "\n").Replace ("\n", "\\n"); + value = DecodeString(value); + + //--[ Type ]--------- + if (key.Length>2 && key[0]=='[') + { + int iTypeEnd = key.IndexOf(']'); + if (iTypeEnd>=0) + { + termType = key.Substring(1, iTypeEnd-1); + key = key.Substring(iTypeEnd+1); + } + } + + ValidateFullTerm( ref key ); + + return true; + } + + #endregion + + #region CSV + public static string ReadCSVfile( string Path, Encoding encoding ) + { + string Text = string.Empty; + #if (UNITY_WP8 || UNITY_METRO) && !UNITY_EDITOR + byte[] buffer = UnityEngine.Windows.File.ReadAllBytes (Path); + Text = Encoding.UTF8.GetString(buffer, 0, buffer.Length); + #else + /*using (System.IO.StreamReader reader = System.IO.File.OpenText(Path)) + { + Text = reader.ReadToEnd(); + }*/ + using (var reader = new StreamReader(Path, encoding )) + Text = reader.ReadToEnd(); + #endif + + Text = Text.Replace("\r\n", "\n"); + Text = Text.Replace("\r", "\n"); + + return Text; + } + + public static List ReadCSV( string Text, char Separator=',' ) + { + int iStart = 0; + List CSV = new List(); + + while (iStart < Text.Length) + { + string[] list = ParseCSVline (Text, ref iStart, Separator); + if (list==null) break; + CSV.Add(list); + } + return CSV; + } + + static string[] ParseCSVline( string Line, ref int iStart, char Separator ) + { + List list = new List(); + + //Line = "puig,\"placeres,\"\"cab\nr\nera\"\"algo\"\npuig";//\"Frank\npuig\nplaceres\",aaa,frank\nplaceres"; + + int TextLength = Line.Length; + int iWordStart = iStart; + bool InsideQuote = false; + + while (iStart < TextLength) + { + char c = Line[iStart]; + + if (InsideQuote) + { + if (c=='\"') //--[ Look for Quote End ]------------ + { + if (iStart+1 >= TextLength || Line[iStart+1] != '\"') //-- Single Quote: Quotation Ends + { + InsideQuote = false; + } + else + if (iStart+2 < TextLength && Line[iStart+2]=='\"') //-- Tripple Quotes: Quotation ends + { + InsideQuote = false; + iStart+=2; + } + else + iStart++; // Skip Double Quotes + } + } + + else //-----[ Separators ]---------------------- + + if (c=='\n' || c==Separator) + { + AddCSVtoken(ref list, ref Line, iStart, ref iWordStart); + if (c=='\n') // Stop the row on line breaks + { + iStart++; + break; + } + } + + else //--------[ Start Quote ]-------------------- + + if (c=='\"') + InsideQuote = true; + + iStart++; + } + if (iStart>iWordStart) + AddCSVtoken(ref list, ref Line, iStart, ref iWordStart); + + return list.ToArray(); + } + + static void AddCSVtoken( ref List list, ref string Line, int iEnd, ref int iWordStart) + { + string Text = Line.Substring(iWordStart, iEnd-iWordStart); + iWordStart = iEnd+1; + + Text = Text.Replace("\"\"", "\"" ); + if (Text.Length>1 && Text[0]=='\"' && Text[Text.Length-1]=='\"') + Text = Text.Substring(1, Text.Length-2 ); + + list.Add( Text); + } + + + + #endregion + + #region I2CSV + + public static List ReadI2CSV( string Text ) + { + string[] ColumnSeparator = {"[*]"}; + string[] RowSeparator = {"[ln]"}; + + List CSV = new List(); + foreach (var line in Text.Split (RowSeparator, StringSplitOptions.None)) + CSV.Add (line.Split (ColumnSeparator, StringSplitOptions.None)); + + return CSV; + } + + #endregion + + #region Misc + + public static void ValidateFullTerm( ref string Term ) + { + Term = Term.Replace('\\', '/'); + int First = Term.IndexOf('/'); + if (First<0) + return; + + int second; + while ( (second=Term.LastIndexOf('/')) != First ) + Term = Term.Remove( second,1); + } + + + // this function encodes \r\n and \n into \\n + public static string EncodeString( string str ) + { + if (string.IsNullOrEmpty(str)) + return string.Empty; + + return str.Replace("\r\n", "<\\n>") + .Replace("\r", "<\\n>") + .Replace("\n", "<\\n>"); + } + + public static string DecodeString( string str ) + { + if (string.IsNullOrEmpty(str)) + return string.Empty; + + return str.Replace("<\\n>", "\r\n"); + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizationReader.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizationReader.cs.meta new file mode 100644 index 00000000..e6c09794 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizationReader.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6ec1933af6b4d6947ba69b9bda4260d1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Localize.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Localize.cs new file mode 100644 index 00000000..af16039c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Localize.cs @@ -0,0 +1,518 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; +using UnityEngine.Events; +using Object = UnityEngine.Object; + +#if UNITY_EDITOR +using UnityEditor.Events; +using UnityEditor; +#endif + +namespace TEngine.Localization +{ + [AddComponentMenu("I2/Localization/I2 Localize")] + public class Localize : MonoBehaviour + { + #region Variables: Term + public string Term + { + get { return mTerm; } + set { SetTerm(value); } + } + public string SecondaryTerm + { + get { return mTermSecondary; } + set { SetTerm(null, value); } + } + + public string mTerm = string.Empty, // if Target is a Label, this will be the text, if sprite, this will be the spriteName, etc + mTermSecondary = string.Empty; // if Target is a Label, this will be the font Name, if sprite, this will be the Atlas name, etc + + // This are the terms actually used (will be mTerm/mSecondaryTerm or will get them from the objects if those are missing. e.g. Labels' text and font name) + // This are set when the component starts + [NonSerialized] public string FinalTerm, FinalSecondaryTerm; + + public enum TermModification { DontModify, ToUpper, ToLower, ToUpperFirst, ToTitle/*, CustomRange*/} + public TermModification PrimaryTermModifier = TermModification.DontModify, + SecondaryTermModifier = TermModification.DontModify; + public string TermPrefix, TermSuffix; + + public bool LocalizeOnAwake = true; + + string LastLocalizedLanguage; // Used to avoid Localizing everytime the object is Enabled + +#if UNITY_EDITOR + public ILanguageSource Source; // Source used while in the Editor to preview the Terms (can be of type LanguageSource or LanguageSourceAsset) +#endif + + #endregion + + #region Variables: Target + + public bool IgnoreRTL; // If false, no Right To Left processing will be done + public int MaxCharactersInRTL; // If the language is RTL, the translation will be split in lines not longer than this amount and the RTL fix will be applied per line + public bool IgnoreNumbersInRTL = true; // If the language is RTL, the translation will not convert numbers (will preserve them like: e.g. 123) + + public bool CorrectAlignmentForRTL = true; // If true, when Right To Left language, alignment will be set to Right + + public bool AddSpacesToJoinedLanguages; // Some languages (e.g. Chinese, Japanese and Thai) don't add spaces to their words (all characters are placed toguether), making this variable true, will add spaces to all characters to allow wrapping long texts into multiple lines. + public bool AllowLocalizedParameters=true; + public bool AllowParameters=true; + + #endregion + + #region Variables: References + + public List TranslatedObjects = new List(); // For targets that reference objects (e.g. AudioSource, UITexture,etc) + // this keeps a reference to the possible options. + // If the value is not the name of any of this objects then it will try to load the object from the Resources + + + [NonSerialized] public Dictionary mAssetDictionary = new Dictionary(StringComparer.Ordinal); //This is used to overcome the issue with Unity not serializing Dictionaries + + #endregion + + #region Variable Translation Modifiers + + + public UnityEvent LocalizeEvent = new UnityEvent(); // This allows scripts to modify the translations : e.g. "Player {0} wins" -> "Player Red wins" + + + public static string MainTranslation, SecondaryTranslation; // The callback should use and modify this variables + public static string CallBackTerm, CallBackSecondaryTerm; // during the callback, this will hold the FinalTerm and FinalSecondary to know what terms are originating the translation + public static Localize CurrentLocalizeComponent; // while in the LocalizeCallBack, this points to the Localize calling the callback + + public bool AlwaysForceLocalize; // Force localization when the object gets enabled (useful for callbacks and parameters that change the localization even through the language is the same as in the previous time it was localized) + + [SerializeField] public EventCallback LocalizeCallBack = new EventCallback(); //LocalizeCallBack is deprecated. Please use LocalizeEvent instead. + + #endregion + + #region Variables: Editor Related + public bool mGUI_ShowReferences; + public bool mGUI_ShowTems = true; + public bool mGUI_ShowCallback; + #endregion + + #region Variables: Runtime (LocalizeTarget) + + public ILocalizeTarget mLocalizeTarget; + public string mLocalizeTargetName; // Used to resolve multiple targets in a prefab + + #endregion + + #region Localize + + void Awake() + { + #if UNITY_EDITOR + if (BuildPipeline.isBuildingPlayer) + return; + #endif + + UpdateAssetDictionary(); + FindTarget(); + + if (LocalizeOnAwake) + OnLocalize(); + } + + #if UNITY_EDITOR + void OnValidate() + { + if (LocalizeCallBack.HasCallback()) + { + try + { + var methodInfo = UnityEventBase.GetValidMethodInfo(LocalizeCallBack.Target, LocalizeCallBack.MethodName, Array.Empty()); + + if (methodInfo != null) + { + UnityAction methodDelegate = Delegate.CreateDelegate(typeof(UnityAction), LocalizeCallBack.Target, methodInfo, false) as UnityAction; + if (methodDelegate != null) + UnityEventTools.AddPersistentListener(LocalizeEvent, methodDelegate); + } + } + catch(Exception) + {} + + LocalizeCallBack.Target = null; + LocalizeCallBack.MethodName = null; + } + } + #endif + + void OnEnable() + { + OnLocalize (); + } + + public bool HasCallback() + { + if (LocalizeCallBack.HasCallback()) + return true; + return LocalizeEvent.GetPersistentEventCount() > 0; + } + + public void OnLocalize( bool Force = false ) + { + if (!Force && (!enabled || gameObject==null || !gameObject.activeInHierarchy)) + return; + + if (string.IsNullOrEmpty(LocalizationManager.CurrentLanguage)) + return; + + if (!AlwaysForceLocalize && !Force && !HasCallback() && LastLocalizedLanguage==LocalizationManager.CurrentLanguage) + return; + LastLocalizedLanguage = LocalizationManager.CurrentLanguage; + + // These are the terms actually used (will be mTerm/mSecondaryTerm or will get them from the objects if those are missing. e.g. Labels' text and font name) + if (string.IsNullOrEmpty(FinalTerm) || string.IsNullOrEmpty(FinalSecondaryTerm)) + GetFinalTerms( out FinalTerm, out FinalSecondaryTerm ); + + + bool hasCallback = I2Utils.IsPlaying() && HasCallback(); + + if (!hasCallback && string.IsNullOrEmpty (FinalTerm) && string.IsNullOrEmpty (FinalSecondaryTerm)) + return; + + CurrentLocalizeComponent = this; + CallBackTerm = FinalTerm; + CallBackSecondaryTerm = FinalSecondaryTerm; + MainTranslation = string.IsNullOrEmpty(FinalTerm) || FinalTerm=="-" ? null : LocalizationManager.GetTranslation (FinalTerm, false); + SecondaryTranslation = string.IsNullOrEmpty(FinalSecondaryTerm) || FinalSecondaryTerm == "-" ? null : LocalizationManager.GetTranslation (FinalSecondaryTerm, false); + + if (!hasCallback && /*string.IsNullOrEmpty (MainTranslation)*/ string.IsNullOrEmpty(FinalTerm) && string.IsNullOrEmpty (SecondaryTranslation)) + return; + + { + LocalizeCallBack.Execute (this); // This allows scripts to modify the translations : e.g. "Player {0} wins" -> "Player Red wins" + LocalizeEvent.Invoke(); + if (AllowParameters) + LocalizationManager.ApplyLocalizationParams (ref MainTranslation, gameObject, AllowLocalizedParameters); + } + + if (!FindTarget()) + return; + bool applyRTL = LocalizationManager.IsRight2Left && !IgnoreRTL; + + if (MainTranslation != null) + { + switch (PrimaryTermModifier) + { + case TermModification.ToUpper: MainTranslation = MainTranslation.ToUpper(); break; + case TermModification.ToLower: MainTranslation = MainTranslation.ToLower(); break; + case TermModification.ToUpperFirst: MainTranslation = GoogleTranslation.UppercaseFirst(MainTranslation); break; + case TermModification.ToTitle: MainTranslation = GoogleTranslation.TitleCase(MainTranslation); break; + } + if (!string.IsNullOrEmpty(TermPrefix)) + MainTranslation = applyRTL ? MainTranslation + TermPrefix : TermPrefix + MainTranslation; + if (!string.IsNullOrEmpty(TermSuffix)) + MainTranslation = applyRTL ? TermSuffix + MainTranslation : MainTranslation + TermSuffix; + + if (AddSpacesToJoinedLanguages && LocalizationManager.HasJoinedWords && !string.IsNullOrEmpty(MainTranslation)) + { + var sb = new StringBuilder(); + sb.Append(MainTranslation[0]); + for (int i = 1, imax = MainTranslation.Length; i < imax; ++i) + { + sb.Append(' '); + sb.Append(MainTranslation[i]); + } + + MainTranslation = sb.ToString(); + } + if (applyRTL && mLocalizeTarget.AllowMainTermToBeRTL() && !string.IsNullOrEmpty(MainTranslation)) + MainTranslation = LocalizationManager.ApplyRTLfix(MainTranslation, MaxCharactersInRTL, IgnoreNumbersInRTL); + + } + + if (SecondaryTranslation != null) + { + switch (SecondaryTermModifier) + { + case TermModification.ToUpper: SecondaryTranslation = SecondaryTranslation.ToUpper(); break; + case TermModification.ToLower: SecondaryTranslation = SecondaryTranslation.ToLower(); break; + case TermModification.ToUpperFirst: SecondaryTranslation = GoogleTranslation.UppercaseFirst(SecondaryTranslation); break; + case TermModification.ToTitle: SecondaryTranslation = GoogleTranslation.TitleCase(SecondaryTranslation); break; + } + if (applyRTL && mLocalizeTarget.AllowSecondTermToBeRTL() && !string.IsNullOrEmpty(SecondaryTranslation)) + SecondaryTranslation = LocalizationManager.ApplyRTLfix(SecondaryTranslation); + } + + if (LocalizationManager.HighlightLocalizedTargets) + { + MainTranslation = "LOC:" + FinalTerm; + } + + mLocalizeTarget.DoLocalize( this, MainTranslation, SecondaryTranslation ); + + CurrentLocalizeComponent = null; + } + + #endregion + + #region Finding Target + + public bool FindTarget() + { + if (mLocalizeTarget != null && mLocalizeTarget.IsValid(this)) + return true; + + if (mLocalizeTarget!=null) + { + DestroyImmediate(mLocalizeTarget); + mLocalizeTarget = null; + mLocalizeTargetName = null; + } + + if (!string.IsNullOrEmpty(mLocalizeTargetName)) + { + foreach (var desc in LocalizationManager.mLocalizeTargets) + { + if (mLocalizeTargetName == desc.GetTargetType().ToString()) + { + if (desc.CanLocalize(this)) + mLocalizeTarget = desc.CreateTarget(this); + if (mLocalizeTarget!=null) + return true; + } + } + } + + foreach (var desc in LocalizationManager.mLocalizeTargets) + { + if (!desc.CanLocalize(this)) + continue; + mLocalizeTarget = desc.CreateTarget(this); + mLocalizeTargetName = desc.GetTargetType().ToString(); + if (mLocalizeTarget != null) + return true; + } + + return false; + } + + #endregion + + #region Finding Term + + // Returns the term that will actually be translated + // its either the Term value in this class or the text of the label if there is no term + public void GetFinalTerms( out string primaryTerm, out string secondaryTerm ) + { + primaryTerm = string.Empty; + secondaryTerm = string.Empty; + + if (!FindTarget()) + return; + + + // if either the primary or secondary term is missing, get them. (e.g. from the label's text and font name) + if (mLocalizeTarget != null) + { + mLocalizeTarget.GetFinalTerms(this, mTerm, mTermSecondary, out primaryTerm, out secondaryTerm); + primaryTerm = I2Utils.GetValidTermName(primaryTerm); + } + + // If there are values already set, go with those + if (!string.IsNullOrEmpty(mTerm)) + primaryTerm = mTerm; + + if (!string.IsNullOrEmpty(mTermSecondary)) + secondaryTerm = mTermSecondary; + + if (primaryTerm != null) + primaryTerm = primaryTerm.Trim(); + if (secondaryTerm != null) + secondaryTerm = secondaryTerm.Trim(); + } + + public string GetMainTargetsText() + { + string primary = null, secondary = null; + + if (mLocalizeTarget!=null) + mLocalizeTarget.GetFinalTerms( this, null, null, out primary, out secondary ); + + return string.IsNullOrEmpty(primary) ? mTerm : primary; + } + + public void SetFinalTerms( string Main, string Secondary, out string primaryTerm, out string secondaryTerm, bool RemoveNonASCII ) + { + primaryTerm = RemoveNonASCII ? I2Utils.GetValidTermName(Main) : Main; + secondaryTerm = Secondary; + } + + #endregion + + #region Misc + + public void SetTerm (string primary) + { + if (!string.IsNullOrEmpty(primary)) + FinalTerm = mTerm = primary; + + OnLocalize (true); + } + + public void SetTerm(string primary, string secondary ) + { + if (!string.IsNullOrEmpty(primary)) + FinalTerm = mTerm = primary; + FinalSecondaryTerm = mTermSecondary = secondary; + + OnLocalize(true); + } + + internal T GetSecondaryTranslatedObj( ref string mainTranslation, ref string secondaryTranslation ) where T: Object + { + string newMain, newSecond; + + //--[ Allow main translation to override Secondary ]------------------- + DeserializeTranslation(mainTranslation, out newMain, out newSecond); + + T obj = null; + + if (!string.IsNullOrEmpty(newSecond)) + { + obj = GetObject(newSecond); + if (obj != null) + { + mainTranslation = newMain; + secondaryTranslation = newSecond; + } + } + + if (obj == null) + obj = GetObject(secondaryTranslation); + + return obj; + } + + public void UpdateAssetDictionary() + { + TranslatedObjects.RemoveAll(x => x == null); + mAssetDictionary = TranslatedObjects.Distinct() + .GroupBy(o => o.name) + .ToDictionary(g => g.Key, g => g.First()); + } + + internal T GetObject( string Translation) where T: Object + { + if (string.IsNullOrEmpty (Translation)) + return null; + T obj = GetTranslatedObject(Translation); + + //if (obj==null) + //{ + // Remove path and search by name + //int Index = Translation.LastIndexOfAny("/\\".ToCharArray()); + //if (Index>=0) + //{ + // Translation = Translation.Substring(Index+1); + // obj = GetTranslatedObject(Translation); + //} + //} + return obj; + } + + T GetTranslatedObject( string Translation) where T: Object + { + T Obj = FindTranslatedObject(Translation); + /*if (Obj == null) + return null; + + if ((Obj as T) != null) + return Obj as T; + + // If the found Obj is not of type T, then try finding a component inside + if (Obj as Component != null) + return (Obj as Component).GetComponent(typeof(T)) as T; + + if (Obj as GameObject != null) + return (Obj as GameObject).GetComponent(typeof(T)) as T; + */ + return Obj; + } + + + // translation format: "[secondary]value" [secondary] is optional + void DeserializeTranslation( string translation, out string value, out string secondary ) + { + if (!string.IsNullOrEmpty(translation) && translation.Length>1 && translation[0]=='[') + { + int Index = translation.IndexOf(']'); + if (Index>0) + { + secondary = translation.Substring(1, Index-1); + value = translation.Substring(Index+1); + return; + } + } + value = translation; + secondary = string.Empty; + } + + public T FindTranslatedObject( string value) where T : Object + { + if (string.IsNullOrEmpty(value)) + return null; + + if (mAssetDictionary == null || mAssetDictionary.Count != TranslatedObjects.Count) + { + UpdateAssetDictionary(); + } + + foreach (var kvp in mAssetDictionary) + { + if (kvp.Value is T && value.EndsWith(kvp.Key, StringComparison.OrdinalIgnoreCase)) + { + // Check if the value is just the name or has a path + if (string.Compare(value, kvp.Key, StringComparison.OrdinalIgnoreCase)==0) + return (T) kvp.Value; + + // Check if the path matches + //Resources.get TranslatedObjects[i]. + } + } + + T obj = LocalizationManager.FindAsset(value) as T; + if (obj) + return obj; + + obj = ResourceManager.pInstance.GetAsset(value); + return obj; + } + + public bool HasTranslatedObject( Object Obj ) + { + if (TranslatedObjects.Contains(Obj)) + return true; + return ResourceManager.pInstance.HasAsset(Obj); + + } + + public void AddTranslatedObject( Object Obj ) + { + if (TranslatedObjects.Contains(Obj)) + return; + TranslatedObjects.Add(Obj); + UpdateAssetDictionary(); + } + + #endregion + + #region Utilities + // This can be used to set the language when a button is clicked + public void SetGlobalLanguage( string Language ) + { + LocalizationManager.CurrentLanguage = Language; + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Localize.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Localize.cs.meta new file mode 100644 index 00000000..af8cbcc7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Localize.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 344445a89b4f74a0e9a0a766903df87e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizeDropdown.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizeDropdown.cs new file mode 100644 index 00000000..ba040203 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizeDropdown.cs @@ -0,0 +1,111 @@ +using System.Collections.Generic; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace TEngine.Localization +{ + #if !UNITY_5_0 && !UNITY_5_1 + [AddComponentMenu("I2/Localization/Localize Dropdown")] + public class LocalizeDropdown : MonoBehaviour + { + public List _Terms = new List(); + + public void Start() + { + LocalizationManager.OnLocalizeEvent += OnLocalize; + OnLocalize(); + } + + public void OnDestroy() + { + LocalizationManager.OnLocalizeEvent -= OnLocalize; + } + + void OnEnable() + { + if (_Terms.Count == 0) + FillValues(); + OnLocalize (); + } + + public void OnLocalize() + { + if (!enabled || gameObject==null || !gameObject.activeInHierarchy) + return; + + if (string.IsNullOrEmpty(LocalizationManager.CurrentLanguage)) + return; + + UpdateLocalization(); + } + + void FillValues() + { + var _Dropdown = GetComponent(); + if (_Dropdown == null && I2Utils.IsPlaying()) + { + #if TextMeshPro + FillValuesTMPro(); + #endif + return; + } + + foreach (var term in _Dropdown.options) + { + _Terms.Add(term.text); + } + } + + public void UpdateLocalization() + { + var _Dropdown = GetComponent(); + if (_Dropdown == null) + { + #if TextMeshPro + UpdateLocalizationTMPro(); + #endif + return; + } + + _Dropdown.options.Clear(); + foreach (var term in _Terms) + { + var translation = LocalizationManager.GetTranslation(term); + _Dropdown.options.Add( new Dropdown.OptionData( translation ) ); + } + _Dropdown.RefreshShownValue(); + } + + #if TextMeshPro + public void UpdateLocalizationTMPro() + { + var _Dropdown = GetComponent(); + if (_Dropdown == null) + return; + + _Dropdown.options.Clear(); + foreach (var term in _Terms) + { + var translation = LocalizationManager.GetTranslation(term); + _Dropdown.options.Add(new TMP_Dropdown.OptionData(translation)); + } + _Dropdown.RefreshShownValue(); + } + + void FillValuesTMPro() + { + var _Dropdown = GetComponent(); + if (_Dropdown == null) + return; + + foreach (var term in _Dropdown.options) + { + _Terms.Add(term.text); + } + } +#endif + + } +#endif +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizeDropdown.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizeDropdown.cs.meta new file mode 100644 index 00000000..f5f29d20 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/LocalizeDropdown.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a5379d3aeaf18a24fa23c26a749edfe5 +timeCreated: 1466568092 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager.meta new file mode 100644 index 00000000..616377c8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ba131beaf0aba9d4084aff4ea6e742c3 +folderAsset: yes +timeCreated: 1516397531 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager.cs new file mode 100644 index 00000000..4e09a8ad --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public static partial class LocalizationManager + { + + #region Variables: Misc + + #endregion + + public static void InitializeIfNeeded() + { + #if UNITY_EDITOR + #if UNITY_2017_2_OR_NEWER + EditorApplication.playModeStateChanged -= OnEditorPlayModeStateChanged; + EditorApplication.playModeStateChanged += OnEditorPlayModeStateChanged; + #else + UnityEditor.EditorApplication.playmodeStateChanged -= OldOnEditorPlayModeStateChanged; + UnityEditor.EditorApplication.playmodeStateChanged += OldOnEditorPlayModeStateChanged; + #endif + #endif + + if (string.IsNullOrEmpty(mCurrentLanguage) || Sources.Count == 0) + { + AutoLoadGlobalParamManagers(); + UpdateSources(); + SelectStartupLanguage(); + } + } + + public static string GetVersion() + { + return "2.8.22 f4"; + } + + public static int GetRequiredWebServiceVersion() + { + return 5; + } + + public static string GetWebServiceURL( LanguageSourceData source = null ) + { + if (source != null && !string.IsNullOrEmpty(source.Google_WebServiceURL)) + return source.Google_WebServiceURL; + + InitializeIfNeeded(); + for (int i = 0; i < Sources.Count; ++i) + if (Sources[i] != null && !string.IsNullOrEmpty(Sources[i].Google_WebServiceURL)) + return Sources[i].Google_WebServiceURL; + return string.Empty; + } + +#if UNITY_EDITOR + #if UNITY_2017_2_OR_NEWER + static void OnEditorPlayModeStateChanged( PlayModeStateChange stateChange ) + { + if (stateChange != PlayModeStateChange.ExitingPlayMode) + return; + #else + static void OldOnEditorPlayModeStateChanged() + { + if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode) + return; + #endif + + OnLocalizeEvent = null; + + foreach (var source in Sources) + { + source.LoadAllLanguages(true); + } + try + { + var tempPath = Application.temporaryCachePath; + + foreach (var file in Directory.GetFiles(tempPath).Where(f => f.Contains("LangSource_") && f.EndsWith(".loc", StringComparison.Ordinal))) + { + File.Delete(file); + } + } + catch(Exception) + { + } + } +#endif + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager.cs.meta new file mode 100644 index 00000000..89de7d0b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: dd42f89f650a540d9bd641f752368e27 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Language.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Language.cs new file mode 100644 index 00000000..3cdb0ecc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Language.cs @@ -0,0 +1,348 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; + +namespace TEngine.Localization +{ + public static partial class LocalizationManager + { + #region Variables: CurrentLanguage + + public static string CurrentLanguage + { + get { + InitializeIfNeeded(); + return mCurrentLanguage; + } + set { + InitializeIfNeeded(); + string SupportedLanguage = GetSupportedLanguage(value); + if (!string.IsNullOrEmpty(SupportedLanguage) && mCurrentLanguage != SupportedLanguage) + { + SetLanguageAndCode(SupportedLanguage, GetLanguageCode(SupportedLanguage)); + } + } + } + public static string CurrentLanguageCode + { + get { + InitializeIfNeeded(); + return mLanguageCode; } + set { + InitializeIfNeeded(); + if (mLanguageCode != value) + { + string LanName = GetLanguageFromCode(value); + if (!string.IsNullOrEmpty(LanName)) + SetLanguageAndCode(LanName, value); + } + } + } + + // "English (United States)" (get returns "United States") + // when set "Canada", the new language code will be "English (Canada)" + public static string CurrentRegion + { + get { + var Lan = CurrentLanguage; + int idx = Lan.IndexOfAny("/\\".ToCharArray()); + if (idx > 0) + return Lan.Substring(idx + 1); + + idx = Lan.IndexOfAny("[(".ToCharArray()); + int idx2 = Lan.LastIndexOfAny("])".ToCharArray()); + if (idx > 0 && idx != idx2) + return Lan.Substring(idx + 1, idx2 - idx - 1); + return string.Empty; + } + set { + var Lan = CurrentLanguage; + int idx = Lan.IndexOfAny("/\\".ToCharArray()); + if (idx > 0) + { + CurrentLanguage = Lan.Substring(idx + 1) + value; + return; + } + + idx = Lan.IndexOfAny("[(".ToCharArray()); + int idx2 = Lan.LastIndexOfAny("])".ToCharArray()); + if (idx > 0 && idx != idx2) + Lan = Lan.Substring(idx); + + CurrentLanguage = Lan + "(" + value + ")"; + } + } + + // "en-US" (get returns "US") (when set "CA", the new language code will be "en-CA") + public static string CurrentRegionCode + { + get { + var code = CurrentLanguageCode; + int idx = code.IndexOfAny(" -_/\\".ToCharArray()); + return idx < 0 ? string.Empty : code.Substring(idx + 1); + } + set { + var code = CurrentLanguageCode; + int idx = code.IndexOfAny(" -_/\\".ToCharArray()); + if (idx > 0) + code = code.Substring(0, idx); + + CurrentLanguageCode = code + "-" + value; + } + } + + public static CultureInfo CurrentCulture + { + get + { + return mCurrentCulture; + } + } + + static string mCurrentLanguage; + static string mLanguageCode; + static CultureInfo mCurrentCulture; + static bool mChangeCultureInfo; + + public static bool IsRight2Left; + public static bool HasJoinedWords; // Some languages (e.g. Chinese, Japanese and Thai) don't add spaces to their words (all characters are placed toguether) + + #endregion + + public static void SetLanguageAndCode(string LanguageName, string LanguageCode, bool RememberLanguage = true, bool Force = false) + { + if (mCurrentLanguage != LanguageName || mLanguageCode != LanguageCode || Force) + { + if (RememberLanguage) + PersistentStorage.SetSetting_String("I2 Language", LanguageName); + mCurrentLanguage = LanguageName; + mLanguageCode = LanguageCode; + mCurrentCulture = CreateCultureForCode(LanguageCode); + if (mChangeCultureInfo) + SetCurrentCultureInfo(); + + IsRight2Left = IsRTL(mLanguageCode); + HasJoinedWords = GoogleLanguages.LanguageCode_HasJoinedWord(mLanguageCode); + LocalizeAll(Force); + } + } + + static CultureInfo CreateCultureForCode(string code) + { +#if !NETFX_CORE + try + { + return CultureInfo.CreateSpecificCulture(code); + } + catch (Exception) + { + return CultureInfo.InvariantCulture; + } +#else + return CultureInfo.InvariantCulture; +#endif + } + + public static void EnableChangingCultureInfo(bool bEnable) + { + if (!mChangeCultureInfo && bEnable) + SetCurrentCultureInfo(); + mChangeCultureInfo = bEnable; + } + + static void SetCurrentCultureInfo() + { + #if !NETFX_CORE + Thread.CurrentThread.CurrentCulture = mCurrentCulture; + #endif + } + + + static void SelectStartupLanguage() + { + if (Sources.Count == 0) + return; + + // Use the system language if there is a source with that language, + // or pick any of the languages provided by the sources + + string SavedLanguage = PersistentStorage.GetSetting_String("I2 Language", string.Empty); + string SysLanguage = GetCurrentDeviceLanguage(); + + // Try selecting the System Language + // But fallback to the first language found if the System Language is not available in any source + + if (!string.IsNullOrEmpty(SavedLanguage) && HasLanguage(SavedLanguage, Initialize: false, SkipDisabled:true)) + { + SetLanguageAndCode(SavedLanguage, GetLanguageCode(SavedLanguage)); + return; + } + + if (!Sources [0].IgnoreDeviceLanguage) + { + // Check if the device language is supported. + // Also recognize when not region is set ("English (United State") will be used if sysLanguage is "English") + string ValidLanguage = GetSupportedLanguage (SysLanguage, true); + if (!string.IsNullOrEmpty (ValidLanguage)) { + SetLanguageAndCode (ValidLanguage, GetLanguageCode (ValidLanguage), false); + return; + } + } + + //--[ Use first language that its not disabled ]----------- + for (int i = 0, imax = Sources.Count; i < imax; ++i) + if (Sources[i].mLanguages.Count > 0) + { + for (int j = 0; j < Sources[i].mLanguages.Count; ++j) + if (Sources[i].mLanguages[j].IsEnabled()) + { + SetLanguageAndCode(Sources[i].mLanguages[j].Name, Sources[i].mLanguages[j].Code, false); + return; + } + } + } + + + public static bool HasLanguage( string Language, bool AllowDiscartingRegion = true, bool Initialize=true, bool SkipDisabled=true ) + { + if (Initialize) + InitializeIfNeeded(); + + // First look for an exact match + for (int i=0, imax=Sources.Count; i=0) + return true; + + // Then allow matching "English (Canada)" to "english" + if (AllowDiscartingRegion) + { + for (int i=0, imax=Sources.Count; i=0) + return true; + } + return false; + } + + // Returns the provided language or a similar one without the Region + //(e.g. "English (Canada)" could be mapped to "english" or "English (United States)" if "English (Canada)" is not found + public static string GetSupportedLanguage( string Language, bool ignoreDisabled=false ) + { + // First try finding the language that matches one of the official languages + string code = GoogleLanguages.GetLanguageCode(Language); + if (!string.IsNullOrEmpty(code)) + { + // First try finding if the exact language code is in one source + for (int i = 0, imax = Sources.Count; i < imax; ++i) + { + int Idx = Sources[i].GetLanguageIndexFromCode(code, true, ignoreDisabled); + if (Idx >= 0) + return Sources[i].mLanguages[Idx].Name; + } + + // If not, try checking without the region + for (int i = 0, imax = Sources.Count; i < imax; ++i) + { + int Idx = Sources[i].GetLanguageIndexFromCode(code, false, ignoreDisabled); + if (Idx >= 0) + return Sources[i].mLanguages[Idx].Name; + } + } + + // If not found, then try finding an exact match for the name + for (int i=0, imax=Sources.Count; i=0) + return Sources[i].mLanguages[Idx].Name; + } + + // Then allow matching "English (Canada)" to "english" + for (int i=0, imax=Sources.Count; i=0) + return Sources[i].mLanguages[Idx].Name; + } + + return string.Empty; + } + + public static string GetLanguageCode( string Language ) + { + if (Sources.Count==0) + UpdateSources(); + for (int i=0, imax=Sources.Count; i=0) + return Sources[i].mLanguages[Idx].Code; + } + return string.Empty; + } + + public static string GetLanguageFromCode( string Code, bool exactMatch=true ) + { + if (Sources.Count==0) + UpdateSources(); + for (int i=0, imax=Sources.Count; i=0) + return Sources[i].mLanguages[Idx].Name; + } + return string.Empty; + } + + + public static List GetAllLanguages ( bool SkipDisabled = true ) + { + if (Sources.Count==0) + UpdateSources(); + List Languages = new List (); + for (int i=0, imax=Sources.Count; i!Languages.Contains(x))); + } + return Languages; + } + + public static List GetAllLanguagesCode(bool allowRegions=true, bool SkipDisabled = true) + { + List Languages = new List(); + for (int i = 0, imax = Sources.Count; i < imax; ++i) + { + Languages.AddRange(Sources[i].GetLanguagesCode(allowRegions, SkipDisabled).Where(x => !Languages.Contains(x))); + } + return Languages; + } + + public static bool IsLanguageEnabled(string Language) + { + for (int i = 0, imax = Sources.Count; i < imax; ++i) + if (!Sources[i].IsLanguageEnabled(Language)) + return false; + return true; + } + + static void LoadCurrentLanguage() + { + for (int i = 0; i < Sources.Count; ++i) + { + var iCurrentLang = Sources[i].GetLanguageIndex(mCurrentLanguage, true, false); + Sources[i].LoadLanguage(iCurrentLang, true, true, true, false); + } + } + + + // This function should only be called from within the Localize Inspector to temporaly preview that Language + public static void PreviewLanguage(string NewLanguage) + { + mCurrentLanguage = NewLanguage; + mLanguageCode = GetLanguageCode(mCurrentLanguage); + IsRight2Left = IsRTL(mLanguageCode); + HasJoinedWords = GoogleLanguages.LanguageCode_HasJoinedWord(mLanguageCode); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Language.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Language.cs.meta new file mode 100644 index 00000000..556a3911 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Language.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 7d629295da7add24e9465e25cd212bf5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Parameters.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Parameters.cs new file mode 100644 index 00000000..99e5ddc1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Parameters.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace TEngine.Localization +{ + public static partial class LocalizationManager + { + #region Variables: Misc + + public static List ParamManagers = new List(); + + + // returns true if this replaces the normal ApplyLocalizationParams + // returns false if after running this function the manager should also run the default ApplyLocalizationParams to replace parameters + public delegate bool FnCustomApplyLocalizationParams(ref string translation, _GetParam getParam, bool allowLocalizedParameters); + public static FnCustomApplyLocalizationParams CustomApplyLocalizationParams; + #endregion + + #region Parameters + + public delegate object _GetParam(string param); + + public static void AutoLoadGlobalParamManagers() + { + foreach (var manager in Object.FindObjectsOfType()) + { + if (manager._IsGlobalManager && !ParamManagers.Contains(manager)) + { + Debug.Log(manager); + ParamManagers.Add(manager); + } + } + } + + public static void ApplyLocalizationParams(ref string translation, bool allowLocalizedParameters = true) + { + ApplyLocalizationParams(ref translation, p => GetLocalizationParam(p, null), allowLocalizedParameters); + } + + + public static void ApplyLocalizationParams(ref string translation, GameObject root, bool allowLocalizedParameters = true) + { + ApplyLocalizationParams(ref translation, p => GetLocalizationParam(p, root), allowLocalizedParameters); + } + + public static void ApplyLocalizationParams(ref string translation, Dictionary parameters, bool allowLocalizedParameters = true) + { + ApplyLocalizationParams(ref translation, p => { + object o = null; + if (parameters.TryGetValue(p, out o)) + return o; + return null; + }, allowLocalizedParameters); + } + + + public static void ApplyLocalizationParams(ref string translation, _GetParam getParam, bool allowLocalizedParameters=true) + { + if (translation == null) + return; + + bool skip_processing = CustomApplyLocalizationParams!=null && CustomApplyLocalizationParams.Invoke(ref translation, getParam, allowLocalizedParameters); + if (skip_processing) return; + + string pluralType=null; + int idx0 = 0; + int idx1 = translation.Length; + + int index = 0; + while (index>=0 && index0 && isubParam= 0) + { + result = termData.GetTranslation(idx); + } + } + } + + var paramTag = translation.Substring(iParamStart, iParamEnd - iParamStart + 2); + translation = translation.Replace(paramTag, result); + + int amount = 0; + if (int.TryParse(result, out amount)) + { + pluralType = GoogleLanguages.GetPluralType(CurrentLanguageCode, amount).ToString(); + } + + index = iParamStart + result.Length; + } + else + { + index = iParamEnd + 2; + } + } + + if (pluralType != null) + { + var tag = "[i2p_" + pluralType + "]"; + idx0 = translation.IndexOf(tag, StringComparison.OrdinalIgnoreCase); + if (idx0 < 0) idx0 = 0; + else idx0 += tag.Length; + + idx1 = translation.IndexOf("[i2p_", idx0 + 1, StringComparison.OrdinalIgnoreCase); + if (idx1 < 0) idx1 = translation.Length; + + translation = translation.Substring(idx0, idx1 - idx0); + } + } + + internal static string GetLocalizationParam(string ParamName, GameObject root) + { + string result = null; + if (root) + { + var components = root.GetComponents(); + for (int i = 0, imax = components.Length; i < imax; ++i) + { + var manager = components[i] as ILocalizationParamsManager; + if (manager != null && components[i].enabled) + { + result = manager.GetParameterValue(ParamName); + if (result != null) + return result; + } + } + } + + for (int i = 0, imax = ParamManagers.Count; i < imax; ++i) + { + result = ParamManagers[i].GetParameterValue(ParamName); + if (result != null) + return result; + } + + return null; + } + + #endregion + + #region Plural + + private static string GetPluralType( MatchCollection matches, string langCode, _GetParam getParam) + { + for (int i = 0, nMatches = matches.Count; i < nMatches; ++i) + { + var match = matches[i]; + var param = match.Groups[match.Groups.Count - 1].Value; + var result = (string)getParam(param); + if (result == null) + continue; + + int amount = 0; + if (!int.TryParse (result, out amount)) + continue; + + var pluralType = GoogleLanguages.GetPluralType(langCode, amount); + return pluralType.ToString (); + } + return null; + } + + #endregion + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Parameters.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Parameters.cs.meta new file mode 100644 index 00000000..703501dd --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Parameters.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9bdcae51172bbb8458cf8c42f889c2a0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_RTL.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_RTL.cs new file mode 100644 index 00000000..f84b9594 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_RTL.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; + +namespace TEngine.Localization +{ + public static partial class LocalizationManager + { + static string[] LanguagesRTL = {"ar-DZ", "ar","ar-BH","ar-EG","ar-IQ","ar-JO","ar-KW","ar-LB","ar-LY","ar-MA","ar-OM","ar-QA","ar-SA","ar-SY","ar-TN","ar-AE","ar-YE", + "fa", "he","ur","ji"}; + + public static string ApplyRTLfix(string line) { return ApplyRTLfix(line, 0, true); } + public static string ApplyRTLfix(string line, int maxCharacters, bool ignoreNumbers) + { + if (string.IsNullOrEmpty(line)) + return line; + + // Fix !, ? and . signs not set correctly + char firstC = line[0]; + if (firstC == '!' || firstC == '.' || firstC == '?') + line = line.Substring(1) + firstC; + + int tagStart = -1, tagEnd = 0; + + // Find all Tags (and Numbers if ignoreNumbers is true) + int tagBase = 0xFFFB; + tagEnd = 0; + var tags = new List(); + while (I2Utils.FindNextTag(line, tagEnd, out tagStart, out tagEnd)) + { + char tag = (char)(tagBase - tags.Count); + tags.Add(line.Substring(tagStart, tagEnd - tagStart + 1)); + + line = line.Substring(0, tagStart) + tag + line.Substring(tagEnd + 1); + tagEnd = tagStart + 1; + } + + // Split into lines and fix each line + line = line.Replace("\r\n", "\n"); + line = I2Utils.SplitLine(line, maxCharacters); + line = RTLFixer.Fix(line, true, !ignoreNumbers); + + + // Restore all tags + + for (int i = 0; i < tags.Count; i++) + { + string old_tag = ((char)(tagBase - i)).ToString(); + string new_tag = I2Utils.ReverseText(tags[i]); + + line = line.Replace(old_tag, new_tag); + } + + return line; + } + + + public static string FixRTL_IfNeeded(string text, int maxCharacters = 0, bool ignoreNumber=false) + { + if (IsRight2Left) + return ApplyRTLfix(text, maxCharacters, ignoreNumber); + return text; + } + + public static bool IsRTL(string Code) + { + return Array.IndexOf(LanguagesRTL, Code)>=0; + } + } + +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_RTL.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_RTL.cs.meta new file mode 100644 index 00000000..bd1ca3c3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_RTL.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d33b5082085040d44ab79b83d25bffee +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Sources.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Sources.cs new file mode 100644 index 00000000..f6dbd915 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Sources.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace TEngine.Localization +{ + public static partial class LocalizationManager + { + + #region Variables: Misc + + public static List Sources = new List(); + public static string[] GlobalSources = { "I2Languages" }; + + #endregion + + #region Sources + + public static bool UpdateSources() + { + // UnregisterDeletededSources(); + // RegisterSourceInResources(); + // RegisterSceneSources(); +#if UNITY_EDITOR + if (!I2Utils.IsPlaying()) + { + RegisterSourceInEditor(); + } +#endif + return Sources.Count>0; + } + + static void UnregisterDeletededSources() + { + // Delete sources that were part of another scene and not longer available + for (int i=Sources.Count-1; i>=0; --i) + if (Sources[i] == null) + RemoveSource( Sources[i] ); + } + +#if UNITY_EDITOR + public static void RegisterSourceInEditor() + { + var sourceAsset = GetEditorAsset(); + if (sourceAsset == null) return; + + if (sourceAsset && !Sources.Contains(sourceAsset.mSource)) + { + if (!sourceAsset.mSource.mIsGlobalSource) + sourceAsset.mSource.mIsGlobalSource = true; + sourceAsset.mSource.owner = sourceAsset; + AddSource(sourceAsset.mSource); + } + } + + private static LanguageSourceAsset m_LastLanguageSourceAsset; + + public static LanguageSourceAsset GetEditorAsset(bool force = false) + { + if (m_LastLanguageSourceAsset != null && !force) + { + return m_LastLanguageSourceAsset; + } + + Debug.Log("I2LocalizationManager 加载编辑器资源数据"); + var sourceAsset = UnityEditor.AssetDatabase.LoadAssetAtPath(DefaultLocalizationHelper.I2GlobalSourcesEditorPath); + if (sourceAsset == null) + { + Debug.LogError($"错误 没有找到编辑器下的资源 {DefaultLocalizationHelper.I2GlobalSourcesEditorPath}"); + return null; + } + + m_LastLanguageSourceAsset = sourceAsset; + return sourceAsset; + } + +#endif + + static void RegisterSceneSources() + { + LanguageSource[] sceneSources = (LanguageSource[])Resources.FindObjectsOfTypeAll( typeof(LanguageSource) ); + foreach (LanguageSource source in sceneSources) + if (!Sources.Contains(source.mSource)) + { + if (source.mSource.owner == null) + source.mSource.owner = source; + AddSource( source.mSource ); + } + } + + static void RegisterSourceInResources() + { + // Find the Source that its on the Resources Folder + foreach (string SourceName in GlobalSources) + { + LanguageSourceAsset sourceAsset = ResourceManager.pInstance.GetAsset(SourceName); + + if (sourceAsset && !Sources.Contains(sourceAsset.mSource)) + { + if (!sourceAsset.mSource.mIsGlobalSource) + sourceAsset.mSource.mIsGlobalSource = true; + sourceAsset.mSource.owner = sourceAsset; + AddSource(sourceAsset.mSource); + } + } + } + + public static Func Callback_AllowSyncFromGoogle = null; + static bool AllowSyncFromGoogle(LanguageSourceData Source) + { + if (Callback_AllowSyncFromGoogle == null) + return true; + return Callback_AllowSyncFromGoogle.Invoke(Source); + } + + internal static void AddSource ( LanguageSourceData Source ) + { + if (Sources.Contains (Source)) + return; + + Sources.Add( Source ); + + if (Source.HasGoogleSpreadsheet() && Source.GoogleUpdateFrequency != LanguageSourceData.eGoogleUpdateFrequency.Never && AllowSyncFromGoogle(Source)) + { + #if !UNITY_EDITOR + Source.Import_Google_FromCache(); + bool justCheck = false; + #else + bool justCheck=true; + #endif + if (Source.GoogleUpdateDelay > 0) + CoroutineManager.Start( Delayed_Import_Google(Source, Source.GoogleUpdateDelay, justCheck) ); + else + Source.Import_Google(false, justCheck); + } + + //if (force) + { + for (int i = 0; i < Source.mLanguages.Count; ++i) + Source.mLanguages[i].SetLoaded(true); + } + + if (Source.mDictionary.Count==0) + Source.UpdateDictionary(true); + } + + static IEnumerator Delayed_Import_Google ( LanguageSourceData source, float delay, bool justCheck ) + { + yield return new WaitForSeconds( delay ); + if (source != null) // handle cases where the source is already deleted + { + source.Import_Google(false, justCheck); + } + } + + internal static void RemoveSource (LanguageSourceData Source ) + { + //Debug.Log ("RemoveSource " + Source+" " + Source.GetInstanceID()); + Sources.Remove( Source ); + } + + public static bool IsGlobalSource( string SourceName ) + { + return Array.IndexOf(GlobalSources, SourceName)>=0; + } + + public static LanguageSourceData GetSourceContaining( string term, bool fallbackToFirst = true ) + { + if (!string.IsNullOrEmpty(term)) + { + for (int i=0, imax=Sources.Count; i0 ? Sources[0] : null; + } + + public static Object FindAsset (string value) + { + for (int i=0, imax=Sources.Count; i("getDefault"); + mCurrentDeviceLanguage = locale.Call("toString"); + //https://stackoverflow.com/questions/4212320/get-the-current-language-in-device + + + if (!string.IsNullOrEmpty(mCurrentDeviceLanguage)) + { + mCurrentDeviceLanguage = mCurrentDeviceLanguage.Replace('_', '-'); + mCurrentDeviceLanguage = GoogleLanguages.GetLanguageName(mCurrentDeviceLanguage, true, true); + if (!string.IsNullOrEmpty(mCurrentDeviceLanguage)) + return; + } + } + catch (System.Exception) + { + } + #endif + + mCurrentDeviceLanguage = Application.systemLanguage.ToString(); + if (mCurrentDeviceLanguage == "ChineseSimplified") mCurrentDeviceLanguage = "Chinese (Simplified)"; + if (mCurrentDeviceLanguage == "ChineseTraditional") mCurrentDeviceLanguage = "Chinese (Traditional)"; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_SystemLanguage.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_SystemLanguage.cs.meta new file mode 100644 index 00000000..42447d5b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_SystemLanguage.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: fd54e24a8c653f341a9540011ba06f01 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Targets.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Targets.cs new file mode 100644 index 00000000..64b0a357 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Targets.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace TEngine.Localization +{ + public static partial class LocalizationManager + { + + #region Variables: Misc + + public static List mLocalizeTargets = new List(); + + #endregion + + public static void RegisterTarget( ILocalizeTargetDescriptor desc ) + { + if (mLocalizeTargets.FindIndex(x => x.Name == desc.Name) != -1) + return; + + for (int i = 0; i < mLocalizeTargets.Count; ++i) + { + if (mLocalizeTargets[i].Priority > desc.Priority) + { + mLocalizeTargets.Insert(i, desc); + return; + } + } + mLocalizeTargets.Add(desc); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Targets.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Targets.cs.meta new file mode 100644 index 00000000..83dae7bf --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Targets.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 84ead5dc664fd394490f4874012ed099 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Translation.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Translation.cs new file mode 100644 index 00000000..26326745 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Manager/LocalizationManager_Translation.cs @@ -0,0 +1,225 @@ +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public static partial class LocalizationManager + { + + #region Variables: Misc + + public delegate void OnLocalizeCallback(); + public static event OnLocalizeCallback OnLocalizeEvent; + + static bool mLocalizeIsScheduled; + static bool mLocalizeIsScheduledWithForcedValue; + + public static bool HighlightLocalizedTargets = false; + + + #endregion + + public static string GetTranslation(string Term, bool FixForRTL = true, int maxLineLengthForRTL = 0, bool ignoreRTLnumbers = true, bool applyParameters = false, GameObject localParametersRoot = null, string overrideLanguage = null, bool allowLocalizedParameters=true) + { + string Translation = null; + TryGetTranslation(Term, out Translation, FixForRTL, maxLineLengthForRTL, ignoreRTLnumbers, applyParameters, localParametersRoot, overrideLanguage, allowLocalizedParameters); + + return Translation; + } + public static string GetTermTranslation(string Term, bool FixForRTL = true, int maxLineLengthForRTL = 0, bool ignoreRTLnumbers = true, bool applyParameters = false, GameObject localParametersRoot = null, string overrideLanguage = null, bool allowLocalizedParameters=true) + { + return GetTranslation(Term, FixForRTL, maxLineLengthForRTL, ignoreRTLnumbers, applyParameters, localParametersRoot, overrideLanguage, allowLocalizedParameters); + } + + + public static bool TryGetTranslation(string Term, out string Translation, bool FixForRTL = true, int maxLineLengthForRTL = 0, bool ignoreRTLnumbers = true, bool applyParameters = false, GameObject localParametersRoot = null, string overrideLanguage = null, bool allowLocalizedParameters=true) + { + Translation = null; + if (string.IsNullOrEmpty(Term)) + return false; + + InitializeIfNeeded(); + + for (int i = 0, imax = Sources.Count; i < imax; ++i) + { + if (Sources[i].TryGetTranslation(Term, out Translation, overrideLanguage)) + { + if (applyParameters) + ApplyLocalizationParams(ref Translation, localParametersRoot, allowLocalizedParameters); + + if (IsRight2Left && FixForRTL) + Translation = ApplyRTLfix(Translation, maxLineLengthForRTL, ignoreRTLnumbers); + return true; + } + } + + return false; + } + + public static T GetTranslatedObject( string AssetName, Localize optionalLocComp=null) where T : Object + { + if (optionalLocComp != null) + { + return optionalLocComp.FindTranslatedObject(AssetName); + } + + T obj = FindAsset(AssetName) as T; + if (obj) + return obj; + + obj = ResourceManager.pInstance.GetAsset(AssetName); + return obj; + } + + public static T GetTranslatedObjectByTermName( string Term, Localize optionalLocComp=null) where T : Object + { + string translation = GetTranslation(Term, FixForRTL: false); + return GetTranslatedObject(translation); + } + + + public static string GetAppName(string languageCode) + { + if (!string.IsNullOrEmpty(languageCode)) + { + for (int i = 0; i < Sources.Count; ++i) + { + if (string.IsNullOrEmpty(Sources[i].mTerm_AppName)) + continue; + + int langIdx = Sources[i].GetLanguageIndexFromCode(languageCode, false); + if (langIdx < 0) + continue; + + var termData = Sources[i].GetTermData(Sources[i].mTerm_AppName); + if (termData == null) + continue; + + var appName = termData.GetTranslation(langIdx); + if (!string.IsNullOrEmpty(appName)) + return appName; + } + } + + return Application.productName; + } + + public static void LocalizeAll(bool Force = false) + { + LoadCurrentLanguage(); + + if (!Application.isPlaying) + { + DoLocalizeAll(Force); + return; + } + mLocalizeIsScheduledWithForcedValue |= Force; + if (mLocalizeIsScheduled) + { + return; + } + CoroutineManager.Start(Coroutine_LocalizeAll()); + } + + static IEnumerator Coroutine_LocalizeAll() + { + mLocalizeIsScheduled = true; + yield return null; + mLocalizeIsScheduled = false; + var force = mLocalizeIsScheduledWithForcedValue; + mLocalizeIsScheduledWithForcedValue = false; + DoLocalizeAll(force); + } + + static void DoLocalizeAll(bool Force = false) + { + Localize[] Locals = (Localize[])Resources.FindObjectsOfTypeAll( typeof(Localize) ); + for (int i=0, imax=Locals.Length; i GetCategories () + { + List Categories = new List (); + for (int i=0, imax=Sources.Count; i GetTermsList ( string Category = null ) + { + if (Sources.Count==0) + UpdateSources(); + + if (Sources.Count==1) + return Sources[0].GetTermsList(Category); + + HashSet Terms = new HashSet (); + for (int i=0, imax=Sources.Count; i(Terms); + } + + public static TermData GetTermData( string term ) + { + InitializeIfNeeded(); + + TermData data; + for (int i=0, imax=Sources.Count; i : ILocalizeTarget where T : Object + { + public T mTarget; + + public override bool IsValid(Localize cmp) + { + if (mTarget!=null) + { + var mTargetCmp = mTarget as Component; + if (mTargetCmp != null && mTargetCmp.gameObject != cmp.gameObject) + mTarget = null; + } + if (mTarget==null) + mTarget = cmp.GetComponent(); + return mTarget!=null; + } + } +} + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTarget.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTarget.cs.meta new file mode 100644 index 00000000..4cd9e46c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTarget.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: bc110e805ac87134bb23eb4f9d6989e8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTargetDesc.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTargetDesc.cs new file mode 100644 index 00000000..228f1a4d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTargetDesc.cs @@ -0,0 +1,41 @@ +using System; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace TEngine.Localization +{ + public abstract class ILocalizeTargetDescriptor + { + public string Name; + public int Priority; + public abstract bool CanLocalize(Localize cmp); + public abstract ILocalizeTarget CreateTarget(Localize cmp); + public abstract Type GetTargetType(); + } + + public abstract class LocalizeTargetDesc : ILocalizeTargetDescriptor where T : ILocalizeTarget + { + public override ILocalizeTarget CreateTarget(Localize cmp) { return ScriptableObject.CreateInstance(); } + public override Type GetTargetType() { return typeof(T); } + } + + + + public class LocalizeTargetDesc_Type : LocalizeTargetDesc where T: Object + where G: LocalizeTarget + { + public override bool CanLocalize(Localize cmp) { return cmp.GetComponent() != null; } + public override ILocalizeTarget CreateTarget(Localize cmp) + { + var target = cmp.GetComponent(); + if (target == null) + return null; + + var locTarget = ScriptableObject.CreateInstance(); + locTarget.mTarget = target; + return locTarget; + } + } + +} + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTargetDesc.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTargetDesc.cs.meta new file mode 100644 index 00000000..651f1283 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/ILocalizeTargetDesc.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 65c3e6b4b14772c4e9fb35235497819b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Label.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Label.cs new file mode 100644 index 00000000..47e4aa94 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Label.cs @@ -0,0 +1,66 @@ +#if TK2D + +using UnityEngine; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [UnityEditor.InitializeOnLoad] + #endif + + public class LocalizeTarget_2DToolKit_Label : LocalizeTarget + { + static LocalizeTarget_2DToolKit_Label() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type() { Name = "2DToolKit Label", Priority = 100 }); } + + TextAnchor mOriginalAlignment = TextAnchor.MiddleCenter; + bool mInitializeAlignment = true; + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Text; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.TK2dFont; } + + public override bool CanUseSecondaryTerm() { return true; } + public override bool AllowMainTermToBeRTL() { return true; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms(Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = mTarget ? mTarget.text : null; + secondaryTerm = (mTarget.font != null ? mTarget.font.name : string.Empty); + } + + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + //--[ Localize Font Object ]---------- + tk2dFont newFont = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + if (newFont != null && mTarget.font != newFont) + { + mTarget.font = newFont.data; + } + + if (mInitializeAlignment) + { + mInitializeAlignment = false; + mOriginalAlignment = mTarget.anchor; + } + + if (mainTranslation != null && mTarget.text != mainTranslation) + { + if (Localize.CurrentLocalizeComponent.CorrectAlignmentForRTL) + { + int align = (int)mTarget.anchor; + + if (align % 3 == 0) + mTarget.anchor = LocalizationManager.IsRight2Left ? mTarget.anchor + 2 : mOriginalAlignment; + else + if (align % 3 == 2) + mTarget.anchor = LocalizationManager.IsRight2Left ? mTarget.anchor - 2 : mOriginalAlignment; + } + mTarget.text = mainTranslation; + } + } + } +} +#endif + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Label.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Label.cs.meta new file mode 100644 index 00000000..c8989caa --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Label.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f7658f1522689aa4b93bc276acf537b1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Sprite.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Sprite.cs new file mode 100644 index 00000000..4c924681 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Sprite.cs @@ -0,0 +1,53 @@ +#if TK2D + +using UnityEngine; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [UnityEditor.InitializeOnLoad] + #endif + + public class LocalizeTarget_2DToolKit_Sprite : LocalizeTarget + { + static LocalizeTarget_2DToolKit_Sprite() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type() { Name = "2DToolKit Sprite", Priority = 100 }); } + + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.TK2dCollection; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.TK2dCollection; } + + public override bool CanUseSecondaryTerm() { return true; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms(Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = (mTarget.CurrentSprite != null ? mTarget.CurrentSprite.name : string.Empty); + secondaryTerm = (mTarget.Collection != null ? mTarget.Collection.spriteCollectionName : null); + } + + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + if (string.IsNullOrEmpty(mainTranslation)) + return; + + //--[ Localize Atlas ]---------- + tk2dSpriteCollection newCollection = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + + if (newCollection != null) + { + if (mTarget.CurrentSprite.name != mainTranslation || mTarget.Collection.name != secondaryTranslation) + mTarget.SetSprite(newCollection.spriteCollection, mainTranslation); + } + else + { + if (mTarget.CurrentSprite.name != mainTranslation) + mTarget.SetSprite(mainTranslation); + } + } + } +} +#endif + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Sprite.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Sprite.cs.meta new file mode 100644 index 00000000..f4ca51fc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_2DToolKit_Sprite.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 53d5ed87a66514e439dddd19568adedd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Label.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Label.cs new file mode 100644 index 00000000..53e92b2d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Label.cs @@ -0,0 +1,94 @@ +#if NGUI + +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_NGUI_Label : LocalizeTarget + { + static LocalizeTarget_NGUI_Label() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "NGUI Label", Priority = 100 }); } + + NGUIText.Alignment mAlignment_RTL = NGUIText.Alignment.Right; + NGUIText.Alignment mAlignment_LTR = NGUIText.Alignment.Left; + bool mAlignmentWasRTL; + bool mInitializeAlignment = true; + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Text; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.UIFont; } + public override bool CanUseSecondaryTerm() { return true; } + public override bool AllowMainTermToBeRTL() { return true; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms(Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = mTarget ? mTarget.text : null; + secondaryTerm = mTarget.ambigiousFont != null ? mTarget.ambigiousFont.name : string.Empty; + } + + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + //--[ Localize Font Object ]---------- + Font newFont = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + if (newFont != null) + { + if (newFont != mTarget.ambigiousFont) + mTarget.ambigiousFont = newFont; + } + if (newFont==null) + { + UIFont newUIFont = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + if (newUIFont != null && mTarget.ambigiousFont != newUIFont) + mTarget.ambigiousFont = newUIFont; + } + if (newFont == null) + { + NGUIFont newUIFont = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + if (newUIFont != null && mTarget.ambigiousFont != newUIFont) + mTarget.ambigiousFont = newUIFont; + } + + + if (mInitializeAlignment) + { + mInitializeAlignment = false; + mAlignment_LTR = mAlignment_RTL = mTarget.alignment; + + if (LocalizationManager.IsRight2Left && mAlignment_RTL == NGUIText.Alignment.Right) + mAlignment_LTR = NGUIText.Alignment.Left; + if (!LocalizationManager.IsRight2Left && mAlignment_LTR == NGUIText.Alignment.Left) + mAlignment_RTL = NGUIText.Alignment.Right; + } + + UIInput input = NGUITools.FindInParents(mTarget.gameObject); + if (input != null && input.label == mTarget) + { + if (mainTranslation != null && input.defaultText != mainTranslation) + { + if (cmp.CorrectAlignmentForRTL && (input.label.alignment == NGUIText.Alignment.Left || input.label.alignment == NGUIText.Alignment.Right)) + input.label.alignment = LocalizationManager.IsRight2Left ? mAlignment_RTL : mAlignment_LTR; + + input.defaultText = mainTranslation; + } + } + else + { + if (mainTranslation != null && mTarget.text != mainTranslation) + { + if (cmp.CorrectAlignmentForRTL && (mTarget.alignment == NGUIText.Alignment.Left || mTarget.alignment == NGUIText.Alignment.Right)) + mTarget.alignment = LocalizationManager.IsRight2Left ? mAlignment_RTL : mAlignment_LTR; + + mTarget.text = mainTranslation; + } + } + } + } +} +#endif + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Label.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Label.cs.meta new file mode 100644 index 00000000..b1f87898 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Label.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3bd97513069766847851e1041f64e378 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Sprite.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Sprite.cs new file mode 100644 index 00000000..3976e545 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Sprite.cs @@ -0,0 +1,65 @@ +#if NGUI + +using UnityEngine; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [UnityEditor.InitializeOnLoad] + #endif + + public class LocalizeTarget_NGUI_Sprite : LocalizeTarget + { + static LocalizeTarget_NGUI_Sprite() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type() { Name = "NGUI UISprite", Priority = 100 }); } + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Sprite; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.UIAtlas; } + public override bool CanUseSecondaryTerm () { return true; } + public override bool AllowMainTermToBeRTL () { return false; } + public override bool AllowSecondTermToBeRTL () { return false; } + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm ) + { + primaryTerm = mTarget ? mTarget.spriteName : null; + secondaryTerm = (mTarget.atlas is UIAtlas atlas ? atlas.name : string.Empty); + } + + + public override void DoLocalize ( Localize cmp, string mainTranslation, string secondaryTranslation ) + { + if (mTarget.spriteName == mainTranslation) + return; + + //--[ Localize Atlas ]---------- + UIAtlas newAtlas = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + bool bChanged = false; + if (newAtlas != null && ((mTarget.atlas as UIAtlas) != newAtlas)) + { + mTarget.atlas = newAtlas; + bChanged = true; + } + + if (newAtlas==null) + { + NGUIAtlas newNGUIAtlas = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + if (newAtlas != null && ((mTarget.atlas as NGUIAtlas) != newNGUIAtlas)) + { + mTarget.atlas = newAtlas; + bChanged = true; + } + + } + + if (mTarget.spriteName != mainTranslation && mTarget.atlas.GetSprite(mainTranslation) != null) + { + mTarget.spriteName = mainTranslation; + bChanged = true; + } + if (bChanged) + mTarget.MakePixelPerfect(); + } + } +} +#endif + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Sprite.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Sprite.cs.meta new file mode 100644 index 00000000..ad158713 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Sprite.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 545ef381b929ce44cad2bf111b096f2c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Texture.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Texture.cs new file mode 100644 index 00000000..da86a995 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Texture.cs @@ -0,0 +1,41 @@ +#if NGUI + +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_NGUI_Texture : LocalizeTarget + { + static LocalizeTarget_NGUI_Texture() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "NGUI UITexture", Priority = 100 }); } + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Texture; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Text; } + public override bool CanUseSecondaryTerm() { return false; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms(Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = mTarget!=null && mTarget.mainTexture!=null ? mTarget.mainTexture.name : null; + secondaryTerm = null; + } + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + Texture Old = mTarget.mainTexture; + if (Old == null || Old.name != mainTranslation) + { + mTarget.mainTexture = cmp.FindTranslatedObject(mainTranslation); + mTarget.MakePixelPerfect(); + } + } + } +} +#endif + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Texture.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Texture.cs.meta new file mode 100644 index 00000000..2e8fd038 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_NGUI_Texture.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8488ebda4a4bc5343b6fcd2158af0360 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Image.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Image.cs new file mode 100644 index 00000000..afc37287 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Image.cs @@ -0,0 +1,42 @@ +#if SVG +using UnityEngine; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [UnityEditor.InitializeOnLoad] + #endif + + public class LocalizeTarget_SVGImporter_Image : LocalizeTarget + { + static LocalizeTarget_SVGImporter_Image() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type() { Name = "SVG Image", Priority = 100 }); } + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.SVGAsset; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Material; } + public override bool CanUseSecondaryTerm() { return true; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms(Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = (mTarget.vectorGraphics != null ? mTarget.vectorGraphics.name : string.Empty); + secondaryTerm = (mTarget.material != null ? mTarget.material.name : null); + } + + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + var OldVectorG = mTarget.vectorGraphics; + if (OldVectorG == null || OldVectorG.name != mainTranslation) + mTarget.vectorGraphics = cmp.FindTranslatedObject(mainTranslation); + + var OldMaterial = mTarget.material; + if (OldMaterial == null || OldMaterial.name != secondaryTranslation) + mTarget.material = cmp.FindTranslatedObject(secondaryTranslation); + + mTarget.SetAllDirty(); + } + } +} +#endif diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Image.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Image.cs.meta new file mode 100644 index 00000000..0ad6478a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Image.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: bbf97c698c733ea4bbf7bc2996984484 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Renderer.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Renderer.cs new file mode 100644 index 00000000..fdcf689a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Renderer.cs @@ -0,0 +1,42 @@ +#if SVG +using UnityEngine; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [UnityEditor.InitializeOnLoad] + #endif + + public class LocalizeTarget_SVGImporter_Renderer : LocalizeTarget + { + static LocalizeTarget_SVGImporter_Renderer() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type() { Name = "SVG Renderer", Priority = 100 }); } + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.SVGAsset; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Material; } + public override bool CanUseSecondaryTerm() { return true; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms(Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = (mTarget.vectorGraphics != null ? mTarget.vectorGraphics.name : string.Empty); + secondaryTerm = (mTarget.opaqueMaterial != null ? mTarget.opaqueMaterial.name : string.Empty); + } + + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + var OldVectorG = mTarget.vectorGraphics; + if (OldVectorG == null || OldVectorG.name != mainTranslation) + mTarget.vectorGraphics = cmp.FindTranslatedObject(mainTranslation); + + var OldMaterial = mTarget.opaqueMaterial; + if (OldMaterial == null || OldMaterial.name != secondaryTranslation) + mTarget.opaqueMaterial = cmp.FindTranslatedObject(secondaryTranslation); + + mTarget.SetAllDirty(); + } + } +} +#endif diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Renderer.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Renderer.cs.meta new file mode 100644 index 00000000..0ac2b0df --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_SVGImporter_Renderer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c78c473b19acc3844ba488904981d75c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_Label.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_Label.cs new file mode 100644 index 00000000..e565bb57 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_Label.cs @@ -0,0 +1,191 @@ +using System; +using TMPro; +using UnityEditor; +using UnityEngine; + +#if TextMeshPro +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_TextMeshPro_Label : LocalizeTarget + { + static LocalizeTarget_TextMeshPro_Label() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "TextMeshPro Label", Priority = 100 }); } + + TextAlignmentOptions mAlignment_RTL = TextAlignmentOptions.Right; + TextAlignmentOptions mAlignment_LTR = TextAlignmentOptions.Left; + bool mAlignmentWasRTL; + bool mInitializeAlignment = true; + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Text; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Font; } + public override bool CanUseSecondaryTerm() { return true; } + public override bool AllowMainTermToBeRTL() { return true; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = mTarget ? mTarget.text : null; + secondaryTerm = mTarget.font != null ? mTarget.font.name : string.Empty; + } + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + //--[ Localize Font Object ]---------- + { + TMP_FontAsset newFont = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + + if (newFont != null) + { + SetFont(mTarget, newFont); + } + else + { + //--[ Localize Font Material ]---------- + Material newMat = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + if (newMat != null && mTarget.fontMaterial != newMat) + { + if (!newMat.name.StartsWith(mTarget.font.name, StringComparison.Ordinal)) + { + newFont = GetTMPFontFromMaterial(cmp, secondaryTranslation.EndsWith(newMat.name, StringComparison.Ordinal) ? secondaryTranslation : newMat.name); + if (newFont != null) + SetFont(mTarget, newFont); + } + SetMaterial(mTarget, newMat); + } + + } + } + if (mInitializeAlignment) + { + mInitializeAlignment = false; + mAlignmentWasRTL = LocalizationManager.IsRight2Left; + InitAlignment_TMPro(mAlignmentWasRTL, mTarget.alignment, out mAlignment_LTR, out mAlignment_RTL); + } + else + { + TextAlignmentOptions alignRTL, alignLTR; + InitAlignment_TMPro(mAlignmentWasRTL, mTarget.alignment, out alignLTR, out alignRTL); + + if (mAlignmentWasRTL && mAlignment_RTL != alignRTL || + !mAlignmentWasRTL && mAlignment_LTR != alignLTR) + { + mAlignment_LTR = alignLTR; + mAlignment_RTL = alignRTL; + } + mAlignmentWasRTL = LocalizationManager.IsRight2Left; + } + + if (mainTranslation != null && mTarget.text != mainTranslation) + { + if (cmp.CorrectAlignmentForRTL) + { + mTarget.alignment = LocalizationManager.IsRight2Left ? mAlignment_RTL : mAlignment_LTR; + } + + mTarget.isRightToLeftText = LocalizationManager.IsRight2Left; + if (LocalizationManager.IsRight2Left) mainTranslation = I2Utils.ReverseText(mainTranslation); + + mTarget.text = mainTranslation; + } + } + + #region Tools + internal static TMP_FontAsset GetTMPFontFromMaterial(Localize cmp, string matName) + { + string splitChars = " .\\/-[]()"; + for (int i = matName.Length - 1; i > 0;) + { + // Find first valid character + while (i > 0 && splitChars.IndexOf(matName[i]) >= 0) + i--; + + if (i <= 0) break; + + var fontName = matName.Substring(0, i + 1); + var obj = cmp.GetObject(fontName); + if (obj != null) + return obj; + + // skip this word + while (i > 0 && splitChars.IndexOf(matName[i]) < 0) + i--; + } + + return null; + } + + internal static void InitAlignment_TMPro(bool isRTL, TextAlignmentOptions alignment, out TextAlignmentOptions alignLTR, out TextAlignmentOptions alignRTL) + { + alignLTR = alignRTL = alignment; + + if (isRTL) + { + switch (alignment) + { + case TextAlignmentOptions.TopRight: alignLTR = TextAlignmentOptions.TopLeft; break; + case TextAlignmentOptions.Right: alignLTR = TextAlignmentOptions.Left; break; + case TextAlignmentOptions.BottomRight: alignLTR = TextAlignmentOptions.BottomLeft; break; + case TextAlignmentOptions.BaselineRight: alignLTR = TextAlignmentOptions.BaselineLeft; break; + case TextAlignmentOptions.MidlineRight: alignLTR = TextAlignmentOptions.MidlineLeft; break; + case TextAlignmentOptions.CaplineRight: alignLTR = TextAlignmentOptions.CaplineLeft; break; + + case TextAlignmentOptions.TopLeft: alignLTR = TextAlignmentOptions.TopRight; break; + case TextAlignmentOptions.Left: alignLTR = TextAlignmentOptions.Right; break; + case TextAlignmentOptions.BottomLeft: alignLTR = TextAlignmentOptions.BottomRight; break; + case TextAlignmentOptions.BaselineLeft: alignLTR = TextAlignmentOptions.BaselineRight; break; + case TextAlignmentOptions.MidlineLeft: alignLTR = TextAlignmentOptions.MidlineRight; break; + case TextAlignmentOptions.CaplineLeft: alignLTR = TextAlignmentOptions.CaplineRight; break; + + } + } + else + { + switch (alignment) + { + case TextAlignmentOptions.TopRight: alignRTL = TextAlignmentOptions.TopLeft; break; + case TextAlignmentOptions.Right: alignRTL = TextAlignmentOptions.Left; break; + case TextAlignmentOptions.BottomRight: alignRTL = TextAlignmentOptions.BottomLeft; break; + case TextAlignmentOptions.BaselineRight: alignRTL = TextAlignmentOptions.BaselineLeft; break; + case TextAlignmentOptions.MidlineRight: alignRTL = TextAlignmentOptions.MidlineLeft; break; + case TextAlignmentOptions.CaplineRight: alignRTL = TextAlignmentOptions.CaplineLeft; break; + + case TextAlignmentOptions.TopLeft: alignRTL = TextAlignmentOptions.TopRight; break; + case TextAlignmentOptions.Left: alignRTL = TextAlignmentOptions.Right; break; + case TextAlignmentOptions.BottomLeft: alignRTL = TextAlignmentOptions.BottomRight; break; + case TextAlignmentOptions.BaselineLeft: alignRTL = TextAlignmentOptions.BaselineRight; break; + case TextAlignmentOptions.MidlineLeft: alignRTL = TextAlignmentOptions.MidlineRight; break; + case TextAlignmentOptions.CaplineLeft: alignRTL = TextAlignmentOptions.CaplineRight; break; + } + } + } + + internal static void SetFont(TMP_Text label, TMP_FontAsset newFont) + { + if (label.font != newFont) + { + label.font = newFont; + } + if (label.linkedTextComponent != null) + { + SetFont(label.linkedTextComponent, newFont); + } + } + internal static void SetMaterial(TMP_Text label, Material newMat) + { + if (label.fontSharedMaterial != newMat) + { + label.fontSharedMaterial = newMat; + } + if (label.linkedTextComponent != null) + { + SetMaterial(label.linkedTextComponent, newMat); + } + } + #endregion + } +} +#endif \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_Label.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_Label.cs.meta new file mode 100644 index 00000000..f9e954b5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_Label.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d96a6c3ea7d28744aacc367115a71af5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_UGUI.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_UGUI.cs new file mode 100644 index 00000000..2279b028 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_UGUI.cs @@ -0,0 +1,98 @@ +using System; +using TMPro; +using UnityEditor; +using UnityEngine; + +#if TextMeshPro +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_TextMeshPro_UGUI : LocalizeTarget + { + static LocalizeTarget_TextMeshPro_UGUI() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "TextMeshPro UGUI", Priority = 100 }); } + + public TextAlignmentOptions mAlignment_RTL = TextAlignmentOptions.Right; + public TextAlignmentOptions mAlignment_LTR = TextAlignmentOptions.Left; + public bool mAlignmentWasRTL; + public bool mInitializeAlignment = true; + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Text; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.TextMeshPFont; } + public override bool CanUseSecondaryTerm() { return true; } + public override bool AllowMainTermToBeRTL() { return true; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = mTarget ? mTarget.text : null; + secondaryTerm = mTarget.font != null ? mTarget.font.name : string.Empty; + } + + + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + { + //--[ Localize Font Object ]---------- + TMP_FontAsset newFont = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + + if (newFont != null) + { + LocalizeTarget_TextMeshPro_Label.SetFont(mTarget, newFont); + } + else + { + //--[ Localize Font Material ]---------- + Material newMat = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + if (newMat != null && mTarget.fontMaterial != newMat) + { + if (!newMat.name.StartsWith(mTarget.font.name, StringComparison.Ordinal)) + { + newFont = LocalizeTarget_TextMeshPro_Label.GetTMPFontFromMaterial(cmp, secondaryTranslation.EndsWith(newMat.name, StringComparison.Ordinal) ? secondaryTranslation : newMat.name); + if (newFont != null) + LocalizeTarget_TextMeshPro_Label.SetFont(mTarget, newFont); + } + LocalizeTarget_TextMeshPro_Label.SetMaterial( mTarget, newMat ); + } + } + } + + if (mInitializeAlignment) + { + mInitializeAlignment = false; + mAlignmentWasRTL = LocalizationManager.IsRight2Left; + LocalizeTarget_TextMeshPro_Label.InitAlignment_TMPro(mAlignmentWasRTL, mTarget.alignment, out mAlignment_LTR, out mAlignment_RTL); + } + else + { + TextAlignmentOptions alignRTL, alignLTR; + LocalizeTarget_TextMeshPro_Label.InitAlignment_TMPro(mAlignmentWasRTL, mTarget.alignment, out alignLTR, out alignRTL); + + if (mAlignmentWasRTL && mAlignment_RTL != alignRTL || + !mAlignmentWasRTL && mAlignment_LTR != alignLTR) + { + mAlignment_LTR = alignLTR; + mAlignment_RTL = alignRTL; + } + mAlignmentWasRTL = LocalizationManager.IsRight2Left; + } + + if (mainTranslation != null && mTarget.text != mainTranslation) + { + if (cmp.CorrectAlignmentForRTL) + { + mTarget.alignment = LocalizationManager.IsRight2Left ? mAlignment_RTL : mAlignment_LTR; + } + if (LocalizationManager.IsRight2Left) mainTranslation = I2Utils.ReverseText(mainTranslation); + + mTarget.isRightToLeftText = LocalizationManager.IsRight2Left; + mTarget.text = mainTranslation; + } + } + } +} +#endif \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_UGUI.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_UGUI.cs.meta new file mode 100644 index 00000000..acb45b3f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_TextMeshPro_UGUI.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 481ab606793a67349be805c13febeba0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_AudioSource.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_AudioSource.cs new file mode 100644 index 00000000..86ddd2f2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_AudioSource.cs @@ -0,0 +1,45 @@ +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_UnityStandard_AudioSource : LocalizeTarget + { + static LocalizeTarget_UnityStandard_AudioSource() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "AudioSource", Priority = 100 }); } + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.AudioClip; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Text; } + public override bool CanUseSecondaryTerm() { return false; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + AudioClip clip = mTarget.clip; + primaryTerm = clip ? clip.name : string.Empty; + secondaryTerm = null; + } + + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + bool bIsPlaying = (mTarget.isPlaying || mTarget.loop) && Application.isPlaying; + AudioClip OldClip = mTarget.clip; + AudioClip NewClip = cmp.FindTranslatedObject(mainTranslation); + if (OldClip != NewClip) + mTarget.clip = NewClip; + + if (bIsPlaying && mTarget.clip) + mTarget.Play(); + + // If the old clip is not in the translatedObjects, then unload it as it most likely was loaded from Resources + //if (!HasTranslatedObject(OldClip)) + // Resources.UnloadAsset(OldClip); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_AudioSource.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_AudioSource.cs.meta new file mode 100644 index 00000000..6f903d82 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_AudioSource.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 007f2c3f7b0e4a048ae89d65dcd38729 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Child.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Child.cs new file mode 100644 index 00000000..c3f25c11 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Child.cs @@ -0,0 +1,51 @@ +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + public class LocalizeTargetDesc_Child : LocalizeTargetDesc + { + public override bool CanLocalize(Localize cmp) { return cmp.transform.childCount > 1; } + } + + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_UnityStandard_Child : LocalizeTarget + { + static LocalizeTarget_UnityStandard_Child() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Child { Name = "Child", Priority = 200 }); } + + public override bool IsValid(Localize cmp) { return cmp.transform.childCount>1; } + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.GameObject; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Text; } + public override bool CanUseSecondaryTerm() { return false; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms(Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = cmp.name; + secondaryTerm = null; + } + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + if (string.IsNullOrEmpty(mainTranslation)) + return; + Transform locTr = cmp.transform; + + var objName = mainTranslation; + var idx = mainTranslation.LastIndexOfAny(LanguageSourceData.CategorySeparators); + if (idx >= 0) + objName = objName.Substring(idx + 1); + + for (int i = 0; i < locTr.childCount; ++i) + { + var child = locTr.GetChild(i); + child.gameObject.SetActive(child.name == objName); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Child.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Child.cs.meta new file mode 100644 index 00000000..2ef5fae1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Child.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 61a67a81d07fe85429a253a86ebac910 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_MeshRenderer.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_MeshRenderer.cs new file mode 100644 index 00000000..1643939e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_MeshRenderer.cs @@ -0,0 +1,80 @@ +using UnityEditor; +using UnityEngine; + +#pragma warning disable 618 + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_UnityStandard_MeshRenderer : LocalizeTarget + { + static LocalizeTarget_UnityStandard_MeshRenderer() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "MeshRenderer", Priority = 800 }); } + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Mesh; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Material; } + public override bool CanUseSecondaryTerm() { return true; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + if (mTarget==null) + { + primaryTerm = secondaryTerm = null; + } + else + { + MeshFilter filter = mTarget.GetComponent(); + if (filter==null || filter.sharedMesh==null) + { + primaryTerm = null; + } + else + { + #if UNITY_EDITOR + primaryTerm = AssetDatabase.GetAssetPath(filter.sharedMesh); + I2Utils.RemoveResourcesPath(ref primaryTerm); + #else + primaryTerm = filter.sharedMesh.name; + #endif + } + } + + if (mTarget==null || mTarget.sharedMaterial==null) + { + secondaryTerm = null; + } + else + { + #if UNITY_EDITOR + secondaryTerm = AssetDatabase.GetAssetPath(mTarget.sharedMaterial); + I2Utils.RemoveResourcesPath(ref secondaryTerm); + #else + secondaryTerm = mTarget.sharedMaterial.name; + #endif + } + } + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + //--[ Localize Material]---------- + Material newMat = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + if (newMat != null && mTarget.sharedMaterial != newMat) + { + mTarget.material = newMat; + } + + //--[ Localize Mesh ]---------- + Mesh newMesh = cmp.FindTranslatedObject( mainTranslation); + MeshFilter filter = mTarget.GetComponent(); + if (newMesh != null && filter.sharedMesh != newMesh) + { + filter.mesh = newMesh; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_MeshRenderer.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_MeshRenderer.cs.meta new file mode 100644 index 00000000..883f5974 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_MeshRenderer.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: b4679336707a2b54caa10d99561be751 +timeCreated: 1518408606 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Prefab.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Prefab.cs new file mode 100644 index 00000000..9022a557 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Prefab.cs @@ -0,0 +1,96 @@ +using UnityEditor; +using UnityEngine; + +#pragma warning disable 618 + +namespace TEngine.Localization +{ + public class LocalizeTargetDesc_Prefab : LocalizeTargetDesc + { + public override bool CanLocalize(Localize cmp) { return true; } + } + + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_UnityStandard_Prefab : LocalizeTarget + { + static LocalizeTarget_UnityStandard_Prefab() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Prefab { Name = "Prefab", Priority = 250 }); } + + public override bool IsValid(Localize cmp) { return true; } + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.GameObject; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Text; } + public override bool CanUseSecondaryTerm() { return false; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = cmp.name; + secondaryTerm = null; + } + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + if (string.IsNullOrEmpty(mainTranslation)) + return; + + if (mTarget && mTarget.name == mainTranslation) + return; + + Transform locTr = cmp.transform; + + var objName = mainTranslation; + var idx = mainTranslation.LastIndexOfAny(LanguageSourceData.CategorySeparators); + if (idx >= 0) + objName = objName.Substring(idx + 1); + + Transform mNew = InstantiateNewPrefab(cmp, mainTranslation); + if (mNew == null) + return; + mNew.name = objName; + + for (int i = locTr.childCount - 1; i >= 0; --i) + { + var child = locTr.GetChild(i); + if (child!=mNew) + { + #if UNITY_EDITOR + if (Application.isPlaying) + Destroy(child.gameObject); + else + DestroyImmediate(child.gameObject); + #else + Object.Destroy (child.gameObject); + #endif + } + } + } + + Transform InstantiateNewPrefab(Localize cmp, string mainTranslation) + { + GameObject NewPrefab = cmp.FindTranslatedObject(mainTranslation); + if (NewPrefab == null) + return null; + + GameObject current = mTarget; + + mTarget = Instantiate(NewPrefab); + if (mTarget == null) + return null; + + Transform locTr = cmp.transform; + Transform mNew = mTarget.transform; + mNew.SetParent(locTr); + + Transform bBase = current ? current.transform : locTr; + //mNew.localScale = bBase.localScale; + mNew.rotation = bBase.rotation; + mNew.position = bBase.position; + + return mNew; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Prefab.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Prefab.cs.meta new file mode 100644 index 00000000..6b0935dd --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_Prefab.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: bd8b481d182cbcd4293524eb92ee520c +timeCreated: 1518408606 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_SpriteRenderer.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_SpriteRenderer.cs new file mode 100644 index 00000000..c4d849a0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_SpriteRenderer.cs @@ -0,0 +1,41 @@ +using UnityEditor; +using UnityEngine; + +#pragma warning disable 618 + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_UnityStandard_SpriteRenderer : LocalizeTarget + { + static LocalizeTarget_UnityStandard_SpriteRenderer() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "SpriteRenderer", Priority = 100 }); } + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Sprite; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Text; } + public override bool CanUseSecondaryTerm() { return false; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + Sprite sprite = mTarget.sprite; + primaryTerm = sprite != null ? sprite.name : string.Empty; + secondaryTerm = null; + } + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + Sprite Old = mTarget.sprite; + if (Old == null || Old.name != mainTranslation) + mTarget.sprite = cmp.FindTranslatedObject(mainTranslation); + + // If the old value is not in the translatedObjects, then unload it as it most likely was loaded from Resources + //if (!HasTranslatedObject(Old)) + // Resources.UnloadAsset(Old); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_SpriteRenderer.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_SpriteRenderer.cs.meta new file mode 100644 index 00000000..05bacef1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_SpriteRenderer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3b29d7ab09a96634a9f704e6a1f21193 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_TextMesh.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_TextMesh.cs new file mode 100644 index 00000000..d13350ae --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_TextMesh.cs @@ -0,0 +1,68 @@ +using UnityEditor; +using UnityEngine; + +#pragma warning disable 618 + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_UnityStandard_TextMesh : LocalizeTarget + { + static LocalizeTarget_UnityStandard_TextMesh() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "TextMesh", Priority = 100 }); } + + TextAlignment mAlignment_RTL = TextAlignment.Right; + TextAlignment mAlignment_LTR = TextAlignment.Left; + bool mAlignmentWasRTL; + bool mInitializeAlignment = true; + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Text; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Font; } + public override bool CanUseSecondaryTerm() { return true; } + public override bool AllowMainTermToBeRTL() { return true; } + public override bool AllowSecondTermToBeRTL() { return false; } + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = mTarget ? mTarget.text : null; + secondaryTerm = string.IsNullOrEmpty(Secondary) && mTarget.font != null ? mTarget.font.name : null; + } + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + //--[ Localize Font Object ]---------- + Font newFont = cmp.GetSecondaryTranslatedObj(ref mainTranslation, ref secondaryTranslation); + if (newFont != null && mTarget.font != newFont) + { + mTarget.font = newFont; + MeshRenderer rend = mTarget.GetComponentInChildren(); + rend.material = newFont.material; + } + + //--[ Localize Text ]---------- + if (mInitializeAlignment) + { + mInitializeAlignment = false; + + mAlignment_LTR = mAlignment_RTL = mTarget.alignment; + + if (LocalizationManager.IsRight2Left && mAlignment_RTL == TextAlignment.Right) + mAlignment_LTR = TextAlignment.Left; + if (!LocalizationManager.IsRight2Left && mAlignment_LTR == TextAlignment.Left) + mAlignment_RTL = TextAlignment.Right; + + } + if (mainTranslation != null && mTarget.text != mainTranslation) + { + if (cmp.CorrectAlignmentForRTL && mTarget.alignment != TextAlignment.Center) + mTarget.alignment = LocalizationManager.IsRight2Left ? mAlignment_RTL : mAlignment_LTR; + + mTarget.font.RequestCharactersInTexture(mainTranslation); + mTarget.text = mainTranslation; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_TextMesh.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_TextMesh.cs.meta new file mode 100644 index 00000000..58ed8e6e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_TextMesh.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 62e865dd37373234c9d966bdd78278e1 +timeCreated: 1518408606 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_VideoPlayer.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_VideoPlayer.cs new file mode 100644 index 00000000..42f813cb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_VideoPlayer.cs @@ -0,0 +1,33 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.Video; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + public class LocalizeTarget_UnityStandard_VideoPlayer : LocalizeTarget + { + static LocalizeTarget_UnityStandard_VideoPlayer() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "VideoPlayer", Priority = 100 }); } + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Video; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Text; } + public override bool CanUseSecondaryTerm() { return false; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + VideoClip clip = mTarget.clip; + primaryTerm = clip != null ? clip.name: string.Empty; + secondaryTerm = null; + } + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + VideoClip Old = mTarget.clip; + if (Old == null || Old.name != mainTranslation) + mTarget.clip = cmp.FindTranslatedObject(mainTranslation); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_VideoPlayer.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_VideoPlayer.cs.meta new file mode 100644 index 00000000..3d496e8a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityStandard_VideoPlayer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5fcaa99c1874460eb953851cbf4bfad2 +timeCreated: 1601759602 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Image.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Image.cs new file mode 100644 index 00000000..fa26f732 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Image.cs @@ -0,0 +1,53 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.UI; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_UnityUI_Image : LocalizeTarget + { + static LocalizeTarget_UnityUI_Image() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "Image", Priority = 100 }); } + + public override bool CanUseSecondaryTerm () { return false; } + public override bool AllowMainTermToBeRTL () { return false; } + public override bool AllowSecondTermToBeRTL () { return false; } + public override eTermType GetPrimaryTermType(Localize cmp) + { + return mTarget.sprite == null ? eTermType.Texture : eTermType.Sprite; + } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Text; } + + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm ) + { + primaryTerm = mTarget.mainTexture ? mTarget.mainTexture.name : ""; + if (mTarget.sprite!=null && mTarget.sprite.name!=primaryTerm) + primaryTerm += "." + mTarget.sprite.name; + + secondaryTerm = null; + } + + + public override void DoLocalize ( Localize cmp, string mainTranslation, string secondaryTranslation ) + { + Sprite Old = mTarget.sprite; + if (Old==null || Old.name!=mainTranslation) + mTarget.sprite = cmp.FindTranslatedObject( mainTranslation ); + + // If the old value is not in the translatedObjects, then unload it as it most likely was loaded from Resources + //if (!HasTranslatedObject(Old)) + // Resources.UnloadAsset(Old); + + // In the editor, sometimes unity "forgets" to show the changes +#if UNITY_EDITOR + if (!Application.isPlaying) + EditorUtility.SetDirty( mTarget ); +#endif + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Image.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Image.cs.meta new file mode 100644 index 00000000..3910dd9f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Image.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: bedef2aeaac8da04faa9a07b7241d0ad +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_RawImage.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_RawImage.cs new file mode 100644 index 00000000..a611a391 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_RawImage.cs @@ -0,0 +1,47 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.UI; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_UnityUI_RawImage : LocalizeTarget + { + static LocalizeTarget_UnityUI_RawImage() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "RawImage", Priority = 100 }); } + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Texture; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Text; } + public override bool CanUseSecondaryTerm() { return false; } + public override bool AllowMainTermToBeRTL() { return false; } + public override bool AllowSecondTermToBeRTL() { return false; } + + + public override void GetFinalTerms(Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm) + { + primaryTerm = mTarget.mainTexture ? mTarget.mainTexture.name : ""; + secondaryTerm = null; + } + + + public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation) + { + Texture Old = mTarget.texture; + if (Old == null || Old.name != mainTranslation) + mTarget.texture = cmp.FindTranslatedObject(mainTranslation); + + // If the old value is not in the translatedObjects, then unload it as it most likely was loaded from Resources + //if (!HasTranslatedObject(Old)) + // Resources.UnloadAsset(Old); + + // In the editor, sometimes unity "forgets" to show the changes + #if UNITY_EDITOR + if (!Application.isPlaying) + EditorUtility.SetDirty(mTarget); + #endif + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_RawImage.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_RawImage.cs.meta new file mode 100644 index 00000000..6a4c5b0a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_RawImage.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a58a0cb6f0764ca42b2877aa2c6fa0af +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Text.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Text.cs new file mode 100644 index 00000000..cb5f1d7d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Text.cs @@ -0,0 +1,111 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.UI; + +namespace TEngine.Localization +{ + #if UNITY_EDITOR + [InitializeOnLoad] + #endif + + public class LocalizeTarget_UnityUI_Text : LocalizeTarget + { + static LocalizeTarget_UnityUI_Text() { AutoRegister(); } + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] static void AutoRegister() { LocalizationManager.RegisterTarget(new LocalizeTargetDesc_Type { Name = "Text", Priority = 100 }); } + + TextAnchor mAlignment_RTL = TextAnchor.UpperRight; + TextAnchor mAlignment_LTR = TextAnchor.UpperLeft; + bool mAlignmentWasRTL; + bool mInitializeAlignment = true; + + public override eTermType GetPrimaryTermType(Localize cmp) { return eTermType.Text; } + public override eTermType GetSecondaryTermType(Localize cmp) { return eTermType.Font; } + public override bool CanUseSecondaryTerm () { return true; } + public override bool AllowMainTermToBeRTL () { return true; } + public override bool AllowSecondTermToBeRTL () { return false; } + + public override void GetFinalTerms ( Localize cmp, string Main, string Secondary, out string primaryTerm, out string secondaryTerm ) + { + primaryTerm = mTarget ? mTarget.text : null; + secondaryTerm = mTarget.font!=null ? mTarget.font.name : string.Empty; + } + + + public override void DoLocalize ( Localize cmp, string mainTranslation, string secondaryTranslation ) + { + //--[ Localize Font Object ]---------- + Font newFont = cmp.GetSecondaryTranslatedObj( ref mainTranslation, ref secondaryTranslation ); + if (newFont!=null && newFont!=mTarget.font) + mTarget.font = newFont; + + if (mInitializeAlignment) + { + mInitializeAlignment = false; + mAlignmentWasRTL = LocalizationManager.IsRight2Left; + InitAlignment( mAlignmentWasRTL, mTarget.alignment, out mAlignment_LTR, out mAlignment_RTL ); + } + else + { + TextAnchor alignRTL, alignLTR; + InitAlignment( mAlignmentWasRTL, mTarget.alignment, out alignLTR, out alignRTL ); + + if (mAlignmentWasRTL && mAlignment_RTL!=alignRTL || + !mAlignmentWasRTL && mAlignment_LTR != alignLTR) + { + mAlignment_LTR = alignLTR; + mAlignment_RTL = alignRTL; + } + mAlignmentWasRTL = LocalizationManager.IsRight2Left; + } + + if (mainTranslation!=null && mTarget.text != mainTranslation) + { + if (cmp.CorrectAlignmentForRTL) + { + mTarget.alignment = LocalizationManager.IsRight2Left ? mAlignment_RTL : mAlignment_LTR; + } + + + mTarget.text = mainTranslation; + mTarget.SetVerticesDirty(); + + // In the editor, sometimes unity "forgets" to show the changes + #if UNITY_EDITOR + if (!Application.isPlaying) + EditorUtility.SetDirty( mTarget ); + #endif + } + } + + void InitAlignment ( bool isRTL, TextAnchor alignment, out TextAnchor alignLTR, out TextAnchor alignRTL ) + { + alignLTR = alignRTL = alignment; + + if (isRTL) + { + switch (alignment) + { + case TextAnchor.UpperRight: alignLTR = TextAnchor.UpperLeft; break; + case TextAnchor.MiddleRight: alignLTR = TextAnchor.MiddleLeft; break; + case TextAnchor.LowerRight: alignLTR = TextAnchor.LowerLeft; break; + case TextAnchor.UpperLeft: alignLTR = TextAnchor.UpperRight; break; + case TextAnchor.MiddleLeft: alignLTR = TextAnchor.MiddleRight; break; + case TextAnchor.LowerLeft: alignLTR = TextAnchor.LowerRight; break; + } + } + else + { + switch (alignment) + { + case TextAnchor.UpperRight: alignRTL = TextAnchor.UpperLeft; break; + case TextAnchor.MiddleRight: alignRTL = TextAnchor.MiddleLeft; break; + case TextAnchor.LowerRight: alignRTL = TextAnchor.LowerLeft; break; + case TextAnchor.UpperLeft: alignRTL = TextAnchor.UpperRight; break; + case TextAnchor.MiddleLeft: alignRTL = TextAnchor.MiddleRight; break; + case TextAnchor.LowerLeft: alignRTL = TextAnchor.LowerRight; break; + } + } + } + } +} + diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Text.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Text.cs.meta new file mode 100644 index 00000000..2372f6e8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Targets/LocalizeTarget_UnityUI_Text.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 332e36893e7cf4a49b3c1f72f76cd5e1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/TermData.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/TermData.cs new file mode 100644 index 00000000..21fa17d9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/TermData.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine.Localization +{ + public enum eTermType + { + Text, Font, Texture, AudioClip, GameObject, Sprite, Material, Child, Mesh, + #if NGUI + UIAtlas, UIFont, + #endif + #if TK2D + TK2dFont, TK2dCollection, + #endif + #if TextMeshPro + TextMeshPFont, + #endif + #if SVG + SVGAsset, + #endif + Object, + Video + } + + public enum TranslationFlag : byte + { + Normal = 1, + AutoTranslated = 2 + } + + + [Serializable] + public class TermData + { + public string Term = string.Empty; + public eTermType TermType = eTermType.Text; + + #if !UNITY_EDITOR + [NonSerialized] + #endif + public string Description; + + public string[] Languages = Array.Empty(); + public byte[] Flags = Array.Empty(); // flags for each translation + + [SerializeField] private string[] Languages_Touch; // TO BE REMOVED IN A FUTURE RELEASE + + public string GetTranslation ( int idx, string specialization=null, bool editMode=false ) + { + string text = Languages[idx]; + if (text != null) + { + text = SpecializationManager.GetSpecializedText(text, specialization); + if (!editMode) + { + text = text.Replace("[i2nt]", "").Replace("[/i2nt]", ""); + } + } + return text; + } + + public void SetTranslation( int idx, string translation, string specialization = null) + { + Languages[idx] = SpecializationManager.SetSpecializedText( Languages[idx], translation, specialization); + } + + public void RemoveSpecialization(string specialization) + { + for (int i = 0; i < Languages.Length; ++i) + RemoveSpecialization(i, specialization); + } + + + public void RemoveSpecialization( int idx, string specialization ) + { + var text = Languages[idx]; + if (specialization == "Any" || !text.Contains("[i2s_" + specialization + "]")) + { + return; + } + + var dict = SpecializationManager.GetSpecializations(text); + dict.Remove(specialization); + Languages[idx] = SpecializationManager.SetSpecializedText(dict); + } + + public bool IsAutoTranslated( int idx, bool IsTouch ) + { + return (Flags[idx] & (byte)TranslationFlag.AutoTranslated) > 0; + } + + public void Validate () + { + int nLanguages = Mathf.Max(Languages.Length, Flags.Length); + + if (Languages.Length != nLanguages) Array.Resize(ref Languages, nLanguages); + if (Flags.Length!=nLanguages) Array.Resize(ref Flags, nLanguages); + + if (Languages_Touch != null) + { + for (int i = 0; i < Mathf.Min(Languages_Touch.Length, nLanguages); ++i) + { + if (string.IsNullOrEmpty(Languages[i]) && !string.IsNullOrEmpty(Languages_Touch[i])) + { + Languages[i] = Languages_Touch[i]; + Languages_Touch[i] = null; + } + } + Languages_Touch = null; + } + } + + public bool IsTerm( string name, bool allowCategoryMistmatch) + { + if (!allowCategoryMistmatch) + return name == Term; + + return name == LanguageSourceData.GetKeyFromFullTerm (Term); + } + + public bool HasSpecializations() + { + for (int i = 0; i < Languages.Length; ++i) + { + if (!string.IsNullOrEmpty(Languages[i]) && Languages[i].Contains("[i2s_")) + return true; + } + return false; + } + + public List GetAllSpecializations() + { + List values = new List(); + for (int i = 0; i < Languages.Length; ++i) + SpecializationManager.AppendSpecializations(Languages[i], values); + return values; + } + } + + public class TermsPopup : PropertyAttribute + { + public TermsPopup(string filter = "") + { + Filter = filter; + } + + public string Filter { get; private set; } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/TermData.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/TermData.cs.meta new file mode 100644 index 00000000..5a63fee5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/TermData.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: e04d3f1e4351c9740ad1815d63ede4cd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils.meta new file mode 100644 index 00000000..be4c36ef --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 23035eaab7d1f024cb7e7b5bae9b078f +folderAsset: yes +timeCreated: 1478234053 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/AutoChangeCultureInfo.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/AutoChangeCultureInfo.cs new file mode 100644 index 00000000..39a3f7c8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/AutoChangeCultureInfo.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace TEngine.Localization +{ + + public class AutoChangeCultureInfo : MonoBehaviour + { + public void Start() + { + LocalizationManager.EnableChangingCultureInfo(true); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/AutoChangeCultureInfo.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/AutoChangeCultureInfo.cs.meta new file mode 100644 index 00000000..864ccef2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/AutoChangeCultureInfo.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9d7ad57256fd47940aba8035315bd2ca +timeCreated: 1478233236 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CoroutineManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CoroutineManager.cs new file mode 100644 index 00000000..9dc04e0d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CoroutineManager.cs @@ -0,0 +1,53 @@ +using System.Collections; +using UnityEditor; +using UnityEngine; + +namespace TEngine.Localization +{ + // This class is used to spawn coroutines from outside of MonoBehaviors + public class CoroutineManager : MonoBehaviour + { + static CoroutineManager pInstance + { + get{ + if (mInstance==null) + { + GameObject GO = new GameObject( "_Coroutiner" ); + GO.hideFlags = HideFlags.HideAndDontSave; + mInstance = GO.AddComponent(); + if (Application.isPlaying) + DontDestroyOnLoad(GO); + } + return mInstance; + } + } + static CoroutineManager mInstance; + + + private void Awake() + { + if (Application.isPlaying) + DontDestroyOnLoad(gameObject); + } + + public static Coroutine Start(IEnumerator coroutine) + { + #if UNITY_EDITOR + // Special case to allow coroutines to run in the Editor + if (!Application.isPlaying) + { + EditorApplication.CallbackFunction delg=null; + delg = delegate + { + if (!coroutine.MoveNext()) + EditorApplication.update -= delg; + }; + EditorApplication.update += delg; + return null; + } + #endif + + return pInstance.StartCoroutine(coroutine); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CoroutineManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CoroutineManager.cs.meta new file mode 100644 index 00000000..28a08d59 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CoroutineManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 20c75ea9a203e3d40aafe9b20abbd228 +timeCreated: 1502501187 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CustomLocalizeCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CustomLocalizeCallback.cs new file mode 100644 index 00000000..85083b39 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CustomLocalizeCallback.cs @@ -0,0 +1,27 @@ +using UnityEngine; +using UnityEngine.Events; + +namespace TEngine.Localization +{ + [AddComponentMenu("I2/Localization/I2 Localize Callback")] + public class CustomLocalizeCallback : MonoBehaviour + { + public UnityEvent _OnLocalize = new UnityEvent(); + + public void OnEnable() + { + LocalizationManager.OnLocalizeEvent -= OnLocalize; + LocalizationManager.OnLocalizeEvent += OnLocalize; + } + + public void OnDisable() + { + LocalizationManager.OnLocalizeEvent -= OnLocalize; + } + + public void OnLocalize() + { + _OnLocalize.Invoke(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CustomLocalizeCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CustomLocalizeCallback.cs.meta new file mode 100644 index 00000000..5202237e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/CustomLocalizeCallback.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 24da539b4435ced4da00f418327a772c +timeCreated: 1520536965 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/HindiFixer.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/HindiFixer.cs new file mode 100644 index 00000000..a12b46cb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/HindiFixer.cs @@ -0,0 +1,157 @@ +using System.Linq; + +namespace TEngine.Localization +{ + + public class HindiFixer + { + + // Needs to also implement: Hindi: https://www.microsoft.com/typography/OpenTypeDev/devanagari/intro.htm + //https://social.msdn.microsoft.com/Forums/windows/en-US/9883ff08-bd72-499b-9543-ed424167281d/converting-hindi-text-to-english-text?forum=winforms + internal static string Fix(string text) + { + while (true) + { + char[] arr = text.ToCharArray(); + bool changed = false; + + for (int i = 0; i < arr.Length; ++i) + { + // interchange the order of "i" vowel + if (arr[i] == 2367 && !char.IsWhiteSpace(arr[i - 1]) && arr[i - 1]!=0) + { + arr[i] = arr[i - 1]; + arr[i - 1] = (char)2367; + changed = true; + } + + if (i == arr.Length - 1) + continue; + + // letter "I" + Nukta forms letter vocalic "L" + if (arr[i] == 2311) + { + if (arr[i + 1] == 2364) + { + arr[i] = (char)2316; + arr[i + 1] = (char)0; + changed = true; + } + } + + // vowel sign vocalic "R" + sign Nukta forms vowel sign vocalic "Rr" + if (arr[i] == 2371) + { + if (arr[i + 1] == 2364) + { + arr[i] = (char)2372; + arr[i + 1] = (char)0; + changed = true; + } + } + + // Candrabindu + sign Nukta forms Om + if (arr[i] == 2305) + { + if (arr[i + 1] == 2364) + { + arr[i] = (char)2384; + arr[i + 1] = (char)0; + changed = true; + } + } + + // letter vocalic "R" + sign Nukta forms letter vocalic "Rr" + if (arr[i] == 2315) + { + if (arr[i + 1] == 2364) + { + arr[i] = (char)2400; + arr[i + 1] = (char)0; + changed = true; + } + } + + // letter "Ii" + sign Nukta forms letter vocalic "LI" + if (arr[i] == 2312) + { + if (arr[i + 1] == 2364) + { + arr[i] = (char)2401; + arr[i + 1] = (char)0; + changed = true; + } + } + + // vowel sign "I" + sign Nukta forms vowel sign vocalic "L" + if (arr[i] == 2367) + { + if (arr[i + 1] == 2364) + { + arr[i] = (char)2402; + arr[i + 1] = (char)0; + changed = true; + } + } + + // vowel sign "Ii" + sign Nukta forms vowel sign vocalic "LI" + if (arr[i] == 2368) + { + if (arr[i + 1] == 2364) + { + arr[i] = (char)2403; + arr[i + 1] = (char)0; + changed = true; + } + } + + // Danda + sign Nukta forms sign Avagraha + if (arr[i] == 2404) + { + if (arr[i + 1] == 2364) + { + arr[i] = (char)2365; + arr[i + 1] = (char)0; + changed = true; + } + } + + // consonant + Halant + Halant + consonant forms consonant + Halant + ZWNJ + consonant + //if (arr[i] == 2381) + //{ + // if (arr[i + 1] == 2381) + // { + // arr[i+1] = (char)8204; // + // } + //} + + // consonant + Halant + Nukta + consonant forms consonant + Halant + ZWJ + Consonant + //if (arr[i] == 2364) + //{ + // if (arr[i + 1] == 2381) + // { + // arr[i] = (char)2381; // + // arr[i+1] = (char)8205; // + // } + //} + /*if (arr[i] == 0x938 && arr[i + 1] == 0x94D)//थ') + { + arr[i] = (char)0x930; + arr[i + 1] = (char)0; + }*/ + } + + if (!changed) + { + return text; + } + + var newText = new string(arr.Where(x => x != 0).ToArray()); + if (newText == text) + return newText; + text = newText; + return text; // remove this later to allow for several passes + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/HindiFixer.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/HindiFixer.cs.meta new file mode 100644 index 00000000..1db8cff8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/HindiFixer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7b58f53b44162054f8b586f0cdbe43ba +timeCreated: 1506968129 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/I2Utils.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/I2Utils.cs new file mode 100644 index 00000000..adb1e84b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/I2Utils.cs @@ -0,0 +1,335 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; +using UnityEngine.Networking; +using UnityEngine.SceneManagement; + +namespace TEngine.Localization +{ + public static class I2Utils + { + public const string ValidChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; + public const string NumberChars = "0123456789"; + public const string ValidNameSymbols = ".-_$#@*()[]{}+:?!&',^=<>~`"; + + public static string ReverseText(string source) + { + int len = source.Length; + char[] output = new char[len]; + + char[] separators = { '\r', '\n' }; + for (int istart = 0; istart' && tagType == '<'))) + { + // We've found the end of the tag, so stop skipping characters + insideTag = false; + shouldAppend = false; // Don't append the closing tag character + } + else if (insideTag) + { + // We're inside a tag, so don't append the current character + shouldAppend = false; + } + + // Append the current character if it's not part of a tag + if (shouldAppend) + { + char new_char = ' '; + if (allowCategory && (c == '\\' || c == '\"' || c == '/') || + char.IsLetterOrDigit(c) || + ValidNameSymbols.IndexOf(c) >= 0) + { + new_char = c; + } + + if (char.IsWhiteSpace(c)) + { + if (!skipped) + { + if (result.Length > 0) + result.Append(' '); + + skipped = true; + } + } + else + { + skipped = false; + result.Append(new_char); + } + } + } + + return result.ToString(); // Convert the StringBuilder to a string and return it + } + + public static string SplitLine(string line, int maxCharacters) + { + if (maxCharacters <= 0 || line.Length < maxCharacters) + return line; + + var chars = line.ToCharArray(); + bool insideOfLine = true; + bool allowNewLine = false; + for (int i = 0, nCharsInLine = 0; i < chars.Length; ++i) + { + if (insideOfLine) + { + nCharsInLine++; + if (chars[i] == '\n') + { + nCharsInLine = 0; + } + if (nCharsInLine >= maxCharacters && char.IsWhiteSpace(chars[i])) + { + chars[i] = '\n'; + insideOfLine = false; + allowNewLine = false; + } + } + else + { + if (!char.IsWhiteSpace(chars[i])) + { + insideOfLine = true; + nCharsInLine = 0; + } + else + { + if (chars[i] != '\n') + { + chars[i] = (char)0; + } + else + { + if (!allowNewLine) + chars[i] = (char)0; + allowNewLine = true; + } + } + } + } + + return new string(chars.Where(c => c != (char)0).ToArray()); + } + + public static bool FindNextTag(string line, int iStart, out int tagStart, out int tagEnd) + { + tagStart = -1; + tagEnd = -1; + int len = line.Length; + + // Find where the tag starts + for (tagStart = iStart; tagStart < len; ++tagStart) + if (line[tagStart] == '[' || line[tagStart] == '(' || line[tagStart] == '{' || line[tagStart] == '<') + break; + + if (tagStart == len) + return false; + + bool isArabic = false; + for (tagEnd = tagStart + 1; tagEnd < len; ++tagEnd) + { + char c = line[tagEnd]; + if (c == ']' || c == ')' || c == '}' || c=='>') + { + if (isArabic) return FindNextTag(line, tagEnd + 1, out tagStart, out tagEnd); + return true; + } + if (c > 255) isArabic = true; + } + + // there is an open, but not close character + return false; + } + + public static string RemoveTags(string text) + { + return Regex.Replace(text, @"\{\[(.*?)]}|\[(.*?)]|\<(.*?)>", ""); + } + + public static bool RemoveResourcesPath(ref string sPath) + { + int Ind1 = sPath.IndexOf("\\Resources\\", StringComparison.Ordinal); + int Ind2 = sPath.IndexOf("\\Resources/", StringComparison.Ordinal); + int Ind3 = sPath.IndexOf("/Resources\\", StringComparison.Ordinal); + int Ind4 = sPath.IndexOf("/Resources/", StringComparison.Ordinal); + int Index = Mathf.Max(Ind1, Ind2, Ind3, Ind4); + bool IsResource = false; + if (Index >= 0) + { + sPath = sPath.Substring(Index + 11); + IsResource = true; + } + else + { + // If its not in the Resources, then it has to be in the References + // Therefore, the path has to be stripped and let only the name + Index = sPath.LastIndexOfAny(LanguageSourceData.CategorySeparators); + if (Index > 0) + sPath = sPath.Substring(Index + 1); + } + + string Extension = Path.GetExtension(sPath); + if (!string.IsNullOrEmpty(Extension)) + sPath = sPath.Substring(0, sPath.Length - Extension.Length); + + return IsResource; + } + + public static bool IsPlaying() + { + if (Application.isPlaying) + return true; + #if UNITY_EDITOR + return EditorApplication.isPlayingOrWillChangePlaymode; + #else + return false; + #endif + } + + public static string GetPath(this Transform tr) + { + var parent = tr.parent; + if (tr == null) + return tr.name; + return parent.GetPath() + "/" + tr.name; + } + +#if UNITY_5_3_OR_NEWER + public static Transform FindObject(string objectPath) + { + return FindObject(SceneManager.GetActiveScene(), objectPath); + } + + + public static Transform FindObject(UnityEngine.SceneManagement.Scene scene, string objectPath) + { + //var roots = SceneManager.GetActiveScene().GetRootGameObjects(); + var roots = scene.GetRootGameObjects(); + for (int i=0; i(Transform tr) where H : Component + { + if (!tr) + return null; + + H comp = tr.GetComponent(); + while (!comp && tr) + { + comp = tr.GetComponent(); + tr = tr.parent; + } + return comp; + } + + public static string GetCaptureMatch(Match match) + { + for (int i = match.Groups.Count - 1; i >= 0; --i) + if (match.Groups[i].Success) + { + return match.Groups[i].ToString(); + } + return match.ToString(); + } + + public static void SendWebRequest(UnityWebRequest www ) + { + #if UNITY_2017_2_OR_NEWER + www.SendWebRequest(); + #else + www.Send(); + #endif + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/I2Utils.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/I2Utils.cs.meta new file mode 100644 index 00000000..bae94eba --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/I2Utils.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 7a974f5f5b8a8c94abaf68d987ea0662 +timeCreated: 1516389217 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizationParamsManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizationParamsManager.cs new file mode 100644 index 00000000..14936fc9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizationParamsManager.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine.Localization +{ + public interface ILocalizationParamsManager + { + string GetParameterValue( string Param ); + } + + public class LocalizationParamsManager : MonoBehaviour, ILocalizationParamsManager + { + [Serializable] + public struct ParamValue + { + public string Name, Value; + + } + + [SerializeField] + public List _Params = new List(); + + public bool _IsGlobalManager; + + public string GetParameterValue( string ParamName ) + { + if (_Params != null) + { + for (int i = 0, imax = _Params.Count; i < imax; ++i) + if (_Params[i].Name == ParamName) + return _Params[i].Value; + } + return null; // not found + } + + public void SetParameterValue( string ParamName, string ParamValue, bool localize = true ) + { + bool setted = false; + for (int i = 0, imax = _Params.Count; i < imax; ++i) + if (_Params[i].Name == ParamName) + { + var temp = _Params[i]; + temp.Value = ParamValue; + _Params[i] = temp; + setted = true; + break; + } + if (!setted) + _Params.Add(new ParamValue { Name = ParamName, Value = ParamValue }); + + if (localize) + OnLocalize(); + } + + public void OnLocalize() + { + var loc = GetComponent(); + if (loc != null) + loc.OnLocalize(true); + } + + public virtual void OnEnable() + { + if (_IsGlobalManager) + DoAutoRegister(); + } + + //[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + //public void AutoStart() + //{ + // if (_AutoRegister) + // DoAutoRegister(); + //} + + public void DoAutoRegister() + { + if (!LocalizationManager.ParamManagers.Contains(this)) + { + LocalizationManager.ParamManagers.Add(this); + LocalizationManager.LocalizeAll(true); + } + } + + public void OnDisable() + { + LocalizationManager.ParamManagers.Remove(this); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizationParamsManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizationParamsManager.cs.meta new file mode 100644 index 00000000..0e6360e6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizationParamsManager.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c9586cfd190ca384a8dd72aa92c86152 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizedString.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizedString.cs new file mode 100644 index 00000000..f5428575 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizedString.cs @@ -0,0 +1,42 @@ +using System; + +namespace TEngine.Localization +{ + [Serializable] + public struct LocalizedString + { + public string mTerm; + public bool mRTL_IgnoreArabicFix; + public int mRTL_MaxLineLength; + public bool mRTL_ConvertNumbers; + public bool m_DontLocalizeParameters; + + public static implicit operator string(LocalizedString s) + { + return s.ToString(); + } + + public static implicit operator LocalizedString(string term) + { + return new LocalizedString { mTerm = term }; + } + + public LocalizedString (LocalizedString str) + { + mTerm = str.mTerm; + mRTL_IgnoreArabicFix = str.mRTL_IgnoreArabicFix; + mRTL_MaxLineLength = str.mRTL_MaxLineLength; + mRTL_ConvertNumbers = str.mRTL_ConvertNumbers; + m_DontLocalizeParameters = str.m_DontLocalizeParameters; + } + + + + public override string ToString() + { + var translation = LocalizationManager.GetTranslation(mTerm, !mRTL_IgnoreArabicFix, mRTL_MaxLineLength, !mRTL_ConvertNumbers, true ); + LocalizationManager.ApplyLocalizationParams(ref translation, !m_DontLocalizeParameters); + return translation; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizedString.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizedString.cs.meta new file mode 100644 index 00000000..e3a9cd2f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/LocalizedString.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0bf401b4b1a2c364ba3795d47b95835f +timeCreated: 1478236841 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RTLFixer.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RTLFixer.cs new file mode 100644 index 00000000..5c256d63 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RTLFixer.cs @@ -0,0 +1,971 @@ +using System; +using System.Collections.Generic; + +namespace TEngine.Localization +{ + + public class RTLFixer + { + /// + /// Fix the specified string. + /// + /// + /// String to be fixed. + /// + public static string Fix(string str) + { + return Fix(str, false, true); + } + + public static string Fix(string str, bool rtl) + { + if (rtl) + + { + return Fix(str); + } + + string[] words = str.Split(' '); + string result = ""; + string arabicToIgnore = ""; + foreach (string word in words) + { + if (char.IsLower(word.ToLower()[word.Length / 2])) + { + result += Fix(arabicToIgnore) + word + " "; + arabicToIgnore = ""; + } + else + { + arabicToIgnore += word + " "; + + } + } + if (arabicToIgnore != "") + result += Fix(arabicToIgnore); + + return result; + } + + /// + /// Fix the specified string with customization options. + /// + /// + /// String to be fixed. + /// + /// + /// Show tashkeel. + /// + /// + /// Use hindu numbers. + /// + public static string Fix(string str, bool showTashkeel, bool useHinduNumbers) + { + var newStr = HindiFixer.Fix(str); + if (newStr != str) + return newStr; + RTLFixerTool.showTashkeel = showTashkeel; + RTLFixerTool.useHinduNumbers = useHinduNumbers; + + if (str.Contains("\n")) + str = str.Replace("\n", Environment.NewLine); + + if (str.Contains(Environment.NewLine)) + { + string[] stringSeparators = { Environment.NewLine }; + string[] strSplit = str.Split(stringSeparators, StringSplitOptions.None); + + if (strSplit.Length == 0) + return RTLFixerTool.FixLine(str); + if (strSplit.Length == 1) + return RTLFixerTool.FixLine(str); + string outputString = RTLFixerTool.FixLine(strSplit[0]); + int iteration = 1; + if (strSplit.Length > 1) + { + while (iteration < strSplit.Length) + { + outputString += Environment.NewLine + RTLFixerTool.FixLine(strSplit[iteration]); + iteration++; + } + } + return outputString; + } + + return RTLFixerTool.FixLine(str); + + } + + } + + + /// + /// Arabic Contextual forms General - Unicode + /// + internal enum IsolatedArabicLetters + { + Hamza = 0xFE80, + Alef = 0xFE8D, + AlefHamza = 0xFE83, + WawHamza = 0xFE85, + AlefMaksoor = 0xFE87, + AlefMaksora = 0xFBFC, + HamzaNabera = 0xFE89, + Ba = 0xFE8F, + Ta = 0xFE95, + Tha2 = 0xFE99, + Jeem = 0xFE9D, + H7aa = 0xFEA1, + Khaa2 = 0xFEA5, + Dal = 0xFEA9, + Thal = 0xFEAB, + Ra2 = 0xFEAD, + Zeen = 0xFEAF, + Seen = 0xFEB1, + Sheen = 0xFEB5, + S9a = 0xFEB9, + Dha = 0xFEBD, + T6a = 0xFEC1, + T6ha = 0xFEC5, + Ain = 0xFEC9, + Gain = 0xFECD, + Fa = 0xFED1, + Gaf = 0xFED5, + Kaf = 0xFED9, + Lam = 0xFEDD, + Meem = 0xFEE1, + Noon = 0xFEE5, + Ha = 0xFEE9, + Waw = 0xFEED, + Ya = 0xFEF1, + AlefMad = 0xFE81, + TaMarboota = 0xFE93, + PersianPe = 0xFB56, // Persian Letters; + PersianChe = 0xFB7A, + PersianZe = 0xFB8A, + PersianGaf = 0xFB92, + PersianGaf2 = 0xFB8E + + } + + /// + /// Arabic Contextual forms - Isolated + /// + internal enum GeneralArabicLetters + { + Hamza = 0x0621, + Alef = 0x0627, + AlefHamza = 0x0623, + WawHamza = 0x0624, + AlefMaksoor = 0x0625, + AlefMagsora = 0x0649, + HamzaNabera = 0x0626, + Ba = 0x0628, + Ta = 0x062A, + Tha2 = 0x062B, + Jeem = 0x062C, + H7aa = 0x062D, + Khaa2 = 0x062E, + Dal = 0x062F, + Thal = 0x0630, + Ra2 = 0x0631, + Zeen = 0x0632, + Seen = 0x0633, + Sheen = 0x0634, + S9a = 0x0635, + Dha = 0x0636, + T6a = 0x0637, + T6ha = 0x0638, + Ain = 0x0639, + Gain = 0x063A, + Fa = 0x0641, + Gaf = 0x0642, + Kaf = 0x0643, + Lam = 0x0644, + Meem = 0x0645, + Noon = 0x0646, + Ha = 0x0647, + Waw = 0x0648, + Ya = 0x064A, + AlefMad = 0x0622, + TaMarboota = 0x0629, + PersianPe = 0x067E, // Persian Letters; + PersianChe = 0x0686, + PersianZe = 0x0698, + PersianGaf = 0x06AF, + PersianGaf2 = 0x06A9 + + } + + /// + /// Data Structure for conversion + /// + internal class ArabicMapping + { + public int from; + public int to; + public ArabicMapping(int from, int to) + { + this.from = from; + this.to = to; + } + } + + /// + /// Sets up and creates the conversion table + /// + internal class ArabicTable + { + + private static List mapList; + private static ArabicTable arabicMapper; + + /// + /// Setting up the conversion table + /// + private ArabicTable() + { + mapList = new List(); + + + + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Hamza, (int)IsolatedArabicLetters.Hamza)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Alef, (int)IsolatedArabicLetters.Alef)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.AlefHamza, (int)IsolatedArabicLetters.AlefHamza)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.WawHamza, (int)IsolatedArabicLetters.WawHamza)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.AlefMaksoor, (int)IsolatedArabicLetters.AlefMaksoor)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.AlefMagsora, (int)IsolatedArabicLetters.AlefMaksora)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.HamzaNabera, (int)IsolatedArabicLetters.HamzaNabera)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ba, (int)IsolatedArabicLetters.Ba)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ta, (int)IsolatedArabicLetters.Ta)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Tha2, (int)IsolatedArabicLetters.Tha2)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Jeem, (int)IsolatedArabicLetters.Jeem)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.H7aa, (int)IsolatedArabicLetters.H7aa)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Khaa2, (int)IsolatedArabicLetters.Khaa2)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Dal, (int)IsolatedArabicLetters.Dal)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Thal, (int)IsolatedArabicLetters.Thal)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ra2, (int)IsolatedArabicLetters.Ra2)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Zeen, (int)IsolatedArabicLetters.Zeen)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Seen, (int)IsolatedArabicLetters.Seen)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Sheen, (int)IsolatedArabicLetters.Sheen)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.S9a, (int)IsolatedArabicLetters.S9a)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Dha, (int)IsolatedArabicLetters.Dha)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.T6a, (int)IsolatedArabicLetters.T6a)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.T6ha, (int)IsolatedArabicLetters.T6ha)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ain, (int)IsolatedArabicLetters.Ain)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Gain, (int)IsolatedArabicLetters.Gain)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Fa, (int)IsolatedArabicLetters.Fa)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Gaf, (int)IsolatedArabicLetters.Gaf)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Kaf, (int)IsolatedArabicLetters.Kaf)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Lam, (int)IsolatedArabicLetters.Lam)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Meem, (int)IsolatedArabicLetters.Meem)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Noon, (int)IsolatedArabicLetters.Noon)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ha, (int)IsolatedArabicLetters.Ha)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Waw, (int)IsolatedArabicLetters.Waw)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ya, (int)IsolatedArabicLetters.Ya)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.AlefMad, (int)IsolatedArabicLetters.AlefMad)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.TaMarboota, (int)IsolatedArabicLetters.TaMarboota)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianPe, (int)IsolatedArabicLetters.PersianPe)); // Persian Letters; + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianChe, (int)IsolatedArabicLetters.PersianChe)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianZe, (int)IsolatedArabicLetters.PersianZe)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianGaf, (int)IsolatedArabicLetters.PersianGaf)); + mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianGaf2, (int)IsolatedArabicLetters.PersianGaf2)); + + + + + //for (int i = 0; i < generalArabic.Length; i++) + // mapList.Add(new ArabicMapping((int)generalArabic.GetValue(i), (int)isolatedArabic.GetValue(i))); // I + + + } + + /// + /// Singleton design pattern, Get the mapper. If it was not created before, create it. + /// + internal static ArabicTable ArabicMapper + { + get + { + if (arabicMapper == null) + arabicMapper = new ArabicTable(); + return arabicMapper; + } + } + + internal int Convert(int toBeConverted) + { + + foreach (ArabicMapping arabicMap in mapList) + if (arabicMap.from == toBeConverted) + { + return arabicMap.to; + } + return toBeConverted; + } + + + } + + + internal class TashkeelLocation + { + public char tashkeel; + public int position; + public TashkeelLocation(char tashkeel, int position) + { + this.tashkeel = tashkeel; + this.position = position; + } + } + + + internal class RTLFixerTool + { + internal static bool showTashkeel = true; + internal static bool useHinduNumbers; + + + internal static string RemoveTashkeel(string str, out List tashkeelLocation) + { + tashkeelLocation = new List(); + char[] letters = str.ToCharArray(); + + int index = 0; + for (int i = 0; i < letters.Length; i++) + { + if (letters[i] == (char)0x064B) + { // Tanween Fatha + tashkeelLocation.Add(new TashkeelLocation((char)0x064B, i)); + index++; + } + else if (letters[i] == (char)0x064C) + { // DAMMATAN + tashkeelLocation.Add(new TashkeelLocation((char)0x064C, i)); + index++; + } + else if (letters[i] == (char)0x064D) + { // KASRATAN + tashkeelLocation.Add(new TashkeelLocation((char)0x064D, i)); + index++; + } + else if (letters[i] == (char)0x064E) + { // FATHA + if (index > 0) + { + if (tashkeelLocation[index - 1].tashkeel == (char)0x0651) // SHADDA + { + tashkeelLocation[index - 1].tashkeel = (char)0xFC60; // Shadda With Fatha + continue; + } + } + + tashkeelLocation.Add(new TashkeelLocation((char)0x064E, i)); + index++; + } + else if (letters[i] == (char)0x064F) + { // DAMMA + if (index > 0) + { + if (tashkeelLocation[index - 1].tashkeel == (char)0x0651) + { // SHADDA + tashkeelLocation[index - 1].tashkeel = (char)0xFC61; // Shadda With DAMMA + continue; + } + } + tashkeelLocation.Add(new TashkeelLocation((char)0x064F, i)); + index++; + } + else if (letters[i] == (char)0x0650) + { // KASRA + if (index > 0) + { + if (tashkeelLocation[index - 1].tashkeel == (char)0x0651) + { // SHADDA + tashkeelLocation[index - 1].tashkeel = (char)0xFC62; // Shadda With KASRA + continue; + } + } + tashkeelLocation.Add(new TashkeelLocation((char)0x0650, i)); + index++; + } + else if (letters[i] == (char)0x0651) + { // SHADDA + if (index > 0) + { + if (tashkeelLocation[index - 1].tashkeel == (char)0x064E) // FATHA + { + tashkeelLocation[index - 1].tashkeel = (char)0xFC60; // Shadda With Fatha + continue; + } + + if (tashkeelLocation[index - 1].tashkeel == (char)0x064F) // DAMMA + { + tashkeelLocation[index - 1].tashkeel = (char)0xFC61; // Shadda With DAMMA + continue; + } + + if (tashkeelLocation[index - 1].tashkeel == (char)0x0650) // KASRA + { + tashkeelLocation[index - 1].tashkeel = (char)0xFC62; // Shadda With KASRA + continue; + } + } + + tashkeelLocation.Add(new TashkeelLocation((char)0x0651, i)); + index++; + } + else if (letters[i] == (char)0x0652) + { // SUKUN + tashkeelLocation.Add(new TashkeelLocation((char)0x0652, i)); + index++; + } + else if (letters[i] == (char)0x0653) + { // MADDAH ABOVE + tashkeelLocation.Add(new TashkeelLocation((char)0x0653, i)); + index++; + } + } + + string[] split = str.Split((char)0x064B, (char)0x064C, (char)0x064D, (char)0x064E, (char)0x064F, (char)0x0650, (char)0x0651, (char)0x0652, (char)0x0653, (char)0xFC60, (char)0xFC61, (char)0xFC62); + str = ""; + + foreach (string s in split) + { + str += s; + } + + return str; + } + + internal static char[] ReturnTashkeel(char[] letters, List tashkeelLocation) + { + char[] lettersWithTashkeel = new char[letters.Length + tashkeelLocation.Count]; + + int letterWithTashkeelTracker = 0; + for (int i = 0; i < letters.Length; i++) + { + lettersWithTashkeel[letterWithTashkeelTracker] = letters[i]; + letterWithTashkeelTracker++; + foreach (TashkeelLocation hLocation in tashkeelLocation) + { + if (hLocation.position == letterWithTashkeelTracker) + { + lettersWithTashkeel[letterWithTashkeelTracker] = hLocation.tashkeel; + letterWithTashkeelTracker++; + } + } + } + + return lettersWithTashkeel; + } + + /// + /// Converts a string to a form in which the sting will be displayed correctly for arabic text. + /// + /// String to be converted. Example: "Aaa" + /// Converted string. Example: "aa aaa A" without the spaces. + internal static string FixLine(string str) + { + string test = ""; + + List tashkeelLocation; + + string originString = RemoveTashkeel(str, out tashkeelLocation); + + char[] lettersOrigin = originString.ToCharArray(); + char[] lettersFinal = originString.ToCharArray(); + + + + for (int i = 0; i < lettersOrigin.Length; i++) + { + lettersOrigin[i] = (char)ArabicTable.ArabicMapper.Convert(lettersOrigin[i]); + } + + for (int i = 0; i < lettersOrigin.Length; i++) + { + bool skip = false; + + + //lettersOrigin[i] = (char)ArabicTable.ArabicMapper.Convert(lettersOrigin[i]); + + + // For special Lam Letter connections. + if (lettersOrigin[i] == (char)IsolatedArabicLetters.Lam) + { + + if (i < lettersOrigin.Length - 1) + { + //lettersOrigin[i + 1] = (char)ArabicTable.ArabicMapper.Convert(lettersOrigin[i + 1]); + if (lettersOrigin[i + 1] == (char)IsolatedArabicLetters.AlefMaksoor) + { + lettersOrigin[i] = (char)0xFEF7; + lettersFinal[i + 1] = (char)0xFFFF; + skip = true; + } + else if (lettersOrigin[i + 1] == (char)IsolatedArabicLetters.Alef) + { + lettersOrigin[i] = (char)0xFEF9; + lettersFinal[i + 1] = (char)0xFFFF; + skip = true; + } + else if (lettersOrigin[i + 1] == (char)IsolatedArabicLetters.AlefHamza) + { + lettersOrigin[i] = (char)0xFEF5; + lettersFinal[i + 1] = (char)0xFFFF; + skip = true; + } + else if (lettersOrigin[i + 1] == (char)IsolatedArabicLetters.AlefMad) + { + lettersOrigin[i] = (char)0xFEF3; + lettersFinal[i + 1] = (char)0xFFFF; + skip = true; + } + } + + } + + + if (!IsIgnoredCharacter(lettersOrigin[i])) + { + if (IsMiddleLetter(lettersOrigin, i)) + lettersFinal[i] = (char)(lettersOrigin[i] + 3); + else if (IsFinishingLetter(lettersOrigin, i)) + lettersFinal[i] = (char)(lettersOrigin[i] + 1); + else if (IsLeadingLetter(lettersOrigin, i)) + lettersFinal[i] = (char)(lettersOrigin[i] + 2); + } + + //string strOut = String.Format(@"\x{0:x4}", (ushort)lettersOrigin[i]); + //UnityEngine.Debug.Log(strOut); + + //strOut = String.Format(@"\x{0:x4}", (ushort)lettersFinal[i]); + //UnityEngine.Debug.Log(strOut); + + test += Convert.ToString(lettersOrigin[i], 16) + " "; + if (skip) + i++; + + + //chaning numbers to hindu + if (useHinduNumbers) + { + if (lettersOrigin[i] == (char)0x0030) + lettersFinal[i] = (char)0x0660; + else if (lettersOrigin[i] == (char)0x0031) + lettersFinal[i] = (char)0x0661; + else if (lettersOrigin[i] == (char)0x0032) + lettersFinal[i] = (char)0x0662; + else if (lettersOrigin[i] == (char)0x0033) + lettersFinal[i] = (char)0x0663; + else if (lettersOrigin[i] == (char)0x0034) + lettersFinal[i] = (char)0x0664; + else if (lettersOrigin[i] == (char)0x0035) + lettersFinal[i] = (char)0x0665; + else if (lettersOrigin[i] == (char)0x0036) + lettersFinal[i] = (char)0x0666; + else if (lettersOrigin[i] == (char)0x0037) + lettersFinal[i] = (char)0x0667; + else if (lettersOrigin[i] == (char)0x0038) + lettersFinal[i] = (char)0x0668; + else if (lettersOrigin[i] == (char)0x0039) + lettersFinal[i] = (char)0x0669; + } + + } + + + + //Return the Tashkeel to their places. + if (showTashkeel) + lettersFinal = ReturnTashkeel(lettersFinal, tashkeelLocation); + + + List list = new List(); + + List numberList = new List(); + + for (int i = lettersFinal.Length - 1; i >= 0; i--) + { + + + // if (lettersFinal[i] == '(') + // numberList.Add(')'); + // else if (lettersFinal[i] == ')') + // numberList.Add('('); + // else if (lettersFinal[i] == '<') + // numberList.Add('>'); + // else if (lettersFinal[i] == '>') + // numberList.Add('<'); + // else + if (char.IsPunctuation(lettersFinal[i]) && i > 0 && i < lettersFinal.Length - 1 && + (char.IsPunctuation(lettersFinal[i - 1]) || char.IsPunctuation(lettersFinal[i + 1]))) + { + if (lettersFinal[i] == '(') + list.Add(')'); + else if (lettersFinal[i] == ')') + list.Add('('); + else if (lettersFinal[i] == '<') + list.Add('>'); + else if (lettersFinal[i] == '>') + list.Add('<'); + else if (lettersFinal[i] == '[') + list.Add(']'); + else if (lettersFinal[i] == ']') + list.Add('['); + else if (lettersFinal[i] != 0xFFFF) + list.Add(lettersFinal[i]); + } + // For cases where english words and arabic are mixed. This allows for using arabic, english and numbers in one sentence. + else if (lettersFinal[i] == ' ' && i > 0 && i < lettersFinal.Length - 1 && + (char.IsLower(lettersFinal[i - 1]) || char.IsUpper(lettersFinal[i - 1]) || char.IsNumber(lettersFinal[i - 1])) && + (char.IsLower(lettersFinal[i + 1]) || char.IsUpper(lettersFinal[i + 1]) || char.IsNumber(lettersFinal[i + 1]))) + + { + numberList.Add(lettersFinal[i]); + } + + else if (char.IsNumber(lettersFinal[i]) || char.IsLower(lettersFinal[i]) || + char.IsUpper(lettersFinal[i]) || char.IsSymbol(lettersFinal[i]) || + char.IsPunctuation(lettersFinal[i]))// || lettersFinal[i] == '^') //) + { + + if (lettersFinal[i] == '(') + numberList.Add(')'); + else if (lettersFinal[i] == ')') + numberList.Add('('); + else if (lettersFinal[i] == '<') + numberList.Add('>'); + else if (lettersFinal[i] == '>') + numberList.Add('<'); + else if (lettersFinal[i] == '[') + list.Add(']'); + else if (lettersFinal[i] == ']') + list.Add('['); + else + numberList.Add(lettersFinal[i]); + } + else if (lettersFinal[i] >= (char)0xD800 && lettersFinal[i] <= (char)0xDBFF || + lettersFinal[i] >= (char)0xDC00 && lettersFinal[i] <= (char)0xDFFF) + { + numberList.Add(lettersFinal[i]); + } + else + { + if (numberList.Count > 0) + { + for (int j = 0; j < numberList.Count; j++) + list.Add(numberList[numberList.Count - 1 - j]); + numberList.Clear(); + } + if (lettersFinal[i] != 0xFFFF) + list.Add(lettersFinal[i]); + + } + } + if (numberList.Count > 0) + { + for (int j = 0; j < numberList.Count; j++) + list.Add(numberList[numberList.Count - 1 - j]); + numberList.Clear(); + } + + // Moving letters from a list to an array. + lettersFinal = new char[list.Count]; + for (int i = 0; i < lettersFinal.Length; i++) + lettersFinal[i] = list[i]; + + + str = new string(lettersFinal); + return str; + } + + /// + /// English letters, numbers and punctuation characters are ignored. This checks if the ch is an ignored character. + /// + /// The character to be checked for skipping + /// True if the character should be ignored, false if it should not be ignored. + internal static bool IsIgnoredCharacter(char ch) + { + bool isPunctuation = char.IsPunctuation(ch); + bool isNumber = char.IsNumber(ch); + bool isLower = char.IsLower(ch); + bool isUpper = char.IsUpper(ch); + bool isSymbol = char.IsSymbol(ch); + bool isPersianCharacter = ch == (char)0xFB56 || ch == (char)0xFB7A || ch == (char)0xFB8A || ch == (char)0xFB92 || ch == (char)0xFB8E; + bool isPresentationFormB = ch <= (char)0xFEFF && ch >= (char)0xFE70; + bool isAcceptableCharacter = isPresentationFormB || isPersianCharacter || ch == (char)0xFBFC; + + + + return isPunctuation || + isNumber || + isLower || + isUpper || + isSymbol || + !isAcceptableCharacter || + ch == 'a' || ch == '>' || ch == '<' || ch == (char)0x061B; + + // return char.IsPunctuation(ch) || char.IsNumber(ch) || ch == 'a' || ch == '>' || ch == '<' || + // char.IsLower(ch) || char.IsUpper(ch) || ch == (char)0x061B || char.IsSymbol(ch) + // || !(ch <= (char)0xFEFF && ch >= (char)0xFE70) // Presentation Form B + // || ch == (char)0xFB56 || ch == (char)0xFB7A || ch == (char)0xFB8A || ch == (char)0xFB92; // Persian Characters + + // PersianPe = 0xFB56, + // PersianChe = 0xFB7A, + // PersianZe = 0xFB8A, + // PersianGaf = 0xFB92 + //lettersOrigin[i] <= (char)0xFEFF && lettersOrigin[i] >= (char)0xFE70 + } + + /// + /// Checks if the letter at index value is a leading character in Arabic or not. + /// + /// The whole word that contains the character to be checked + /// The index of the character to be checked + /// True if the character at index is a leading character, else, returns false + internal static bool IsLeadingLetter(char[] letters, int index) + { + + bool lettersThatCannotBeBeforeALeadingLetter = index == 0 + || letters[index - 1] == ' ' + || letters[index - 1] == '*' // ??? Remove? + || letters[index - 1] == 'A' // ??? Remove? + || char.IsPunctuation(letters[index - 1]) + || letters[index - 1] == '>' + || letters[index - 1] == '<' + || letters[index - 1] == (int)IsolatedArabicLetters.Alef + || letters[index - 1] == (int)IsolatedArabicLetters.Dal + || letters[index - 1] == (int)IsolatedArabicLetters.Thal + || letters[index - 1] == (int)IsolatedArabicLetters.Ra2 + || letters[index - 1] == (int)IsolatedArabicLetters.Zeen + || letters[index - 1] == (int)IsolatedArabicLetters.PersianZe + //|| letters[index - 1] == (int)IsolatedArabicLetters.AlefMaksora + || letters[index - 1] == (int)IsolatedArabicLetters.Waw + || letters[index - 1] == (int)IsolatedArabicLetters.AlefMad + || letters[index - 1] == (int)IsolatedArabicLetters.AlefHamza + || letters[index - 1] == (int)IsolatedArabicLetters.AlefMaksoor + || letters[index - 1] == (int)IsolatedArabicLetters.WawHamza; + + bool lettersThatCannotBeALeadingLetter = letters[index] != ' ' + && letters[index] != (int)IsolatedArabicLetters.Dal + && letters[index] != (int)IsolatedArabicLetters.Thal + && letters[index] != (int)IsolatedArabicLetters.Ra2 + && letters[index] != (int)IsolatedArabicLetters.Zeen + && letters[index] != (int)IsolatedArabicLetters.PersianZe + && letters[index] != (int)IsolatedArabicLetters.Alef + && letters[index] != (int)IsolatedArabicLetters.AlefHamza + && letters[index] != (int)IsolatedArabicLetters.AlefMaksoor + && letters[index] != (int)IsolatedArabicLetters.AlefMad + && letters[index] != (int)IsolatedArabicLetters.WawHamza + && letters[index] != (int)IsolatedArabicLetters.Waw + && letters[index] != (int)IsolatedArabicLetters.Hamza; + + bool lettersThatCannotBeAfterLeadingLetter = index < letters.Length - 1 + && letters[index + 1] != ' ' + && !char.IsPunctuation(letters[index + 1]) + && !char.IsNumber(letters[index + 1]) + && !char.IsSymbol(letters[index + 1]) + && !char.IsLower(letters[index + 1]) + && !char.IsUpper(letters[index + 1]) + && letters[index + 1] != (int)IsolatedArabicLetters.Hamza; + + if (lettersThatCannotBeBeforeALeadingLetter && lettersThatCannotBeALeadingLetter && lettersThatCannotBeAfterLeadingLetter) + + // if ((index == 0 || letters[index - 1] == ' ' || letters[index - 1] == '*' || letters[index - 1] == 'A' || char.IsPunctuation(letters[index - 1]) + // || letters[index - 1] == '>' || letters[index - 1] == '<' + // || letters[index - 1] == (int)IsolatedArabicLetters.Alef + // || letters[index - 1] == (int)IsolatedArabicLetters.Dal || letters[index - 1] == (int)IsolatedArabicLetters.Thal + // || letters[index - 1] == (int)IsolatedArabicLetters.Ra2 + // || letters[index - 1] == (int)IsolatedArabicLetters.Zeen || letters[index - 1] == (int)IsolatedArabicLetters.PersianZe + // || letters[index - 1] == (int)IsolatedArabicLetters.AlefMaksora || letters[index - 1] == (int)IsolatedArabicLetters.Waw + // || letters[index - 1] == (int)IsolatedArabicLetters.AlefMad || letters[index - 1] == (int)IsolatedArabicLetters.AlefHamza + // || letters[index - 1] == (int)IsolatedArabicLetters.AlefMaksoor || letters[index - 1] == (int)IsolatedArabicLetters.WawHamza) + // && letters[index] != ' ' && letters[index] != (int)IsolatedArabicLetters.Dal + // && letters[index] != (int)IsolatedArabicLetters.Thal + // && letters[index] != (int)IsolatedArabicLetters.Ra2 + // && letters[index] != (int)IsolatedArabicLetters.Zeen && letters[index] != (int)IsolatedArabicLetters.PersianZe + // && letters[index] != (int)IsolatedArabicLetters.Alef && letters[index] != (int)IsolatedArabicLetters.AlefHamza + // && letters[index] != (int)IsolatedArabicLetters.AlefMaksoor + // && letters[index] != (int)IsolatedArabicLetters.AlefMad + // && letters[index] != (int)IsolatedArabicLetters.WawHamza + // && letters[index] != (int)IsolatedArabicLetters.Waw + // && letters[index] != (int)IsolatedArabicLetters.Hamza + // && index < letters.Length - 1 && letters[index + 1] != ' ' && !char.IsPunctuation(letters[index + 1] ) && !char.IsNumber(letters[index + 1]) + // && letters[index + 1] != (int)IsolatedArabicLetters.Hamza ) + { + return true; + } + + return false; + } + + /// + /// Checks if the letter at index value is a finishing character in Arabic or not. + /// + /// The whole word that contains the character to be checked + /// The index of the character to be checked + /// True if the character at index is a finishing character, else, returns false + internal static bool IsFinishingLetter(char[] letters, int index) + { + //bool indexZero = index != 0; + bool lettersThatCannotBeBeforeAFinishingLetter = index == 0 ? false : + letters[index - 1] != ' ' + // && char.IsDigit(letters[index-1]) + // && char.IsLower(letters[index-1]) + // && char.IsUpper(letters[index-1]) + // && char.IsNumber(letters[index-1]) + // && char.IsWhiteSpace(letters[index-1]) + // && char.IsPunctuation(letters[index-1]) + // && char.IsSymbol(letters[index-1]) + + && letters[index - 1] != (int)IsolatedArabicLetters.Dal + && letters[index - 1] != (int)IsolatedArabicLetters.Thal + && letters[index - 1] != (int)IsolatedArabicLetters.Ra2 + && letters[index - 1] != (int)IsolatedArabicLetters.Zeen + && letters[index - 1] != (int)IsolatedArabicLetters.PersianZe + //&& letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksora + && letters[index - 1] != (int)IsolatedArabicLetters.Waw + && letters[index - 1] != (int)IsolatedArabicLetters.Alef + && letters[index - 1] != (int)IsolatedArabicLetters.AlefMad + && letters[index - 1] != (int)IsolatedArabicLetters.AlefHamza + && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksoor + && letters[index - 1] != (int)IsolatedArabicLetters.WawHamza + && letters[index - 1] != (int)IsolatedArabicLetters.Hamza + + + + && !char.IsPunctuation(letters[index - 1]) + && letters[index - 1] != '>' + && letters[index - 1] != '<'; + + + bool lettersThatCannotBeFinishingLetters = letters[index] != ' ' && letters[index] != (int)IsolatedArabicLetters.Hamza; + + + + + if (lettersThatCannotBeBeforeAFinishingLetter && lettersThatCannotBeFinishingLetters) + + // if (index != 0 && letters[index - 1] != ' ' && letters[index - 1] != '*' && letters[index - 1] != 'A' + // && letters[index - 1] != (int)IsolatedArabicLetters.Dal && letters[index - 1] != (int)IsolatedArabicLetters.Thal + // && letters[index - 1] != (int)IsolatedArabicLetters.Ra2 + // && letters[index - 1] != (int)IsolatedArabicLetters.Zeen && letters[index - 1] != (int)IsolatedArabicLetters.PersianZe + // && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksora && letters[index - 1] != (int)IsolatedArabicLetters.Waw + // && letters[index - 1] != (int)IsolatedArabicLetters.Alef && letters[index - 1] != (int)IsolatedArabicLetters.AlefMad + // && letters[index - 1] != (int)IsolatedArabicLetters.AlefHamza && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksoor + // && letters[index - 1] != (int)IsolatedArabicLetters.WawHamza && letters[index - 1] != (int)IsolatedArabicLetters.Hamza + // && !char.IsPunctuation(letters[index - 1]) && letters[index - 1] != '>' && letters[index - 1] != '<' + // && letters[index] != ' ' && index < letters.Length + // && letters[index] != (int)IsolatedArabicLetters.Hamza) + { + //try + //{ + // if (char.IsPunctuation(letters[index + 1])) + // return true; + // else + // return false; + //} + //catch (Exception e) + //{ + // return false; + //} + + return true; + } + //return true; + + return false; + } + + /// + /// Checks if the letter at index value is a middle character in Arabic or not. + /// + /// The whole word that contains the character to be checked + /// The index of the character to be checked + /// True if the character at index is a middle character, else, returns false + internal static bool IsMiddleLetter(char[] letters, int index) + { + bool lettersThatCannotBeMiddleLetters = index == 0 ? false : + letters[index] != (int)IsolatedArabicLetters.Alef + && letters[index] != (int)IsolatedArabicLetters.Dal + && letters[index] != (int)IsolatedArabicLetters.Thal + && letters[index] != (int)IsolatedArabicLetters.Ra2 + && letters[index] != (int)IsolatedArabicLetters.Zeen + && letters[index] != (int)IsolatedArabicLetters.PersianZe + //&& letters[index] != (int)IsolatedArabicLetters.AlefMaksora + && letters[index] != (int)IsolatedArabicLetters.Waw + && letters[index] != (int)IsolatedArabicLetters.AlefMad + && letters[index] != (int)IsolatedArabicLetters.AlefHamza + && letters[index] != (int)IsolatedArabicLetters.AlefMaksoor + && letters[index] != (int)IsolatedArabicLetters.WawHamza + && letters[index] != (int)IsolatedArabicLetters.Hamza; + + bool lettersThatCannotBeBeforeMiddleCharacters = index == 0 ? false : + letters[index - 1] != (int)IsolatedArabicLetters.Alef + && letters[index - 1] != (int)IsolatedArabicLetters.Dal + && letters[index - 1] != (int)IsolatedArabicLetters.Thal + && letters[index - 1] != (int)IsolatedArabicLetters.Ra2 + && letters[index - 1] != (int)IsolatedArabicLetters.Zeen + && letters[index - 1] != (int)IsolatedArabicLetters.PersianZe + //&& letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksora + && letters[index - 1] != (int)IsolatedArabicLetters.Waw + && letters[index - 1] != (int)IsolatedArabicLetters.AlefMad + && letters[index - 1] != (int)IsolatedArabicLetters.AlefHamza + && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksoor + && letters[index - 1] != (int)IsolatedArabicLetters.WawHamza + && letters[index - 1] != (int)IsolatedArabicLetters.Hamza + && !char.IsPunctuation(letters[index - 1]) + && letters[index - 1] != '>' + && letters[index - 1] != '<' + && letters[index - 1] != ' ' + && letters[index - 1] != '*'; + + bool lettersThatCannotBeAfterMiddleCharacters = index >= letters.Length - 1 ? false : + letters[index + 1] != ' ' + && letters[index + 1] != '\r' + && letters[index + 1] != (int)IsolatedArabicLetters.Hamza + && !char.IsNumber(letters[index + 1]) + && !char.IsSymbol(letters[index + 1]) + && !char.IsPunctuation(letters[index + 1]); + if (lettersThatCannotBeAfterMiddleCharacters && lettersThatCannotBeBeforeMiddleCharacters && lettersThatCannotBeMiddleLetters) + + // if (index != 0 && letters[index] != ' ' + // && letters[index] != (int)IsolatedArabicLetters.Alef && letters[index] != (int)IsolatedArabicLetters.Dal + // && letters[index] != (int)IsolatedArabicLetters.Thal && letters[index] != (int)IsolatedArabicLetters.Ra2 + // && letters[index] != (int)IsolatedArabicLetters.Zeen && letters[index] != (int)IsolatedArabicLetters.PersianZe + // && letters[index] != (int)IsolatedArabicLetters.AlefMaksora + // && letters[index] != (int)IsolatedArabicLetters.Waw && letters[index] != (int)IsolatedArabicLetters.AlefMad + // && letters[index] != (int)IsolatedArabicLetters.AlefHamza && letters[index] != (int)IsolatedArabicLetters.AlefMaksoor + // && letters[index] != (int)IsolatedArabicLetters.WawHamza && letters[index] != (int)IsolatedArabicLetters.Hamza + // && letters[index - 1] != (int)IsolatedArabicLetters.Alef && letters[index - 1] != (int)IsolatedArabicLetters.Dal + // && letters[index - 1] != (int)IsolatedArabicLetters.Thal && letters[index - 1] != (int)IsolatedArabicLetters.Ra2 + // && letters[index - 1] != (int)IsolatedArabicLetters.Zeen && letters[index - 1] != (int)IsolatedArabicLetters.PersianZe + // && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksora + // && letters[index - 1] != (int)IsolatedArabicLetters.Waw && letters[index - 1] != (int)IsolatedArabicLetters.AlefMad + // && letters[index - 1] != (int)IsolatedArabicLetters.AlefHamza && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksoor + // && letters[index - 1] != (int)IsolatedArabicLetters.WawHamza && letters[index - 1] != (int)IsolatedArabicLetters.Hamza + // && letters[index - 1] != '>' && letters[index - 1] != '<' + // && letters[index - 1] != ' ' && letters[index - 1] != '*' && !char.IsPunctuation(letters[index - 1]) + // && index < letters.Length - 1 && letters[index + 1] != ' ' && letters[index + 1] != '\r' && letters[index + 1] != 'A' + // && letters[index + 1] != '>' && letters[index + 1] != '>' && letters[index + 1] != (int)IsolatedArabicLetters.Hamza + // ) + { + try + { + if (char.IsPunctuation(letters[index + 1])) + return false; + return true; + } + catch + { + return false; + } + //return true; + } + + return false; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RTLFixer.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RTLFixer.cs.meta new file mode 100644 index 00000000..7392591b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RTLFixer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cada559fcf5844047b6f6333f8a36012 +timeCreated: 1506968129 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterCallback_AllowSyncFromGoogle.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterCallback_AllowSyncFromGoogle.cs new file mode 100644 index 00000000..14fb9118 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterCallback_AllowSyncFromGoogle.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +namespace TEngine.Localization +{ + public class RegisterCallback_AllowSyncFromGoogle : MonoBehaviour + { + public void Awake() + { + LocalizationManager.Callback_AllowSyncFromGoogle = AllowSyncFromGoogle; + } + + public void OnEnable() + { + LocalizationManager.Callback_AllowSyncFromGoogle = AllowSyncFromGoogle; + } + + public void OnDisable() + { + LocalizationManager.Callback_AllowSyncFromGoogle = null; + } + + public virtual bool AllowSyncFromGoogle(LanguageSourceData Source) + { + return true; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterCallback_AllowSyncFromGoogle.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterCallback_AllowSyncFromGoogle.cs.meta new file mode 100644 index 00000000..2edf9247 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterCallback_AllowSyncFromGoogle.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 893c292e5fa149cf965cc68e2d471396 +timeCreated: 1601758486 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterGlobalParameters.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterGlobalParameters.cs new file mode 100644 index 00000000..6d8fc708 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterGlobalParameters.cs @@ -0,0 +1,28 @@ +using UnityEngine; + +namespace TEngine.Localization +{ + + public class RegisterGlobalParameters : MonoBehaviour, ILocalizationParamsManager + { + public virtual void OnEnable() + { + if (!LocalizationManager.ParamManagers.Contains(this)) + { + LocalizationManager.ParamManagers.Add(this); + LocalizationManager.LocalizeAll(true); + } + } + + public virtual void OnDisable() + { + LocalizationManager.ParamManagers.Remove(this); + } + + public virtual string GetParameterValue( string ParamName ) + { + return null; + } + + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterGlobalParameters.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterGlobalParameters.cs.meta new file mode 100644 index 00000000..a3c5dbb0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/RegisterGlobalParameters.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 31f3671f793c32f47b37480ed345e8fa +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/ResourceManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/ResourceManager.cs new file mode 100644 index 00000000..20a532f9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/ResourceManager.cs @@ -0,0 +1,186 @@ +using UnityEngine; +using System.Collections.Generic; +#if UNITY_5_4_OR_NEWER +using UnityEngine.SceneManagement; +#endif + +namespace TEngine.Localization +{ + public interface IResourceManager_Bundles + { + T LoadFromBundle(string path) where T : UnityEngine.Object; + } + + public class ResourceManager : MonoBehaviour + { + #region Singleton + public static ResourceManager pInstance + { + get { + bool changed = mInstance==null; + + if (mInstance==null) + mInstance = (ResourceManager)FindObjectOfType(typeof(ResourceManager)); + + if (mInstance==null) + { + GameObject GO = new GameObject("I2ResourceManager", typeof(ResourceManager)); + GO.hideFlags = GO.hideFlags | HideFlags.HideAndDontSave; // Only hide it if this manager was autocreated + mInstance = GO.GetComponent(); + #if UNITY_5_4_OR_NEWER + SceneManager.sceneLoaded += MyOnLevelWasLoaded; + #endif + } + + if (changed && Application.isPlaying) + DontDestroyOnLoad(mInstance.gameObject); + + return mInstance; + } + } + static ResourceManager mInstance; + + #endregion + + #region Management + + public List mBundleManagers = new List(); + + #if UNITY_5_4_OR_NEWER + public static void MyOnLevelWasLoaded(UnityEngine.SceneManagement.Scene scene, LoadSceneMode mode) + #else + public void OnLevelWasLoaded() + #endif + { + pInstance.CleanResourceCache(); + LocalizationManager.UpdateSources(); + } + + #endregion + + #region Assets + + public Object[] Assets; + + // This function tries finding an asset in the Assets array, if not found it tries loading it from the Resources Folder + public T GetAsset( string Name ) where T : Object + { + T Obj = FindAsset( Name ) as T; + if (Obj!=null) + return Obj; + + return LoadFromResources( Name ); + } + + Object FindAsset( string Name ) + { + if (Assets!=null) + { + for (int i=0, imax=Assets.Length; i= 0; + } + + #endregion + + #region Resources Cache + + // This cache is kept for a few moments and then cleared + // Its meant to avoid doing several Resource.Load for the same Asset while Localizing + // (e.g. Lot of labels could be trying to Load the same Font) + readonly Dictionary mResourcesCache = new Dictionary(System.StringComparer.Ordinal); // This is used to avoid re-loading the same object from resources in the same frame + //bool mCleaningScheduled = false; + + public T LoadFromResources( string Path ) where T : Object + { + try + { + if (string.IsNullOrEmpty( Path )) + return null; + + Object Obj; + // Doing Resource.Load is very slow so we are catching the recently loaded objects + if (mResourcesCache.TryGetValue( Path, out Obj ) && Obj!=null) + { + return Obj as T; + } + + T obj = null; + + if (Path.EndsWith("]", System.StringComparison.OrdinalIgnoreCase)) // Handle sprites (Multiple) loaded from resources : "SpritePath[SpriteName]" + { + int idx = Path.LastIndexOf("[", System.StringComparison.OrdinalIgnoreCase); + int len = Path.Length - idx - 2; + string MultiSpriteName = Path.Substring(idx + 1, len); + Path = Path.Substring(0, idx); + + T[] objs = Resources.LoadAll(Path); + for (int j = 0, jmax = objs.Length; j < jmax; ++j) + if (objs[j].name.Equals(MultiSpriteName)) + { + obj = objs[j]; + break; + } + } + else + { + obj = Resources.Load(Path, typeof(T)) as T; + } + + if (obj == null) + obj = LoadFromBundle( Path ); + + if (obj!=null) + mResourcesCache[Path] = obj; + + /*if (!mCleaningScheduled) + { + Invoke("CleanResourceCache", 0.1f); + mCleaningScheduled = true; + }*/ + //if (obj==null) + //Debug.LogWarningFormat( "Unable to load {0} '{1}'", typeof( T ), Path ); + + return obj; + } + catch (System.Exception e) + { + Debug.LogErrorFormat( "Unable to load {0} '{1}'\nERROR: {2}", typeof(T), Path, e.ToString() ); + return null; + } + } + + public T LoadFromBundle(string path ) where T : Object + { + for (int i = 0, imax = mBundleManagers.Count; i < imax; ++i) + if (mBundleManagers[i]!=null) + { + var obj = mBundleManagers[i].LoadFromBundle(path); + if (obj != null) + return obj; + } + return null; + } + + public void CleanResourceCache( bool unloadResources=false ) + { + mResourcesCache.Clear(); + if (unloadResources) + Resources.UnloadUnusedAssets(); + + CancelInvoke(); + //mCleaningScheduled = false; + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/ResourceManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/ResourceManager.cs.meta new file mode 100644 index 00000000..9734d609 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/ResourceManager.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f3ae68c55d3a8e44989e08d4686b3db9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguage.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguage.cs new file mode 100644 index 00000000..bbc26dae --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguage.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +namespace TEngine.Localization +{ + [AddComponentMenu("I2/Localization/SetLanguage Button")] + public class SetLanguage : MonoBehaviour + { + public string _Language; + +#if UNITY_EDITOR + public LanguageSource mSource; +#endif + + void OnClick() + { + ApplyLanguage(); + } + + public void ApplyLanguage() + { + if( LocalizationManager.HasLanguage(_Language)) + { + LocalizationManager.CurrentLanguage = _Language; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguage.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguage.cs.meta new file mode 100644 index 00000000..fe2f0f44 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguage.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f8d7972c568b50940a54c7f599af66c5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguageDropdown.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguageDropdown.cs new file mode 100644 index 00000000..800d3358 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguageDropdown.cs @@ -0,0 +1,43 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace TEngine.Localization +{ + [AddComponentMenu("I2/Localization/SetLanguage Dropdown")] + public class SetLanguageDropdown : MonoBehaviour + { + #if UNITY_5_2 || UNITY_5_3 || UNITY_5_4_OR_NEWER + void OnEnable() + { + var dropdown = GetComponent(); + if (dropdown==null) + return; + + var currentLanguage = LocalizationManager.CurrentLanguage; + if (LocalizationManager.Sources.Count==0) LocalizationManager.UpdateSources(); + var languages = LocalizationManager.GetAllLanguages(); + + // Fill the dropdown elements + dropdown.ClearOptions(); + dropdown.AddOptions( languages ); + + dropdown.value = languages.IndexOf( currentLanguage ); + dropdown.onValueChanged.RemoveListener( OnValueChanged ); + dropdown.onValueChanged.AddListener( OnValueChanged ); + } + + + void OnValueChanged( int index ) + { + var dropdown = GetComponent(); + if (index<0) + { + index = 0; + dropdown.value = index; + } + + LocalizationManager.CurrentLanguage = dropdown.options[index].text; + } + #endif + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguageDropdown.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguageDropdown.cs.meta new file mode 100644 index 00000000..10b09caf --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/SetLanguageDropdown.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 33897b093844df84a8e8a0258a1fb0dd +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/StringObfuscator.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/StringObfuscator.cs new file mode 100644 index 00000000..746f6212 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Core/Utils/StringObfuscator.cs @@ -0,0 +1,74 @@ +using System; +using System.Text; + +namespace TEngine.Localization +{ + // Simple String Obfucator + // (not particularly safe, but will stop most players from hacking your strings and its FAST) + + public class StringObfucator + { + // Change this for your projects if you need extra security + public static char[] StringObfuscatorPassword = "ÝúbUu¸CÁ§*4PÚ©-᩾@T6Dl±ÒWâuzÅm4GÐóØ$=Íg,¥Që®iKEßr¡×60Ít4öÃ~^«y:Èd1 + /// 默认本地化辅助器。 + /// + public class DefaultLocalizationHelper + { +#if UNITY_EDITOR + public const string I2GlobalSourcesEditorPath = "Assets/Editor/I2Localization/I2Languages.asset"; +#endif + + public const string I2ResAssetNamePrefix = "I2_"; + + /// + /// 获取系统语言。 + /// + public static Language SystemLanguage + { + get + { + switch (Application.systemLanguage) + { + case UnityEngine.SystemLanguage.Afrikaans: return Language.Afrikaans; + case UnityEngine.SystemLanguage.Arabic: return Language.Arabic; + case UnityEngine.SystemLanguage.Basque: return Language.Basque; + case UnityEngine.SystemLanguage.Belarusian: return Language.Belarusian; + case UnityEngine.SystemLanguage.Bulgarian: return Language.Bulgarian; + case UnityEngine.SystemLanguage.Catalan: return Language.Catalan; + case UnityEngine.SystemLanguage.Chinese: return Language.ChineseSimplified; + case UnityEngine.SystemLanguage.ChineseSimplified: return Language.ChineseSimplified; + case UnityEngine.SystemLanguage.ChineseTraditional: return Language.ChineseTraditional; + case UnityEngine.SystemLanguage.Czech: return Language.Czech; + case UnityEngine.SystemLanguage.Danish: return Language.Danish; + case UnityEngine.SystemLanguage.Dutch: return Language.Dutch; + case UnityEngine.SystemLanguage.English: return Language.English; + case UnityEngine.SystemLanguage.Estonian: return Language.Estonian; + case UnityEngine.SystemLanguage.Faroese: return Language.Faroese; + case UnityEngine.SystemLanguage.Finnish: return Language.Finnish; + case UnityEngine.SystemLanguage.French: return Language.French; + case UnityEngine.SystemLanguage.German: return Language.German; + case UnityEngine.SystemLanguage.Greek: return Language.Greek; + case UnityEngine.SystemLanguage.Hebrew: return Language.Hebrew; + case UnityEngine.SystemLanguage.Hungarian: return Language.Hungarian; + case UnityEngine.SystemLanguage.Icelandic: return Language.Icelandic; + case UnityEngine.SystemLanguage.Indonesian: return Language.Indonesian; + case UnityEngine.SystemLanguage.Italian: return Language.Italian; + case UnityEngine.SystemLanguage.Japanese: return Language.Japanese; + case UnityEngine.SystemLanguage.Korean: return Language.Korean; + case UnityEngine.SystemLanguage.Latvian: return Language.Latvian; + case UnityEngine.SystemLanguage.Lithuanian: return Language.Lithuanian; + case UnityEngine.SystemLanguage.Norwegian: return Language.Norwegian; + case UnityEngine.SystemLanguage.Polish: return Language.Polish; + case UnityEngine.SystemLanguage.Portuguese: return Language.PortuguesePortugal; + case UnityEngine.SystemLanguage.Romanian: return Language.Romanian; + case UnityEngine.SystemLanguage.Russian: return Language.Russian; + case UnityEngine.SystemLanguage.SerboCroatian: return Language.SerboCroatian; + case UnityEngine.SystemLanguage.Slovak: return Language.Slovak; + case UnityEngine.SystemLanguage.Slovenian: return Language.Slovenian; + case UnityEngine.SystemLanguage.Spanish: return Language.Spanish; + case UnityEngine.SystemLanguage.Swedish: return Language.Swedish; + case UnityEngine.SystemLanguage.Thai: return Language.Thai; + case UnityEngine.SystemLanguage.Turkish: return Language.Turkish; + case UnityEngine.SystemLanguage.Ukrainian: return Language.Ukrainian; + case UnityEngine.SystemLanguage.Unknown: return Language.Unspecified; + case UnityEngine.SystemLanguage.Vietnamese: return Language.Vietnamese; + default: return Language.Unspecified; + } + } + } + + private static readonly Dictionary s_LanguageMap = new Dictionary(); + private static readonly Dictionary s_LanguageStrMap = new Dictionary(); + + static DefaultLocalizationHelper() + { + RegisterLanguageMap(Language.English); + RegisterLanguageMap(Language.ChineseSimplified, "Chinese"); + RegisterLanguageMap(Language.ChineseTraditional); + RegisterLanguageMap(Language.Japanese); + RegisterLanguageMap(Language.Korean); + } + + private static void RegisterLanguageMap(Language language, string str = "") + { + if (string.IsNullOrEmpty(str)) + { + str = language.ToString(); + } + + s_LanguageMap[language] = str; + s_LanguageStrMap[str] = language; + } + + /// + /// 根据语言字符串获取语言枚举。 + /// + /// 语言字符串。 + /// 语言枚举。 + public static Language GetLanguage(string str) + { + if (string.IsNullOrEmpty(str)) + { + return Language.Unspecified; + } + if (s_LanguageStrMap.TryGetValue(str, out var language)) + { + return language; + } + + language = Language.English; + return language; + } + + /// + /// 根据语言枚举获取语言字符串。 + /// + /// 语言枚举。 + /// 语言字符串。 + public static string GetLanguageStr(Language language) + { + if (s_LanguageMap.TryGetValue(language, out var ret)) + { + return ret; + } + + ret = "English"; + return ret; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/DefaultLocalizationHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/DefaultLocalizationHelper.cs.meta new file mode 100644 index 00000000..86e3ed7e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/DefaultLocalizationHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57465d541030d834b9d764c79af94e2e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Language.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Language.cs new file mode 100644 index 00000000..e0251dfc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Language.cs @@ -0,0 +1,263 @@ +namespace TEngine +{ + /// + /// 本地化语言。 + /// + public enum Language : byte + { + /// + /// 未指定。 + /// + Unspecified = 0, + + /// + /// 南非荷兰语。 + /// + Afrikaans, + + /// + /// 阿尔巴尼亚语。 + /// + Albanian, + + /// + /// 阿拉伯语。 + /// + Arabic, + + /// + /// 巴斯克语。 + /// + Basque, + + /// + /// 白俄罗斯语。 + /// + Belarusian, + + /// + /// 保加利亚语。 + /// + Bulgarian, + + /// + /// 加泰罗尼亚语。 + /// + Catalan, + + /// + /// 简体中文。 + /// + ChineseSimplified, + + /// + /// 繁体中文。 + /// + ChineseTraditional, + + /// + /// 克罗地亚语。 + /// + Croatian, + + /// + /// 捷克语。 + /// + Czech, + + /// + /// 丹麦语。 + /// + Danish, + + /// + /// 荷兰语。 + /// + Dutch, + + /// + /// 英语。 + /// + English, + + /// + /// 爱沙尼亚语。 + /// + Estonian, + + /// + /// 法罗语。 + /// + Faroese, + + /// + /// 芬兰语。 + /// + Finnish, + + /// + /// 法语。 + /// + French, + + /// + /// 格鲁吉亚语。 + /// + Georgian, + + /// + /// 德语。 + /// + German, + + /// + /// 希腊语。 + /// + Greek, + + /// + /// 希伯来语。 + /// + Hebrew, + + /// + /// 匈牙利语。 + /// + Hungarian, + + /// + /// 冰岛语。 + /// + Icelandic, + + /// + /// 印尼语。 + /// + Indonesian, + + /// + /// 意大利语。 + /// + Italian, + + /// + /// 日语。 + /// + Japanese, + + /// + /// 韩语。 + /// + Korean, + + /// + /// 拉脱维亚语。 + /// + Latvian, + + /// + /// 立陶宛语。 + /// + Lithuanian, + + /// + /// 马其顿语。 + /// + Macedonian, + + /// + /// 马拉雅拉姆语。 + /// + Malayalam, + + /// + /// 挪威语。 + /// + Norwegian, + + /// + /// 波斯语。 + /// + Persian, + + /// + /// 波兰语。 + /// + Polish, + + /// + /// 巴西葡萄牙语。 + /// + PortugueseBrazil, + + /// + /// 葡萄牙语。 + /// + PortuguesePortugal, + + /// + /// 罗马尼亚语。 + /// + Romanian, + + /// + /// 俄语。 + /// + Russian, + + /// + /// 塞尔维亚克罗地亚语。 + /// + SerboCroatian, + + /// + /// 塞尔维亚西里尔语。 + /// + SerbianCyrillic, + + /// + /// 塞尔维亚拉丁语。 + /// + SerbianLatin, + + /// + /// 斯洛伐克语。 + /// + Slovak, + + /// + /// 斯洛文尼亚语。 + /// + Slovenian, + + /// + /// 西班牙语。 + /// + Spanish, + + /// + /// 瑞典语。 + /// + Swedish, + + /// + /// 泰语。 + /// + Thai, + + /// + /// 土耳其语。 + /// + Turkish, + + /// + /// 乌克兰语。 + /// + Ukrainian, + + /// + /// 越南语。 + /// + Vietnamese + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Language.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Language.cs.meta new file mode 100644 index 00000000..5de8e74d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/Language.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8ab44b0472a74109b0a0c1eba66eeb15 +timeCreated: 1710742688 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/LocalizationModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/LocalizationModule.cs new file mode 100644 index 00000000..a1966150 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/LocalizationModule.cs @@ -0,0 +1,313 @@ +using UnityEngine; +using Object = UnityEngine.Object; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Cysharp.Threading.Tasks; +using TEngine.Localization; + +namespace TEngine +{ + /// + /// 本地化组件。 + /// + [DisallowMultipleComponent] + public sealed class LocalizationModule: Module, IResourceManager_Bundles + { + private string m_DefaultLanguage = "Chinese"; + + [SerializeField] private TextAsset m_InnerLocalizationCSV; + + private LanguageSource m_LanguageSource; + + private LanguageSourceData m_SourceData + { + get + { + if (m_LanguageSource == null) + { + m_LanguageSource = gameObject.AddComponent(); + } + + return m_LanguageSource.SourceData; + } + } + + [SerializeField] public List m_AllLanguage = new List(); + + /// + /// 模拟平台运行时 编辑器资源不加载。 + /// + [SerializeField] private bool m_UseRuntimeModule = true; + + private string m_CurrentLanguage; + + /// + /// 获取或设置本地化语言。 + /// + public Language Language + { + get + { + return DefaultLocalizationHelper.GetLanguage(m_CurrentLanguage); + } + set + { + SetLanguage(DefaultLocalizationHelper.GetLanguageStr(value)); + } + } + + /// + /// 获取系统语言。 + /// + public Language SystemLanguage => DefaultLocalizationHelper.SystemLanguage; + + private IResourceManager m_ResourceManager; + + /// + /// 游戏框架组件初始化。 + /// + protected override void Awake() + { + base.Awake(); + + m_ResourceManager = ModuleImpSystem.GetModule(); + if (m_ResourceManager == null) + { + Log.Fatal("Resource component is invalid."); + return; + } + } + + private void Start() + { + RootModule rootModule = ModuleSystem.GetModule(); + if (rootModule == null) + { + Log.Fatal("Base component is invalid."); + return; + } + + m_DefaultLanguage = DefaultLocalizationHelper.GetLanguageStr( + rootModule.EditorLanguage != Language.Unspecified ? rootModule.EditorLanguage : SystemLanguage); + + AsyncInit().Forget(); + } + + private async UniTask AsyncInit() + { + if (string.IsNullOrEmpty(m_DefaultLanguage)) + { + Log.Fatal($"Must set defaultLanguage."); + return false; + } +#if UNITY_EDITOR + if (!m_UseRuntimeModule) + { + LocalizationManager.RegisterSourceInEditor(); + UpdateAllLanguages(); + SetLanguage(m_DefaultLanguage); + } + else + { + m_SourceData.Awake(); + await LoadLanguage(m_DefaultLanguage, true, true); + } +#else + m_SourceData.Awake(); + await LoadLanguage(m_DefaultLanguage, true, true); +#endif + return true; + } + + /// + /// 加载语言总表。 + /// + public async UniTask LoadLanguageTotalAsset(string assetName) + { +#if UNITY_EDITOR + if (!m_UseRuntimeModule) + { + Log.Warning($"禁止在此模式下 动态加载语言"); + return; + } +#endif + TextAsset assetTextAsset= await m_ResourceManager.LoadAssetAsync(assetName); + + if (assetTextAsset == null) + { + Log.Warning($"没有加载到语言总表"); + return; + } + + Log.Info($"加载语言总表成功"); + + UseLocalizationCSV(assetTextAsset.text, true); + } + + /// + /// 加载语言分表。 + /// + /// 语言类型。 + /// 是否立刻设置成当前语言。 + /// 是否初始化Inner语言。 + public async UniTask LoadLanguage(string language, bool setCurrent = false, bool fromInit = false) + { +#if UNITY_EDITOR + if (!m_UseRuntimeModule) + { + Log.Warning($"禁止在此模式下 动态加载语言 {language}"); + return; + } +#endif + TextAsset assetTextAsset; + + if (!fromInit) + { + var assetName = GetLanguageAssetName(language); + + assetTextAsset = await m_ResourceManager.LoadAssetAsync(assetName); + } + else + { + if (m_InnerLocalizationCSV == null) + { + Log.Warning($"请使用I2Localization.asset导出CSV创建内置多语言."); + return; + } + + assetTextAsset = m_InnerLocalizationCSV; + } + + if (assetTextAsset == null) + { + Log.Warning($"没有加载到目标语言资源 {language}"); + return; + } + + Log.Info($"加载语言成功 {language}"); + + UseLocalizationCSV(assetTextAsset.text, !setCurrent); + if (setCurrent) + { + SetLanguage(language); + } + } + + private string GetLanguageAssetName(string language) + { + return $"{DefaultLocalizationHelper.I2ResAssetNamePrefix}{language}"; + } + + /// + /// 检查并初始化所有语言的Id。 + /// + private void UpdateAllLanguages() + { + m_AllLanguage.Clear(); + List allLanguage = LocalizationManager.GetAllLanguages(); + foreach (var language in allLanguage) + { + var newLanguage = Regex.Replace(language, @"[\r\n]", ""); + m_AllLanguage.Add(newLanguage); + } + } + + /// + /// 检查是否存在该语言。 + /// + /// 语言。 + /// 是否已加载。 + public bool CheckLanguage(string language) + { + return m_AllLanguage.Contains(language); + } + + /// + /// 设置当前语言。 + /// + /// 语言名称。 + /// 是否加载。 + /// + public bool SetLanguage(Language language, bool load = false) + { + return SetLanguage(DefaultLocalizationHelper.GetLanguageStr(language), load); + } + + /// + /// 设置当前语言。 + /// + /// 语言名称。 + /// 是否加载。 + /// + public bool SetLanguage(string language, bool load = false) + { + if (!CheckLanguage(language)) + { + if (load) + { + LoadLanguage(language, true).Forget(); + return true; + } + + Log.Warning($"当前没有这个语言无法切换到此语言 {language}"); + return false; + } + + if (m_CurrentLanguage == language) + { + return true; + } + + Log.Info($"设置当前语言 = {language}"); + LocalizationManager.CurrentLanguage = language; + m_CurrentLanguage = language; + return true; + } + + /// + /// 通过语言的Id设置语言。 + /// + /// 语言ID。 + /// 是否设置成功。 + public bool SetLanguage(int languageId) + { + if (languageId < 0 || languageId >= m_AllLanguage.Count) + { + Log.Warning($"Error languageIndex. Could not set and check {languageId} Language.Count = {m_AllLanguage.Count}."); + return false; + } + + var language = m_AllLanguage[languageId]; + return SetLanguage(language); + } + + private void UseLocalizationCSV(string text, bool isLocalizeAll = false) + { + m_SourceData.Import_CSV(string.Empty, text, eSpreadsheetUpdateMode.Merge, ','); + if (isLocalizeAll) + { + LocalizationManager.LocalizeAll(); + } + + UpdateAllLanguages(); + } + + /// + /// 语言模块加载资源接口。 + /// + /// 资源定位地址。 + /// 资源类型。 + /// 返回资源实例。 + public T LoadFromBundle(string path) where T : Object + { + var assetObject = m_ResourceManager.LoadAsset(path); + if (assetObject != null) + { + return assetObject; + } + + Log.Error($"Localization could not load {path} assetsType :{typeof(T).Name}."); + return null; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/Localization/LocalizationModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/LocalizationModule.cs.meta new file mode 100644 index 00000000..4a6e0972 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/Localization/LocalizationModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 706e6317a59f61044b2805be79f6b284 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore.meta new file mode 100644 index 00000000..13146d8a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 462ffa7ba5e34bc8a647e9dcfbc4a2e6 +timeCreated: 1694835557 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/Module.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/Module.cs new file mode 100644 index 00000000..db57bc75 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/Module.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +namespace TEngine +{ + /// + /// 游戏框架模块抽象类。 + /// + public abstract class Module : MonoBehaviour + { + /// + /// 游戏框架模块初始化。 + /// + protected virtual void Awake() + { + ModuleSystem.RegisterModule(this); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/Module.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/Module.cs.meta new file mode 100644 index 00000000..3f944a1d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/Module.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8d03a2850c3d46bfbb20c1b3f0ba28cc +timeCreated: 1694836036 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImp.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImp.cs new file mode 100644 index 00000000..62aa23d4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImp.cs @@ -0,0 +1,40 @@ +using System; + +namespace TEngine +{ + /// + /// 模块需要框架轮询属性。 + /// + /// 注入此属性标识模块需要轮询。 + [AttributeUsage(AttributeTargets.Class)] + internal class UpdateModuleAttribute : Attribute + { + } + + /// + /// 游戏框架模块抽象类。 + /// 实现游戏框架具体逻辑。 + /// + internal abstract class ModuleImp + { + /// + /// 获取游戏框架模块优先级。 + /// + /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 + internal virtual int Priority => 0; + + /// + /// 游戏框架模块轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + internal virtual void Update(float elapseSeconds, float realElapseSeconds) + { + } + + /// + /// 关闭并清理游戏框架模块。 + /// + internal abstract void Shutdown(); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImp.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImp.cs.meta new file mode 100644 index 00000000..e87b58b0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImp.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b4db746c6b3928b4a89a3ce316a8870b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImpSystem.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImpSystem.cs new file mode 100644 index 00000000..1010da38 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImpSystem.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 游戏框架模块实现类管理系统。 + /// + public static class ModuleImpSystem + { + /// + /// 默认设计的模块数量。 + /// 有增删可以自行修改减少内存分配与GCAlloc。 + /// + internal const int DesignModuleCount = 16; + private const string ModuleRootNameSpace = "TEngine."; + + private static readonly Dictionary _moduleMaps = new Dictionary(DesignModuleCount); + private static readonly GameFrameworkLinkedList _modules = new GameFrameworkLinkedList(); + private static readonly GameFrameworkLinkedList _updateModules = new GameFrameworkLinkedList(); + private static readonly List _updateExecuteList = new List(DesignModuleCount); + private static bool _isExecuteListDirty; + + /// + /// 所有游戏框架模块轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + public static void Update(float elapseSeconds, float realElapseSeconds) + { + if (_isExecuteListDirty) + { + _isExecuteListDirty = false; + BuildExecuteList(); + } + + int executeCount = _updateExecuteList.Count; + for (int i = 0; i < executeCount; i++) + { + _updateExecuteList[i].Update(elapseSeconds, realElapseSeconds); + } + } + + /// + /// 关闭并清理所有游戏框架模块。 + /// + public static void Shutdown() + { + for (LinkedListNode current = _modules.Last; current != null; current = current.Previous) + { + current.Value.Shutdown(); + } + + _modules.Clear(); + _moduleMaps.Clear(); + _updateModules.Clear(); + _updateExecuteList.Clear(); + MemoryPool.ClearAll(); + Utility.Marshal.FreeCachedHGlobal(); + } + + /// + /// 获取游戏框架模块。 + /// + /// 要获取的游戏框架模块类型。 + /// 要获取的游戏框架模块。 + /// 如果要获取的游戏框架模块不存在,则自动创建该游戏框架模块。 + public static T GetModule() where T : class + { + Type module = typeof(T); + + if (module.FullName != null && !module.FullName.StartsWith(ModuleRootNameSpace, StringComparison.Ordinal)) + { + throw new GameFrameworkException(Utility.Text.Format("You must get a Framework module, but '{0}' is not.", module.FullName)); + } + + string moduleName = Utility.Text.Format("{0}.{1}", module.Namespace, module.Name.Substring(1)); + Type moduleType = Type.GetType(moduleName); + if (moduleType == null) + { + moduleName = Utility.Text.Format("{0}.{1}", module.Namespace, module.Name); + moduleType = Type.GetType(moduleName); + if (moduleType == null) + { + throw new GameFrameworkException(Utility.Text.Format("Can not find Game Framework module type '{0}'.", moduleName)); + } + } + + return GetModule(moduleType) as T; + } + + /// + /// 获取游戏框架模块。 + /// + /// 要获取的游戏框架模块类型。 + /// 要获取的游戏框架模块。 + /// 如果要获取的游戏框架模块不存在,则自动创建该游戏框架模块。 + private static ModuleImp GetModule(Type moduleType) + { + return _moduleMaps.TryGetValue(moduleType, out ModuleImp module) ? module : CreateModule(moduleType); + } + + /// + /// 创建游戏框架模块。 + /// + /// 要创建的游戏框架模块类型。 + /// 要创建的游戏框架模块。 + private static ModuleImp CreateModule(Type moduleType) + { + ModuleImp moduleImp = (ModuleImp)Activator.CreateInstance(moduleType); + if (moduleImp == null) + { + throw new GameFrameworkException(Utility.Text.Format("Can not create module '{0}'.", moduleType.FullName)); + } + + _moduleMaps[moduleType] = moduleImp; + + LinkedListNode current = _modules.First; + while (current != null) + { + if (moduleImp.Priority > current.Value.Priority) + { + break; + } + + current = current.Next; + } + + if (current != null) + { + _modules.AddBefore(current, moduleImp); + } + else + { + _modules.AddLast(moduleImp); + } + + if (Attribute.GetCustomAttribute(moduleType, typeof(UpdateModuleAttribute)) is UpdateModuleAttribute updateModuleAttribute) + { + LinkedListNode currentUpdate = _updateModules.First; + while (currentUpdate != null) + { + if (moduleImp.Priority > currentUpdate.Value.Priority) + { + break; + } + + currentUpdate = currentUpdate.Next; + } + + if (currentUpdate != null) + { + _updateModules.AddBefore(currentUpdate, moduleImp); + } + else + { + _updateModules.AddLast(moduleImp); + } + + _isExecuteListDirty = true; + } + + return moduleImp; + } + + /// + /// 构造执行队列。 + /// + private static void BuildExecuteList() + { + _updateExecuteList.Clear(); + _updateExecuteList.AddRange(_updateModules); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImpSystem.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImpSystem.cs.meta new file mode 100644 index 00000000..8262c0ed --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleImpSystem.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: eb600bcb941e4094a006a6780098c241 +timeCreated: 1694796997 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleSystem.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleSystem.cs new file mode 100644 index 00000000..82857706 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleSystem.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace TEngine +{ + /// + /// 游戏框架模块管理系统。 + /// + public static class ModuleSystem + { + private static readonly GameFrameworkLinkedList _modules = new GameFrameworkLinkedList(); + + /// + /// 游戏框架所在的场景编号。 + /// + internal const int GameFrameworkSceneId = 0; + + /// + /// 获取游戏框架模块。 + /// + /// 要获取的游戏框架模块类型。 + /// 要获取的游戏框架模块。 + public static T GetModule() where T : Module + { + return (T)GetModule(typeof(T)); + } + + /// + /// 获取游戏框架模块。 + /// + /// 要获取的游戏框架模块类型。 + /// 要获取的游戏框架模块。 + public static Module GetModule(Type type) + { + LinkedListNode current = _modules.First; + while (current != null) + { + if (current.Value.GetType() == type) + { + return current.Value; + } + + current = current.Next; + } + + return null; + } + + /// + /// 获取游戏框架模块。 + /// + /// 要获取的游戏框架模块类型名称。 + /// 要获取的游戏框架模块。 + public static Module GetModule(string typeName) + { + LinkedListNode current = _modules.First; + while (current != null) + { + Type type = current.Value.GetType(); + if (type.FullName == typeName || type.Name == typeName) + { + return current.Value; + } + + current = current.Next; + } + + return null; + } + + /// + /// 关闭游戏框架。 + /// + /// 关闭游戏框架类型。 + public static void Shutdown(ShutdownType shutdownType) + { + Log.Info("Shutdown Game Framework ({0})...", shutdownType); + Utility.Unity.Shutdown(); + RootModule rootModule = GetModule(); + if (rootModule != null) + { + rootModule.Shutdown(); + rootModule = null; + } + _modules.Clear(); + + GameModule.Shutdown(shutdownType); + GameEvent.Shutdown(); + + if (shutdownType == ShutdownType.None) + { + return; + } + + if (shutdownType == ShutdownType.Restart) + { + SceneManager.LoadScene(GameFrameworkSceneId); + return; + } + + if (shutdownType == ShutdownType.Quit) + { + Application.Quit(); +#if UNITY_EDITOR + UnityEditor.EditorApplication.isPlaying = false; +#endif + } + } + + /// + /// 注册游戏框架模块。 + /// + /// 要注册的游戏框架模块。 + internal static void RegisterModule(Module module) + { + if (module == null) + { + Log.Error("TEngine Module is invalid."); + return; + } + + Type type = module.GetType(); + + LinkedListNode current = _modules.First; + while (current != null) + { + if (current.Value.GetType() == type) + { + Log.Error("Game Framework component type '{0}' is already exist.", type.FullName); + return; + } + + current = current.Next; + } + + _modules.AddLast(module); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleSystem.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleSystem.cs.meta new file mode 100644 index 00000000..b003bbc9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ModuleSystem.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d3f0059418a84d0d8aaebdbc005bb1f5 +timeCreated: 1694839938 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ShutdownType.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ShutdownType.cs new file mode 100644 index 00000000..9e6ab52b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ShutdownType.cs @@ -0,0 +1,23 @@ +namespace TEngine +{ + /// + /// 关闭游戏框架类型。 + /// + public enum ShutdownType : byte + { + /// + /// 仅关闭游戏框架。 + /// + None = 0, + + /// + /// 关闭游戏框架并重启游戏。 + /// + Restart, + + /// + /// 关闭游戏框架并退出游戏。 + /// + Quit, + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ShutdownType.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ShutdownType.cs.meta new file mode 100644 index 00000000..55f3e5d8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ModuleCore/ShutdownType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e004d71ac8074d1ab0021efcf433f34d +timeCreated: 1694840037 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule.meta new file mode 100644 index 00000000..632f9d2d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a428e9130101d942bb8da0dc04f50d3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPool.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPool.cs new file mode 100644 index 00000000..91f59d3e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPool.cs @@ -0,0 +1,211 @@ +using System; + +namespace TEngine +{ + /// + /// 对象池接口。 + /// + /// 对象类型。 + public interface IObjectPool where T : ObjectBase + { + /// + /// 获取对象池名称。 + /// + string Name + { + get; + } + + /// + /// 获取对象池完整名称。 + /// + string FullName + { + get; + } + + /// + /// 获取对象池对象类型。 + /// + Type ObjectType + { + get; + } + + /// + /// 获取对象池中对象的数量。 + /// + int Count + { + get; + } + + /// + /// 获取对象池中能被释放的对象的数量。 + /// + int CanReleaseCount + { + get; + } + + /// + /// 获取是否允许对象被多次获取。 + /// + bool AllowMultiSpawn + { + get; + } + + /// + /// 获取或设置对象池自动释放可释放对象的间隔秒数。 + /// + float AutoReleaseInterval + { + get; + set; + } + + /// + /// 获取或设置对象池的容量。 + /// + int Capacity + { + get; + set; + } + + /// + /// 获取或设置对象池对象过期秒数。 + /// + float ExpireTime + { + get; + set; + } + + /// + /// 获取或设置对象池的优先级。 + /// + int Priority + { + get; + set; + } + + /// + /// 创建对象。 + /// + /// 对象。 + /// 对象是否已被获取。 + void Register(T obj, bool spawned); + + /// + /// 检查对象。 + /// + /// 要检查的对象是否存在。 + bool CanSpawn(); + + /// + /// 检查对象。 + /// + /// 对象名称。 + /// 要检查的对象是否存在。 + bool CanSpawn(string name); + + /// + /// 获取对象。 + /// + /// 要获取的对象。 + T Spawn(); + + /// + /// 获取对象。 + /// + /// 对象名称。 + /// 要获取的对象。 + T Spawn(string name); + + /// + /// 回收对象。 + /// + /// 要回收的对象。 + void Unspawn(T obj); + + /// + /// 回收对象。 + /// + /// 要回收的对象。 + void Unspawn(object target); + + /// + /// 设置对象是否被加锁。 + /// + /// 要设置被加锁的对象。 + /// 是否被加锁。 + void SetLocked(T obj, bool locked); + + /// + /// 设置对象是否被加锁。 + /// + /// 要设置被加锁的对象。 + /// 是否被加锁。 + void SetLocked(object target, bool locked); + + /// + /// 设置对象的优先级。 + /// + /// 要设置优先级的对象。 + /// 优先级。 + void SetPriority(T obj, int priority); + + /// + /// 设置对象的优先级。 + /// + /// 要设置优先级的对象。 + /// 优先级。 + void SetPriority(object target, int priority); + + /// + /// 释放对象。 + /// + /// 要释放的对象。 + /// 释放对象是否成功。 + bool ReleaseObject(T obj); + + /// + /// 释放对象。 + /// + /// 要释放的对象。 + /// 释放对象是否成功。 + bool ReleaseObject(object target); + + /// + /// 释放对象池中的可释放对象。 + /// + void Release(); + + /// + /// 释放对象池中的可释放对象。 + /// + /// 尝试释放对象数量。 + void Release(int toReleaseCount); + + /// + /// 释放对象池中的可释放对象。 + /// + /// 释放对象筛选函数。 + void Release(ReleaseObjectFilterCallback releaseObjectFilterCallback); + + /// + /// 释放对象池中的可释放对象。 + /// + /// 尝试释放对象数量。 + /// 释放对象筛选函数。 + void Release(int toReleaseCount, ReleaseObjectFilterCallback releaseObjectFilterCallback); + + /// + /// 释放对象池中的所有未使用对象。 + /// + void ReleaseAllUnused(); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPool.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPool.cs.meta new file mode 100644 index 00000000..99dee097 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1582208c233e48f9b3707a8ebc230df7 +timeCreated: 1680501171 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPoolManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPoolManager.cs new file mode 100644 index 00000000..4064e27c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPoolManager.cs @@ -0,0 +1,744 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 对象池管理器。 + /// + public interface IObjectPoolManager + { + /// + /// 获取对象池数量。 + /// + int Count + { + get; + } + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 是否存在对象池。 + bool HasObjectPool() where T : ObjectBase; + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 是否存在对象池。 + bool HasObjectPool(Type objectType); + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 是否存在对象池。 + bool HasObjectPool(string name) where T : ObjectBase; + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 是否存在对象池。 + bool HasObjectPool(Type objectType, string name); + + /// + /// 检查是否存在对象池。 + /// + /// 要检查的条件。 + /// 是否存在对象池。 + bool HasObjectPool(Predicate condition); + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 要获取的对象池。 + IObjectPool GetObjectPool() where T : ObjectBase; + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 要获取的对象池。 + ObjectPoolBase GetObjectPool(Type objectType); + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要获取的对象池。 + IObjectPool GetObjectPool(string name) where T : ObjectBase; + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要获取的对象池。 + ObjectPoolBase GetObjectPool(Type objectType, string name); + + /// + /// 获取对象池。 + /// + /// 要检查的条件。 + /// 要获取的对象池。 + ObjectPoolBase GetObjectPool(Predicate condition); + + /// + /// 获取对象池。 + /// + /// 要检查的条件。 + /// 要获取的对象池。 + ObjectPoolBase[] GetObjectPools(Predicate condition); + + /// + /// 获取对象池。 + /// + /// 要检查的条件。 + /// 要获取的对象池。 + void GetObjectPools(Predicate condition, List results); + + /// + /// 获取所有对象池。 + /// + /// 所有对象池。 + ObjectPoolBase[] GetAllObjectPools(); + + /// + /// 获取所有对象池。 + /// + /// 所有对象池。 + void GetAllObjectPools(List results); + + /// + /// 获取所有对象池。 + /// + /// 是否根据对象池的优先级排序。 + /// 所有对象池。 + ObjectPoolBase[] GetAllObjectPools(bool sort); + + /// + /// 获取所有对象池。 + /// + /// 是否根据对象池的优先级排序。 + /// 所有对象池。 + void GetAllObjectPools(bool sort, List results); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool() where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(string name) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(int capacity) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(float expireTime) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(string name, int capacity) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(int capacity, int priority) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, int priority); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime, int priority); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, int priority); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime, int priority); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority); + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + IObjectPool CreateSingleSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool() where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(string name) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(int capacity) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(float expireTime) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(string name, int capacity) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(int capacity, int priority) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, int priority); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime, int priority); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, int priority); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime, int priority); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority); + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + IObjectPool CreateMultiSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) where T : ObjectBase; + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority); + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 是否销毁对象池成功。 + bool DestroyObjectPool() where T : ObjectBase; + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 是否销毁对象池成功。 + bool DestroyObjectPool(Type objectType); + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 要销毁的对象池名称。 + /// 是否销毁对象池成功。 + bool DestroyObjectPool(string name) where T : ObjectBase; + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 要销毁的对象池名称。 + /// 是否销毁对象池成功。 + bool DestroyObjectPool(Type objectType, string name); + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 要销毁的对象池。 + /// 是否销毁对象池成功。 + bool DestroyObjectPool(IObjectPool objectPool) where T : ObjectBase; + + /// + /// 销毁对象池。 + /// + /// 要销毁的对象池。 + /// 是否销毁对象池成功。 + bool DestroyObjectPool(ObjectPoolBase objectPool); + + /// + /// 释放对象池中的可释放对象。 + /// + void Release(); + + /// + /// 释放对象池中的所有未使用对象。 + /// + void ReleaseAllUnused(); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPoolManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPoolManager.cs.meta new file mode 100644 index 00000000..24030d9f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/IObjectPoolManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 669817740b024599b6f700ecc9fd0db8 +timeCreated: 1680501171 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectBase.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectBase.cs new file mode 100644 index 00000000..7420de12 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectBase.cs @@ -0,0 +1,164 @@ +using System; + +namespace TEngine +{ + /// + /// 对象基类。 + /// + public abstract class ObjectBase : IMemory + { + private string _name; + private object _target; + private bool _locked; + private int _priority; + private DateTime _lastUseTime; + + /// + /// 初始化对象基类的新实例。 + /// + public ObjectBase() + { + _name = null; + _target = null; + _locked = false; + _priority = 0; + _lastUseTime = default(DateTime); + } + + /// + /// 获取对象名称。 + /// + public string Name => _name; + + /// + /// 获取对象。 + /// + public object Target => _target; + + /// + /// 获取或设置对象是否被加锁。 + /// + public bool Locked + { + get => _locked; + set => _locked = value; + } + + /// + /// 获取或设置对象的优先级。 + /// + public int Priority + { + get => _priority; + set => _priority = value; + } + + /// + /// 获取自定义释放检查标记。 + /// + public virtual bool CustomCanReleaseFlag => true; + + /// + /// 获取对象上次使用时间。 + /// + public DateTime LastUseTime + { + get => _lastUseTime; + internal set => _lastUseTime = value; + } + + /// + /// 初始化对象基类。 + /// + /// 对象。 + protected void Initialize(object target) + { + Initialize(null, target, false, 0); + } + + /// + /// 初始化对象基类。 + /// + /// 对象名称。 + /// 对象。 + protected void Initialize(string name, object target) + { + Initialize(name, target, false, 0); + } + + /// + /// 初始化对象基类。 + /// + /// 对象名称。 + /// 对象。 + /// 对象是否被加锁。 + protected void Initialize(string name, object target, bool locked) + { + Initialize(name, target, locked, 0); + } + + /// + /// 初始化对象基类。 + /// + /// 对象名称。 + /// 对象。 + /// 对象的优先级。 + protected void Initialize(string name, object target, int priority) + { + Initialize(name, target, false, priority); + } + + /// + /// 初始化对象基类。 + /// + /// 对象名称。 + /// 对象。 + /// 对象是否被加锁。 + /// 对象的优先级。 + protected void Initialize(string name, object target, bool locked, int priority) + { + if (target == null) + { + throw new GameFrameworkException(Utility.Text.Format("Target '{0}' is invalid.", name)); + } + + _name = name ?? string.Empty; + _target = target; + _locked = locked; + _priority = priority; + _lastUseTime = DateTime.UtcNow; + } + + /// + /// 清理对象基类。 + /// + public virtual void Clear() + { + _name = null; + _target = null; + _locked = false; + _priority = 0; + _lastUseTime = default(DateTime); + } + + /// + /// 获取对象时的事件。 + /// + protected internal virtual void OnSpawn() + { + } + + /// + /// 回收对象时的事件。 + /// + protected internal virtual void OnUnspawn() + { + } + + /// + /// 释放对象。 + /// + /// 是否是关闭对象池时触发。 + protected internal abstract void Release(bool isShutdown); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectBase.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectBase.cs.meta new file mode 100644 index 00000000..1777cf2e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectBase.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 524a94dffe1f4918a09b5922fba3778b +timeCreated: 1680501171 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectInfo.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectInfo.cs new file mode 100644 index 00000000..1414eea6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectInfo.cs @@ -0,0 +1,73 @@ +using System; +using System.Runtime.InteropServices; + +namespace TEngine +{ + /// + /// 对象信息。 + /// + [StructLayout(LayoutKind.Auto)] + public struct ObjectInfo + { + private readonly string m_Name; + private readonly bool m_Locked; + private readonly bool m_CustomCanReleaseFlag; + private readonly int m_Priority; + private readonly DateTime m_LastUseTime; + private readonly int m_SpawnCount; + + /// + /// 初始化对象信息的新实例。 + /// + /// 对象名称。 + /// 对象是否被加锁。 + /// 对象自定义释放检查标记。 + /// 对象的优先级。 + /// 对象上次使用时间。 + /// 对象的获取计数。 + public ObjectInfo(string name, bool locked, bool customCanReleaseFlag, int priority, DateTime lastUseTime, int spawnCount) + { + m_Name = name; + m_Locked = locked; + m_CustomCanReleaseFlag = customCanReleaseFlag; + m_Priority = priority; + m_LastUseTime = lastUseTime; + m_SpawnCount = spawnCount; + } + + /// + /// 获取对象名称。 + /// + public string Name => m_Name; + + /// + /// 获取对象是否被加锁。 + /// + public bool Locked => m_Locked; + + /// + /// 获取对象自定义释放检查标记。 + /// + public bool CustomCanReleaseFlag => m_CustomCanReleaseFlag; + + /// + /// 获取对象的优先级。 + /// + public int Priority => m_Priority; + + /// + /// 获取对象上次使用时间。 + /// + public DateTime LastUseTime => m_LastUseTime; + + /// + /// 获取对象是否正在使用。 + /// + public bool IsInUse => m_SpawnCount > 0; + + /// + /// 获取对象的获取计数。 + /// + public int SpawnCount => m_SpawnCount; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectInfo.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectInfo.cs.meta new file mode 100644 index 00000000..701ca5c1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5269851c1924478e8f3150fc57f8d36f +timeCreated: 1680501171 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolBase.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolBase.cs new file mode 100644 index 00000000..73a7b965 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolBase.cs @@ -0,0 +1,133 @@ +using System; + +namespace TEngine +{ + /// + /// 对象池基类。 + /// + public abstract class ObjectPoolBase + { + private readonly string m_Name; + + /// + /// 初始化对象池基类的新实例。 + /// + public ObjectPoolBase() + : this(null) + { + } + + /// + /// 初始化对象池基类的新实例。 + /// + /// 对象池名称。 + public ObjectPoolBase(string name) + { + m_Name = name ?? string.Empty; + } + + /// + /// 获取对象池名称。 + /// + public string Name => m_Name; + + /// + /// 获取对象池完整名称。 + /// + public string FullName => new TypeNamePair(ObjectType, m_Name).ToString(); + + /// + /// 获取对象池对象类型。 + /// + public abstract Type ObjectType + { + get; + } + + /// + /// 获取对象池中对象的数量。 + /// + public abstract int Count + { + get; + } + + /// + /// 获取对象池中能被释放的对象的数量。 + /// + public abstract int CanReleaseCount + { + get; + } + + /// + /// 获取是否允许对象被多次获取。 + /// + public abstract bool AllowMultiSpawn + { + get; + } + + /// + /// 获取或设置对象池自动释放可释放对象的间隔秒数。 + /// + public abstract float AutoReleaseInterval + { + get; + set; + } + + /// + /// 获取或设置对象池的容量。 + /// + public abstract int Capacity + { + get; + set; + } + + /// + /// 获取或设置对象池对象过期秒数。 + /// + public abstract float ExpireTime + { + get; + set; + } + + /// + /// 获取或设置对象池的优先级。 + /// + public abstract int Priority + { + get; + set; + } + + /// + /// 释放对象池中的可释放对象。 + /// + public abstract void Release(); + + /// + /// 释放对象池中的可释放对象。 + /// + /// 尝试释放对象数量。 + public abstract void Release(int toReleaseCount); + + /// + /// 释放对象池中的所有未使用对象。 + /// + public abstract void ReleaseAllUnused(); + + /// + /// 获取所有对象信息。 + /// + /// 所有对象信息。 + public abstract ObjectInfo[] GetAllObjectInfos(); + + internal abstract void Update(float elapseSeconds, float realElapseSeconds); + + internal abstract void Shutdown(); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolBase.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolBase.cs.meta new file mode 100644 index 00000000..10f7822b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolBase.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f8ab28e091804ce3ba660e7948f37ca8 +timeCreated: 1680501171 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.Object.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.Object.cs new file mode 100644 index 00000000..0074fc57 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.Object.cs @@ -0,0 +1,189 @@ +using System; + +namespace TEngine +{ + internal sealed partial class ObjectPoolManager : ModuleImp, IObjectPoolManager + { + /// + /// 内部对象。 + /// + /// 对象类型。 + private sealed class Object : IMemory where T : ObjectBase + { + private T _object; + private int _spawnCount; + + /// + /// 初始化内部对象的新实例。 + /// + public Object() + { + _object = null; + _spawnCount = 0; + } + + /// + /// 获取对象名称。 + /// + public string Name + { + get + { + return _object.Name; + } + } + + /// + /// 获取对象是否被加锁。 + /// + public bool Locked + { + get + { + return _object.Locked; + } + internal set + { + _object.Locked = value; + } + } + + /// + /// 获取对象的优先级。 + /// + public int Priority + { + get + { + return _object.Priority; + } + internal set + { + _object.Priority = value; + } + } + + /// + /// 获取自定义释放检查标记。 + /// + public bool CustomCanReleaseFlag + { + get + { + return _object.CustomCanReleaseFlag; + } + } + + /// + /// 获取对象上次使用时间。 + /// + public DateTime LastUseTime + { + get + { + return _object.LastUseTime; + } + } + + /// + /// 获取对象是否正在使用。 + /// + public bool IsInUse + { + get + { + return _spawnCount > 0; + } + } + + /// + /// 获取对象的获取计数。 + /// + public int SpawnCount + { + get + { + return _spawnCount; + } + } + + /// + /// 创建内部对象。 + /// + /// 对象。 + /// 对象是否已被获取。 + /// 创建的内部对象。 + public static Object Create(T obj, bool spawned) + { + if (obj == null) + { + throw new GameFrameworkException("Object is invalid."); + } + + Object internalObject = MemoryPool.Acquire>(); + internalObject._object = obj; + internalObject._spawnCount = spawned ? 1 : 0; + if (spawned) + { + obj.OnSpawn(); + } + + return internalObject; + } + + /// + /// 清理内部对象。 + /// + public void Clear() + { + _object = null; + _spawnCount = 0; + } + + /// + /// 查看对象。 + /// + /// 对象。 + public T Peek() + { + return _object; + } + + /// + /// 获取对象。 + /// + /// 对象。 + public T Spawn() + { + _spawnCount++; + _object.LastUseTime = DateTime.UtcNow; + _object.OnSpawn(); + return _object; + } + + /// + /// 回收对象。 + /// + public void Unspawn() + { + _object.OnUnspawn(); + _object.LastUseTime = DateTime.UtcNow; + _spawnCount--; + if (_spawnCount < 0) + { + throw new GameFrameworkException(Utility.Text.Format("Object '{0}' spawn count is less than 0.", Name)); + } + } + + /// + /// 释放对象。 + /// + /// 是否是关闭对象池时触发。 + public void Release(bool isShutdown) + { + _object.Release(isShutdown); + MemoryPool.Release(_object); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.Object.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.Object.cs.meta new file mode 100644 index 00000000..2d73bd11 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.Object.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 979efb6cb1ae4b36a4296a8229aea3ff +timeCreated: 1680501171 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.ObjectPool.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.ObjectPool.cs new file mode 100644 index 00000000..77bb793b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.ObjectPool.cs @@ -0,0 +1,602 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + internal sealed partial class ObjectPoolManager : ModuleImp, IObjectPoolManager + { + /// + /// 对象池。 + /// + /// 对象类型。 + private sealed class ObjectPool : ObjectPoolBase, IObjectPool where T : ObjectBase + { + private readonly GameFrameworkMultiDictionary> _objects; + private readonly Dictionary> _objectMap; + private readonly ReleaseObjectFilterCallback _defaultReleaseObjectFilterCallback; + private readonly List _cachedCanReleaseObjects; + private readonly List _cachedToReleaseObjects; + private readonly bool _allowMultiSpawn; + private float _autoReleaseInterval; + private int _capacity; + private float _expireTime; + private int _priority; + private float _autoReleaseTime; + + /// + /// 初始化对象池的新实例。 + /// + /// 对象池名称。 + /// 是否允许对象被多次获取。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + public ObjectPool(string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, int priority) + : base(name) + { + _objects = new GameFrameworkMultiDictionary>(); + _objectMap = new Dictionary>(); + _defaultReleaseObjectFilterCallback = DefaultReleaseObjectFilterCallback; + _cachedCanReleaseObjects = new List(); + _cachedToReleaseObjects = new List(); + _allowMultiSpawn = allowMultiSpawn; + _autoReleaseInterval = autoReleaseInterval; + Capacity = capacity; + ExpireTime = expireTime; + _priority = priority; + _autoReleaseTime = 0f; + } + + /// + /// 获取对象池对象类型。 + /// + public override Type ObjectType => typeof(T); + + /// + /// 获取对象池中对象的数量。 + /// + public override int Count => _objectMap.Count; + + /// + /// 获取对象池中能被释放的对象的数量。 + /// + public override int CanReleaseCount + { + get + { + GetCanReleaseObjects(_cachedCanReleaseObjects); + return _cachedCanReleaseObjects.Count; + } + } + + /// + /// 获取是否允许对象被多次获取。 + /// + public override bool AllowMultiSpawn => _allowMultiSpawn; + + /// + /// 获取或设置对象池自动释放可释放对象的间隔秒数。 + /// + public override float AutoReleaseInterval + { + get => _autoReleaseInterval; + set => _autoReleaseInterval = value; + } + + /// + /// 获取或设置对象池的容量。 + /// + public override int Capacity + { + get => _capacity; + set + { + if (value < 0) + { + throw new GameFrameworkException("Capacity is invalid."); + } + + if (_capacity == value) + { + return; + } + + _capacity = value; + Release(); + } + } + + /// + /// 获取或设置对象池对象过期秒数。 + /// + public override float ExpireTime + { + get => _expireTime; + + set + { + if (value < 0f) + { + throw new GameFrameworkException("ExpireTime is invalid."); + } + + if (Math.Abs(ExpireTime - value) < 0.01f) + { + return; + } + + _expireTime = value; + Release(); + } + } + + /// + /// 获取或设置对象池的优先级。 + /// + public override int Priority + { + get => _priority; + set => _priority = value; + } + + /// + /// 创建对象。 + /// + /// 对象。 + /// 对象是否已被获取。 + public void Register(T obj, bool spawned) + { + if (obj == null) + { + throw new GameFrameworkException("Object is invalid."); + } + + Object internalObject = Object.Create(obj, spawned); + _objects.Add(obj.Name, internalObject); + _objectMap.Add(obj.Target, internalObject); + + if (Count > _capacity) + { + Release(); + } + } + + /// + /// 检查对象。 + /// + /// 要检查的对象是否存在。 + public bool CanSpawn() + { + return CanSpawn(string.Empty); + } + + /// + /// 检查对象。 + /// + /// 对象名称。 + /// 要检查的对象是否存在。 + public bool CanSpawn(string name) + { + if (name == null) + { + throw new GameFrameworkException("Name is invalid."); + } + + GameFrameworkLinkedListRange> objectRange = default(GameFrameworkLinkedListRange>); + if (_objects.TryGetValue(name, out objectRange)) + { + foreach (Object internalObject in objectRange) + { + if (_allowMultiSpawn || !internalObject.IsInUse) + { + return true; + } + } + } + + return false; + } + + /// + /// 获取对象。 + /// + /// 要获取的对象。 + public T Spawn() + { + return Spawn(string.Empty); + } + + /// + /// 获取对象。 + /// + /// 对象名称。 + /// 要获取的对象。 + public T Spawn(string name) + { + if (name == null) + { + throw new GameFrameworkException("Name is invalid."); + } + + GameFrameworkLinkedListRange> objectRange = default(GameFrameworkLinkedListRange>); + if (_objects.TryGetValue(name, out objectRange)) + { + foreach (Object internalObject in objectRange) + { + if (_allowMultiSpawn || !internalObject.IsInUse) + { + return internalObject.Spawn(); + } + } + } + + return null; + } + + /// + /// 回收对象。 + /// + /// 要回收的对象。 + public void Unspawn(T obj) + { + if (obj == null) + { + throw new GameFrameworkException("Object is invalid."); + } + + Unspawn(obj.Target); + } + + /// + /// 回收对象。 + /// + /// 要回收的对象。 + public void Unspawn(object target) + { + if (target == null) + { + throw new GameFrameworkException("Target is invalid."); + } + + Object internalObject = GetObject(target); + if (internalObject != null) + { + internalObject.Unspawn(); + if (Count > _capacity && internalObject.SpawnCount <= 0) + { + Release(); + } + } + else + { + throw new GameFrameworkException(Utility.Text.Format( + "Can not find target in object pool '{0}', target type is '{1}', target value is '{2}'.", new TypeNamePair(typeof(T), Name), + target.GetType().FullName, target)); + } + } + + /// + /// 设置对象是否被加锁。 + /// + /// 要设置被加锁的对象。 + /// 是否被加锁。 + public void SetLocked(T obj, bool locked) + { + if (obj == null) + { + throw new GameFrameworkException("Object is invalid."); + } + + SetLocked(obj.Target, locked); + } + + /// + /// 设置对象是否被加锁。 + /// + /// 要设置被加锁的对象。 + /// 是否被加锁。 + public void SetLocked(object target, bool locked) + { + if (target == null) + { + throw new GameFrameworkException("Target is invalid."); + } + + Object internalObject = GetObject(target); + if (internalObject != null) + { + internalObject.Locked = locked; + } + else + { + throw new GameFrameworkException(Utility.Text.Format( + "Can not find target in object pool '{0}', target type is '{1}', target value is '{2}'.", new TypeNamePair(typeof(T), Name), + target.GetType().FullName, target)); + } + } + + /// + /// 设置对象的优先级。 + /// + /// 要设置优先级的对象。 + /// 优先级。 + public void SetPriority(T obj, int priority) + { + if (obj == null) + { + throw new GameFrameworkException("Object is invalid."); + } + + SetPriority(obj.Target, priority); + } + + /// + /// 设置对象的优先级。 + /// + /// 要设置优先级的对象。 + /// 优先级。 + public void SetPriority(object target, int priority) + { + if (target == null) + { + throw new GameFrameworkException("Target is invalid."); + } + + Object internalObject = GetObject(target); + if (internalObject != null) + { + internalObject.Priority = priority; + } + else + { + throw new GameFrameworkException(Utility.Text.Format( + "Can not find target in object pool '{0}', target type is '{1}', target value is '{2}'.", new TypeNamePair(typeof(T), Name), + target.GetType().FullName, target)); + } + } + + /// + /// 释放对象。 + /// + /// 要释放的对象。 + /// 释放对象是否成功。 + public bool ReleaseObject(T obj) + { + if (obj == null) + { + throw new GameFrameworkException("Object is invalid."); + } + + return ReleaseObject(obj.Target); + } + + /// + /// 释放对象。 + /// + /// 要释放的对象。 + /// 释放对象是否成功。 + public bool ReleaseObject(object target) + { + if (target == null) + { + throw new GameFrameworkException("Target is invalid."); + } + + Object internalObject = GetObject(target); + if (internalObject == null) + { + return false; + } + + if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) + { + return false; + } + + _objects.Remove(internalObject.Name, internalObject); + _objectMap.Remove(internalObject.Peek().Target); + + internalObject.Release(false); + MemoryPool.Release(internalObject); + return true; + } + + /// + /// 释放对象池中的可释放对象。 + /// + public override void Release() + { + Release(Count - _capacity, _defaultReleaseObjectFilterCallback); + } + + /// + /// 释放对象池中的可释放对象。 + /// + /// 尝试释放对象数量。 + public override void Release(int toReleaseCount) + { + Release(toReleaseCount, _defaultReleaseObjectFilterCallback); + } + + /// + /// 释放对象池中的可释放对象。 + /// + /// 释放对象筛选函数。 + public void Release(ReleaseObjectFilterCallback releaseObjectFilterCallback) + { + Release(Count - _capacity, releaseObjectFilterCallback); + } + + /// + /// 释放对象池中的可释放对象。 + /// + /// 尝试释放对象数量。 + /// 释放对象筛选函数。 + public void Release(int toReleaseCount, ReleaseObjectFilterCallback releaseObjectFilterCallback) + { + if (releaseObjectFilterCallback == null) + { + throw new GameFrameworkException("Release object filter callback is invalid."); + } + + if (toReleaseCount < 0) + { + toReleaseCount = 0; + } + + DateTime expireTime = DateTime.MinValue; + if (_expireTime < float.MaxValue) + { + expireTime = DateTime.UtcNow.AddSeconds(-_expireTime); + } + + _autoReleaseTime = 0f; + GetCanReleaseObjects(_cachedCanReleaseObjects); + List toReleaseObjects = releaseObjectFilterCallback(_cachedCanReleaseObjects, toReleaseCount, expireTime); + if (toReleaseObjects == null || toReleaseObjects.Count <= 0) + { + return; + } + + foreach (T toReleaseObject in toReleaseObjects) + { + ReleaseObject(toReleaseObject); + } + } + + /// + /// 释放对象池中的所有未使用对象。 + /// + public override void ReleaseAllUnused() + { + _autoReleaseTime = 0f; + GetCanReleaseObjects(_cachedCanReleaseObjects); + foreach (T toReleaseObject in _cachedCanReleaseObjects) + { + ReleaseObject(toReleaseObject); + } + } + + /// + /// 获取所有对象信息。 + /// + /// 所有对象信息。 + public override ObjectInfo[] GetAllObjectInfos() + { + List results = new List(); + foreach (KeyValuePair>> objectRanges in _objects) + { + foreach (Object internalObject in objectRanges.Value) + { + results.Add(new ObjectInfo(internalObject.Name, internalObject.Locked, internalObject.CustomCanReleaseFlag, internalObject.Priority, + internalObject.LastUseTime, internalObject.SpawnCount)); + } + } + + return results.ToArray(); + } + + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + _autoReleaseTime += realElapseSeconds; + if (_autoReleaseTime < _autoReleaseInterval) + { + return; + } + + Release(); + } + + internal override void Shutdown() + { + foreach (KeyValuePair> objectInMap in _objectMap) + { + objectInMap.Value.Release(true); + MemoryPool.Release(objectInMap.Value); + } + + _objects.Clear(); + _objectMap.Clear(); + _cachedCanReleaseObjects.Clear(); + _cachedToReleaseObjects.Clear(); + } + + private Object GetObject(object target) + { + if (target == null) + { + throw new GameFrameworkException("Target is invalid."); + } + + Object internalObject = null; + if (_objectMap.TryGetValue(target, out internalObject)) + { + return internalObject; + } + + return null; + } + + private void GetCanReleaseObjects(List results) + { + if (results == null) + { + throw new GameFrameworkException("Results is invalid."); + } + + results.Clear(); + foreach (KeyValuePair> objectInMap in _objectMap) + { + Object internalObject = objectInMap.Value; + if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag) + { + continue; + } + + results.Add(internalObject.Peek()); + } + } + + private List DefaultReleaseObjectFilterCallback(List candidateObjects, int toReleaseCount, DateTime expireTime) + { + _cachedToReleaseObjects.Clear(); + + if (expireTime > DateTime.MinValue) + { + for (int i = candidateObjects.Count - 1; i >= 0; i--) + { + if (candidateObjects[i].LastUseTime <= expireTime) + { + _cachedToReleaseObjects.Add(candidateObjects[i]); + candidateObjects.RemoveAt(i); + continue; + } + } + + toReleaseCount -= _cachedToReleaseObjects.Count; + } + + for (int i = 0; toReleaseCount > 0 && i < candidateObjects.Count; i++) + { + for (int j = i + 1; j < candidateObjects.Count; j++) + { + if (candidateObjects[i].Priority > candidateObjects[j].Priority + || candidateObjects[i].Priority == candidateObjects[j].Priority && + candidateObjects[i].LastUseTime > candidateObjects[j].LastUseTime) + { + T temp = candidateObjects[i]; + candidateObjects[i] = candidateObjects[j]; + candidateObjects[j] = temp; + } + } + + _cachedToReleaseObjects.Add(candidateObjects[i]); + toReleaseCount--; + } + + return _cachedToReleaseObjects; + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.ObjectPool.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.ObjectPool.cs.meta new file mode 100644 index 00000000..8c788216 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.ObjectPool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 68ff3108f40a407b819e52b8fc2e65e0 +timeCreated: 1680501171 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.cs new file mode 100644 index 00000000..c045fc4e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.cs @@ -0,0 +1,1290 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 对象池管理器。 + /// + [UpdateModule] + internal sealed partial class ObjectPoolManager : ModuleImp, IObjectPoolManager + { + private const int DefaultCapacity = int.MaxValue; + private const float DefaultExpireTime = float.MaxValue; + private const int DefaultPriority = 0; + + private readonly Dictionary _objectPools; + private readonly List _cachedAllObjectPools; + private readonly Comparison _objectPoolComparer; + + /// + /// 初始化对象池管理器的新实例。 + /// + public ObjectPoolManager() + { + _objectPools = new Dictionary(); + _cachedAllObjectPools = new List(); + _objectPoolComparer = ObjectPoolComparer; + } + + /// + /// 获取游戏框架模块优先级。 + /// + /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 + internal override int Priority => 6; + + /// + /// 获取对象池数量。 + /// + public int Count => _objectPools.Count; + + /// + /// 对象池管理器轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + foreach (KeyValuePair objectPool in _objectPools) + { + objectPool.Value.Update(elapseSeconds, realElapseSeconds); + } + } + + /// + /// 关闭并清理对象池管理器。 + /// + internal override void Shutdown() + { + foreach (KeyValuePair objectPool in _objectPools) + { + objectPool.Value.Shutdown(); + } + + _objectPools.Clear(); + _cachedAllObjectPools.Clear(); + } + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 是否存在对象池。 + public bool HasObjectPool() where T : ObjectBase + { + return InternalHasObjectPool(new TypeNamePair(typeof(T))); + } + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 是否存在对象池。 + public bool HasObjectPool(Type objectType) + { + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + if (!typeof(ObjectBase).IsAssignableFrom(objectType)) + { + throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); + } + + return InternalHasObjectPool(new TypeNamePair(objectType)); + } + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 是否存在对象池。 + public bool HasObjectPool(string name) where T : ObjectBase + { + return InternalHasObjectPool(new TypeNamePair(typeof(T), name)); + } + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 是否存在对象池。 + public bool HasObjectPool(Type objectType, string name) + { + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + if (!typeof(ObjectBase).IsAssignableFrom(objectType)) + { + throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); + } + + return InternalHasObjectPool(new TypeNamePair(objectType, name)); + } + + /// + /// 检查是否存在对象池。 + /// + /// 要检查的条件。 + /// 是否存在对象池。 + public bool HasObjectPool(Predicate condition) + { + if (condition == null) + { + throw new GameFrameworkException("Condition is invalid."); + } + + foreach (KeyValuePair objectPool in _objectPools) + { + if (condition(objectPool.Value)) + { + return true; + } + } + + return false; + } + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 要获取的对象池。 + public IObjectPool GetObjectPool() where T : ObjectBase + { + return (IObjectPool)InternalGetObjectPool(new TypeNamePair(typeof(T))); + } + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 要获取的对象池。 + public ObjectPoolBase GetObjectPool(Type objectType) + { + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + if (!typeof(ObjectBase).IsAssignableFrom(objectType)) + { + throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); + } + + return InternalGetObjectPool(new TypeNamePair(objectType)); + } + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要获取的对象池。 + public IObjectPool GetObjectPool(string name) where T : ObjectBase + { + return (IObjectPool)InternalGetObjectPool(new TypeNamePair(typeof(T), name)); + } + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要获取的对象池。 + public ObjectPoolBase GetObjectPool(Type objectType, string name) + { + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + if (!typeof(ObjectBase).IsAssignableFrom(objectType)) + { + throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); + } + + return InternalGetObjectPool(new TypeNamePair(objectType, name)); + } + + /// + /// 获取对象池。 + /// + /// 要检查的条件。 + /// 要获取的对象池。 + public ObjectPoolBase GetObjectPool(Predicate condition) + { + if (condition == null) + { + throw new GameFrameworkException("Condition is invalid."); + } + + foreach (KeyValuePair objectPool in _objectPools) + { + if (condition(objectPool.Value)) + { + return objectPool.Value; + } + } + + return null; + } + + /// + /// 获取对象池。 + /// + /// 要检查的条件。 + /// 要获取的对象池。 + public ObjectPoolBase[] GetObjectPools(Predicate condition) + { + if (condition == null) + { + throw new GameFrameworkException("Condition is invalid."); + } + + List results = new List(); + foreach (KeyValuePair objectPool in _objectPools) + { + if (condition(objectPool.Value)) + { + results.Add(objectPool.Value); + } + } + + return results.ToArray(); + } + + /// + /// 获取对象池。 + /// + /// 要检查的条件。 + /// 要获取的对象池。 + public void GetObjectPools(Predicate condition, List results) + { + if (condition == null) + { + throw new GameFrameworkException("Condition is invalid."); + } + + if (results == null) + { + throw new GameFrameworkException("Results is invalid."); + } + + results.Clear(); + foreach (KeyValuePair objectPool in _objectPools) + { + if (condition(objectPool.Value)) + { + results.Add(objectPool.Value); + } + } + } + + /// + /// 获取所有对象池。 + /// + /// 所有对象池。 + public ObjectPoolBase[] GetAllObjectPools() + { + return GetAllObjectPools(false); + } + + /// + /// 获取所有对象池。 + /// + /// 所有对象池。 + public void GetAllObjectPools(List results) + { + GetAllObjectPools(false, results); + } + + /// + /// 获取所有对象池。 + /// + /// 是否根据对象池的优先级排序。 + /// 所有对象池。 + public ObjectPoolBase[] GetAllObjectPools(bool sort) + { + if (sort) + { + List results = new List(); + foreach (KeyValuePair objectPool in _objectPools) + { + results.Add(objectPool.Value); + } + + results.Sort(_objectPoolComparer); + return results.ToArray(); + } + else + { + int index = 0; + ObjectPoolBase[] results = new ObjectPoolBase[_objectPools.Count]; + foreach (KeyValuePair objectPool in _objectPools) + { + results[index++] = objectPool.Value; + } + + return results; + } + } + + /// + /// 获取所有对象池。 + /// + /// 是否根据对象池的优先级排序。 + /// 所有对象池。 + public void GetAllObjectPools(bool sort, List results) + { + if (results == null) + { + throw new GameFrameworkException("Results is invalid."); + } + + results.Clear(); + foreach (KeyValuePair objectPool in _objectPools) + { + results.Add(objectPool.Value); + } + + if (sort) + { + results.Sort(_objectPoolComparer); + } + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool() where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType) + { + return InternalCreateObjectPool(objectType, string.Empty, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name) where T : ObjectBase + { + return InternalCreateObjectPool(name, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name) + { + return InternalCreateObjectPool(objectType, name, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(int capacity) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity) + { + return InternalCreateObjectPool(objectType, string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(float expireTime) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime) + { + return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity) where T : ObjectBase + { + return InternalCreateObjectPool(name, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity) + { + return InternalCreateObjectPool(objectType, name, false, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime) where T : ObjectBase + { + return InternalCreateObjectPool(name, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime) + { + return InternalCreateObjectPool(objectType, name, false, expireTime, DefaultCapacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, false, expireTime, capacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime) + { + return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, capacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(int capacity, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, int priority) + { + return InternalCreateObjectPool(objectType, string.Empty, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(float expireTime, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, false, expireTime, DefaultCapacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, DefaultCapacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase + { + return InternalCreateObjectPool(name, false, expireTime, capacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime) + { + return InternalCreateObjectPool(objectType, name, false, expireTime, capacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(name, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, int priority) + { + return InternalCreateObjectPool(objectType, name, false, DefaultExpireTime, capacity, DefaultExpireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(name, false, expireTime, DefaultCapacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, name, false, expireTime, DefaultCapacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, false, expireTime, capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, string.Empty, false, expireTime, capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(name, false, expireTime, capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, name, false, expireTime, capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) + where T : ObjectBase + { + return InternalCreateObjectPool(name, false, autoReleaseInterval, capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, name, false, autoReleaseInterval, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool() where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType) + { + return InternalCreateObjectPool(objectType, string.Empty, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name) where T : ObjectBase + { + return InternalCreateObjectPool(name, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name) + { + return InternalCreateObjectPool(objectType, name, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(int capacity) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity) + { + return InternalCreateObjectPool(objectType, string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(float expireTime) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime) + { + return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity) where T : ObjectBase + { + return InternalCreateObjectPool(name, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity) + { + return InternalCreateObjectPool(objectType, name, true, DefaultExpireTime, capacity, DefaultExpireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime) where T : ObjectBase + { + return InternalCreateObjectPool(name, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime) + { + return InternalCreateObjectPool(objectType, name, true, expireTime, DefaultCapacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, true, expireTime, capacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime) + { + return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, capacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(int capacity, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, int priority) + { + return InternalCreateObjectPool(objectType, string.Empty, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(float expireTime, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, true, expireTime, DefaultCapacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, DefaultCapacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase + { + return InternalCreateObjectPool(name, true, expireTime, capacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime) + { + return InternalCreateObjectPool(objectType, name, true, expireTime, capacity, expireTime, DefaultPriority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(name, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, int priority) + { + return InternalCreateObjectPool(objectType, name, true, DefaultExpireTime, capacity, DefaultExpireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(name, true, expireTime, DefaultCapacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, name, true, expireTime, DefaultCapacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(string.Empty, true, expireTime, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, string.Empty, true, expireTime, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase + { + return InternalCreateObjectPool(name, true, expireTime, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, name, true, expireTime, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) + where T : ObjectBase + { + return InternalCreateObjectPool(name, true, autoReleaseInterval, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority) + { + return InternalCreateObjectPool(objectType, name, true, autoReleaseInterval, capacity, expireTime, priority); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool() where T : ObjectBase + { + return InternalDestroyObjectPool(new TypeNamePair(typeof(T))); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(Type objectType) + { + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + if (!typeof(ObjectBase).IsAssignableFrom(objectType)) + { + throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); + } + + return InternalDestroyObjectPool(new TypeNamePair(objectType)); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 要销毁的对象池名称。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(string name) where T : ObjectBase + { + return InternalDestroyObjectPool(new TypeNamePair(typeof(T), name)); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 要销毁的对象池名称。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(Type objectType, string name) + { + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + if (!typeof(ObjectBase).IsAssignableFrom(objectType)) + { + throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); + } + + return InternalDestroyObjectPool(new TypeNamePair(objectType, name)); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 要销毁的对象池。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(IObjectPool objectPool) where T : ObjectBase + { + if (objectPool == null) + { + throw new GameFrameworkException("Object pool is invalid."); + } + + return InternalDestroyObjectPool(new TypeNamePair(typeof(T), objectPool.Name)); + } + + /// + /// 销毁对象池。 + /// + /// 要销毁的对象池。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(ObjectPoolBase objectPool) + { + if (objectPool == null) + { + throw new GameFrameworkException("Object pool is invalid."); + } + + return InternalDestroyObjectPool(new TypeNamePair(objectPool.ObjectType, objectPool.Name)); + } + + /// + /// 释放对象池中的可释放对象。 + /// + public void Release() + { + GetAllObjectPools(true, _cachedAllObjectPools); + foreach (ObjectPoolBase objectPool in _cachedAllObjectPools) + { + objectPool.Release(); + } + } + + /// + /// 释放对象池中的所有未使用对象。 + /// + public void ReleaseAllUnused() + { + GetAllObjectPools(true, _cachedAllObjectPools); + foreach (ObjectPoolBase objectPool in _cachedAllObjectPools) + { + objectPool.ReleaseAllUnused(); + } + } + + private bool InternalHasObjectPool(TypeNamePair typeNamePair) + { + return _objectPools.ContainsKey(typeNamePair); + } + + private ObjectPoolBase InternalGetObjectPool(TypeNamePair typeNamePair) + { + ObjectPoolBase objectPool = null; + if (_objectPools.TryGetValue(typeNamePair, out objectPool)) + { + return objectPool; + } + + return null; + } + + private IObjectPool InternalCreateObjectPool(string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, float expireTime, + int priority) where T : ObjectBase + { + TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name); + if (HasObjectPool(name)) + { + throw new GameFrameworkException(Utility.Text.Format("Already exist object pool '{0}'.", typeNamePair)); + } + + ObjectPool objectPool = new ObjectPool(name, allowMultiSpawn, autoReleaseInterval, capacity, expireTime, priority); + _objectPools.Add(typeNamePair, objectPool); + return objectPool; + } + + private ObjectPoolBase InternalCreateObjectPool(Type objectType, string name, bool allowMultiSpawn, float autoReleaseInterval, int capacity, + float expireTime, int priority) + { + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + if (!typeof(ObjectBase).IsAssignableFrom(objectType)) + { + throw new GameFrameworkException(Utility.Text.Format("Object type '{0}' is invalid.", objectType.FullName)); + } + + TypeNamePair typeNamePair = new TypeNamePair(objectType, name); + if (HasObjectPool(objectType, name)) + { + throw new GameFrameworkException(Utility.Text.Format("Already exist object pool '{0}'.", typeNamePair)); + } + + Type objectPoolType = typeof(ObjectPool<>).MakeGenericType(objectType); + ObjectPoolBase objectPool = + (ObjectPoolBase)Activator.CreateInstance(objectPoolType, name, allowMultiSpawn, autoReleaseInterval, capacity, expireTime, priority); + _objectPools.Add(typeNamePair, objectPool); + return objectPool; + } + + private bool InternalDestroyObjectPool(TypeNamePair typeNamePair) + { + ObjectPoolBase objectPool = null; + if (_objectPools.TryGetValue(typeNamePair, out objectPool)) + { + objectPool.Shutdown(); + return _objectPools.Remove(typeNamePair); + } + + return false; + } + + private static int ObjectPoolComparer(ObjectPoolBase a, ObjectPoolBase b) + { + return a.Priority.CompareTo(b.Priority); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.cs.meta new file mode 100644 index 00000000..799be2b1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 446300b409bc49d0a006e35e20957799 +timeCreated: 1680501171 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolModule.cs new file mode 100644 index 00000000..0792665f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolModule.cs @@ -0,0 +1,1015 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine +{ + /// + /// 对象池模块。 + /// + [DisallowMultipleComponent] + public sealed class ObjectPoolModule : Module + { + private IObjectPoolManager _objectPoolManager = null; + + /// + /// 获取对象池数量。 + /// + public int Count => _objectPoolManager.Count; + + /// + /// 游戏框架模块初始化。 + /// + protected override void Awake() + { + base.Awake(); + + _objectPoolManager = ModuleImpSystem.GetModule(); + if (_objectPoolManager == null) + { + Log.Fatal("Object pool manager is invalid."); + return; + } + } + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 是否存在对象池。 + public bool HasObjectPool() where T : ObjectBase + { + return _objectPoolManager.HasObjectPool(); + } + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 是否存在对象池。 + public bool HasObjectPool(Type objectType) + { + return _objectPoolManager.HasObjectPool(objectType); + } + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 是否存在对象池。 + public bool HasObjectPool(string name) where T : ObjectBase + { + return _objectPoolManager.HasObjectPool(name); + } + + /// + /// 检查是否存在对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 是否存在对象池。 + public bool HasObjectPool(Type objectType, string name) + { + return _objectPoolManager.HasObjectPool(objectType, name); + } + + /// + /// 检查是否存在对象池。 + /// + /// 要检查的条件。 + /// 是否存在对象池。 + public bool HasObjectPool(Predicate condition) + { + return _objectPoolManager.HasObjectPool(condition); + } + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 要获取的对象池。 + public IObjectPool GetObjectPool() where T : ObjectBase + { + return _objectPoolManager.GetObjectPool(); + } + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 要获取的对象池。 + public ObjectPoolBase GetObjectPool(Type objectType) + { + return _objectPoolManager.GetObjectPool(objectType); + } + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要获取的对象池。 + public IObjectPool GetObjectPool(string name) where T : ObjectBase + { + return _objectPoolManager.GetObjectPool(name); + } + + /// + /// 获取对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要获取的对象池。 + public ObjectPoolBase GetObjectPool(Type objectType, string name) + { + return _objectPoolManager.GetObjectPool(objectType, name); + } + + /// + /// 获取对象池。 + /// + /// 要检查的条件。 + /// 要获取的对象池。 + public ObjectPoolBase GetObjectPool(Predicate condition) + { + return _objectPoolManager.GetObjectPool(condition); + } + + /// + /// 获取对象池。 + /// + /// 要检查的条件。 + /// 要获取的对象池。 + public ObjectPoolBase[] GetObjectPools(Predicate condition) + { + return _objectPoolManager.GetObjectPools(condition); + } + + /// + /// 获取对象池。 + /// + /// 要检查的条件。 + /// 要获取的对象池。 + public void GetObjectPools(Predicate condition, List results) + { + _objectPoolManager.GetObjectPools(condition, results); + } + + /// + /// 获取所有对象池。 + /// + public ObjectPoolBase[] GetAllObjectPools() + { + return _objectPoolManager.GetAllObjectPools(); + } + + /// + /// 获取所有对象池。 + /// + /// 所有对象池。 + public void GetAllObjectPools(List results) + { + _objectPoolManager.GetAllObjectPools(results); + } + + /// + /// 获取所有对象池。 + /// + /// 是否根据对象池的优先级排序。 + /// 所有对象池。 + public ObjectPoolBase[] GetAllObjectPools(bool sort) + { + return _objectPoolManager.GetAllObjectPools(sort); + } + + /// + /// 获取所有对象池。 + /// + /// 是否根据对象池的优先级排序。 + /// 所有对象池。 + public void GetAllObjectPools(bool sort, List results) + { + _objectPoolManager.GetAllObjectPools(sort, results); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool() where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(name); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, name); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(int capacity) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(capacity); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, capacity); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(float expireTime) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(expireTime); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, expireTime); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(name, capacity); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, name, capacity); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(name, expireTime); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, name, expireTime); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(capacity, expireTime); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, capacity, expireTime); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(int capacity, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(capacity, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, int priority) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, capacity, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(float expireTime, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, float expireTime, int priority) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(name, capacity, expireTime); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, name, capacity, expireTime); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(name, capacity, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, int priority) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, name, capacity, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(name, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float expireTime, int priority) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, name, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(name, capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, name, capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public IObjectPool CreateSingleSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) + where T : ObjectBase + { + return _objectPoolManager.CreateSingleSpawnObjectPool(name, autoReleaseInterval, capacity, expireTime, priority); + } + + /// + /// 创建允许单次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许单次获取的对象池。 + public ObjectPoolBase CreateSingleSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority) + { + return _objectPoolManager.CreateSingleSpawnObjectPool(objectType, name, autoReleaseInterval, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool() where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(name); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, name); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(int capacity) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(capacity); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, capacity); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(float expireTime) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(expireTime); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, expireTime); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(name, capacity); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, name, capacity); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(name, expireTime); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, name, expireTime); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(capacity, expireTime); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, capacity, expireTime); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(int capacity, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(capacity, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, int priority) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, capacity, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(float expireTime, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, float expireTime, int priority) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(name, capacity, expireTime); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, name, capacity, expireTime); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(name, capacity, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, int priority) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, name, capacity, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, float expireTime, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(name, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float expireTime, int priority) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, name, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(int capacity, float expireTime, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, int capacity, float expireTime, int priority) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, int capacity, float expireTime, int priority) where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(name, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, int capacity, float expireTime, int priority) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, name, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public IObjectPool CreateMultiSpawnObjectPool(string name, float autoReleaseInterval, int capacity, float expireTime, int priority) + where T : ObjectBase + { + return _objectPoolManager.CreateMultiSpawnObjectPool(name, autoReleaseInterval, capacity, expireTime, priority); + } + + /// + /// 创建允许多次获取的对象池。 + /// + /// 对象类型。 + /// 对象池名称。 + /// 对象池自动释放可释放对象的间隔秒数。 + /// 对象池的容量。 + /// 对象池对象过期秒数。 + /// 对象池的优先级。 + /// 要创建的允许多次获取的对象池。 + public ObjectPoolBase CreateMultiSpawnObjectPool(Type objectType, string name, float autoReleaseInterval, int capacity, float expireTime, int priority) + { + return _objectPoolManager.CreateMultiSpawnObjectPool(objectType, name, autoReleaseInterval, capacity, expireTime, priority); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool() where T : ObjectBase + { + return _objectPoolManager.DestroyObjectPool(); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(Type objectType) + { + return _objectPoolManager.DestroyObjectPool(objectType); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 要销毁的对象池名称。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(string name) where T : ObjectBase + { + return _objectPoolManager.DestroyObjectPool(name); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 要销毁的对象池名称。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(Type objectType, string name) + { + return _objectPoolManager.DestroyObjectPool(objectType, name); + } + + /// + /// 销毁对象池。 + /// + /// 对象类型。 + /// 要销毁的对象池。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(IObjectPool objectPool) where T : ObjectBase + { + return _objectPoolManager.DestroyObjectPool(objectPool); + } + + /// + /// 销毁对象池。 + /// + /// 要销毁的对象池。 + /// 是否销毁对象池成功。 + public bool DestroyObjectPool(ObjectPoolBase objectPool) + { + return _objectPoolManager.DestroyObjectPool(objectPool); + } + + /// + /// 释放对象池中的可释放对象。 + /// + public void Release() + { + Log.Info("Object pool release..."); + _objectPoolManager.Release(); + } + + /// + /// 释放对象池中的所有未使用对象。 + /// + public void ReleaseAllUnused() + { + Log.Info("Object pool release all unused..."); + _objectPoolManager.ReleaseAllUnused(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolModule.cs.meta new file mode 100644 index 00000000..69fba120 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ObjectPoolModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: da10a6ed68a3439b8a2df5384febd504 +timeCreated: 1680501224 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ReleaseObjectFilterCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ReleaseObjectFilterCallback.cs new file mode 100644 index 00000000..beffd27e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ReleaseObjectFilterCallback.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 释放对象筛选函数。 + /// + /// 对象类型。 + /// 要筛选的对象集合。 + /// 需要释放的对象数量。 + /// 对象过期参考时间。 + /// 经筛选需要释放的对象集合。 + public delegate List ReleaseObjectFilterCallback(List candidateObjects, int toReleaseCount, DateTime expireTime) where T : ObjectBase; +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ReleaseObjectFilterCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ReleaseObjectFilterCallback.cs.meta new file mode 100644 index 00000000..6c04aded --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ObjectPoolModule/ReleaseObjectFilterCallback.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bad5108ff5ac489096a35b039c31eaf3 +timeCreated: 1680501171 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule.meta new file mode 100644 index 00000000..52d5495c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 673837edfb10bce449aeb339555cd178 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/IProcedureManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/IProcedureManager.cs new file mode 100644 index 00000000..1b7d5309 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/IProcedureManager.cs @@ -0,0 +1,73 @@ +using System; + +namespace TEngine +{ + /// + /// 流程管理器接口。 + /// + public interface IProcedureManager + { + /// + /// 获取当前流程。 + /// + ProcedureBase CurrentProcedure + { + get; + } + + /// + /// 获取当前流程持续时间。 + /// + float CurrentProcedureTime + { + get; + } + + /// + /// 初始化流程管理器。 + /// + /// 有限状态机管理器。 + /// 流程管理器包含的流程。 + void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures); + + /// + /// 开始流程。 + /// + /// 要开始的流程类型。 + void StartProcedure() where T : ProcedureBase; + + /// + /// 开始流程。 + /// + /// 要开始的流程类型。 + void StartProcedure(Type procedureType); + + /// + /// 是否存在流程。 + /// + /// 要检查的流程类型。 + /// 是否存在流程。 + bool HasProcedure() where T : ProcedureBase; + + /// + /// 是否存在流程。 + /// + /// 要检查的流程类型。 + /// 是否存在流程。 + bool HasProcedure(Type procedureType); + + /// + /// 获取流程。 + /// + /// 要获取的流程类型。 + /// 要获取的流程。 + ProcedureBase GetProcedure() where T : ProcedureBase; + + /// + /// 获取流程。 + /// + /// 要获取的流程类型。 + /// 要获取的流程。 + ProcedureBase GetProcedure(Type procedureType); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/IProcedureManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/IProcedureManager.cs.meta new file mode 100644 index 00000000..ba9bac89 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/IProcedureManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5dd7530db77a4e9dac3f40e30aa05cb0 +timeCreated: 1680663217 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureBase.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureBase.cs new file mode 100644 index 00000000..12f4b952 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureBase.cs @@ -0,0 +1,58 @@ +using ProcedureOwner = TEngine.IFsm; + +namespace TEngine +{ + /// + /// 流程基类。 + /// + public abstract class ProcedureBase : FsmState + { + /// + /// 状态初始化时调用。 + /// + /// 流程持有者。 + protected internal override void OnInit(ProcedureOwner procedureOwner) + { + base.OnInit(procedureOwner); + } + + /// + /// 进入状态时调用。 + /// + /// 流程持有者。 + protected internal override void OnEnter(ProcedureOwner procedureOwner) + { + base.OnEnter(procedureOwner); + } + + /// + /// 状态轮询时调用。 + /// + /// 流程持有者。 + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + protected internal override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds) + { + base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); + } + + /// + /// 离开状态时调用。 + /// + /// 流程持有者。 + /// 是否是关闭状态机时触发。 + protected internal override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown) + { + base.OnLeave(procedureOwner, isShutdown); + } + + /// + /// 状态销毁时调用。 + /// + /// 流程持有者。 + protected internal override void OnDestroy(ProcedureOwner procedureOwner) + { + base.OnDestroy(procedureOwner); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureBase.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureBase.cs.meta new file mode 100644 index 00000000..74dfb832 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureBase.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: eb8b31eea6d2468f8a717e780d44844f +timeCreated: 1680663217 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureManager.cs new file mode 100644 index 00000000..458dddd3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureManager.cs @@ -0,0 +1,190 @@ +using System; + +namespace TEngine +{ + /// + /// 流程管理器。 + /// + internal sealed class ProcedureManager : ModuleImp, IProcedureManager + { + private IFsmManager _fsmManager; + private IFsm _procedureFsm; + + /// + /// 初始化流程管理器的新实例。 + /// + public ProcedureManager() + { + _fsmManager = null; + _procedureFsm = null; + } + + /// + /// 获取游戏框架模块优先级。 + /// + /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 + internal override int Priority => -2; + + /// + /// 获取当前流程。 + /// + public ProcedureBase CurrentProcedure + { + get + { + if (_procedureFsm == null) + { + throw new GameFrameworkException("You must initialize procedure first."); + } + + return (ProcedureBase)_procedureFsm.CurrentState; + } + } + + /// + /// 获取当前流程持续时间。 + /// + public float CurrentProcedureTime + { + get + { + if (_procedureFsm == null) + { + throw new GameFrameworkException("You must initialize procedure first."); + } + + return _procedureFsm.CurrentStateTime; + } + } + + /// + /// 流程管理器轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + } + + /// + /// 关闭并清理流程管理器。 + /// + internal override void Shutdown() + { + if (_fsmManager != null) + { + if (_procedureFsm != null) + { + _fsmManager.DestroyFsm(_procedureFsm); + _procedureFsm = null; + } + + _fsmManager = null; + } + } + + /// + /// 初始化流程管理器。 + /// + /// 有限状态机管理器。 + /// 流程管理器包含的流程。 + public void Initialize(IFsmManager fsmManager, params ProcedureBase[] procedures) + { + if (fsmManager == null) + { + throw new GameFrameworkException("FSM manager is invalid."); + } + + _fsmManager = fsmManager; + _procedureFsm = _fsmManager.CreateFsm(this, procedures); + } + + /// + /// 开始流程。 + /// + /// 要开始的流程类型。 + public void StartProcedure() where T : ProcedureBase + { + if (_procedureFsm == null) + { + throw new GameFrameworkException("You must initialize procedure first."); + } + + _procedureFsm.Start(); + } + + /// + /// 开始流程。 + /// + /// 要开始的流程类型。 + public void StartProcedure(Type procedureType) + { + if (_procedureFsm == null) + { + throw new GameFrameworkException("You must initialize procedure first."); + } + + _procedureFsm.Start(procedureType); + } + + /// + /// 是否存在流程。 + /// + /// 要检查的流程类型。 + /// 是否存在流程。 + public bool HasProcedure() where T : ProcedureBase + { + if (_procedureFsm == null) + { + throw new GameFrameworkException("You must initialize procedure first."); + } + + return _procedureFsm.HasState(); + } + + /// + /// 是否存在流程。 + /// + /// 要检查的流程类型。 + /// 是否存在流程。 + public bool HasProcedure(Type procedureType) + { + if (_procedureFsm == null) + { + throw new GameFrameworkException("You must initialize procedure first."); + } + + return _procedureFsm.HasState(procedureType); + } + + /// + /// 获取流程。 + /// + /// 要获取的流程类型。 + /// 要获取的流程。 + public ProcedureBase GetProcedure() where T : ProcedureBase + { + if (_procedureFsm == null) + { + throw new GameFrameworkException("You must initialize procedure first."); + } + + return _procedureFsm.GetState(); + } + + /// + /// 获取流程。 + /// + /// 要获取的流程类型。 + /// 要获取的流程。 + public ProcedureBase GetProcedure(Type procedureType) + { + if (_procedureFsm == null) + { + throw new GameFrameworkException("You must initialize procedure first."); + } + + return (ProcedureBase)_procedureFsm.GetState(procedureType); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureManager.cs.meta new file mode 100644 index 00000000..805e8d2c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: efb3019410a04559a5d3b39f9435d519 +timeCreated: 1680663217 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureModule.cs new file mode 100644 index 00000000..a1305aaa --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureModule.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections; +using UnityEngine; +using UnityEngine.Serialization; + +namespace TEngine +{ + /// + /// 流程管理模块。 + /// + [DisallowMultipleComponent] + public sealed class ProcedureModule : Module + { + private IProcedureManager _procedureManager = null; + private ProcedureBase _entranceProcedure = null; + + [SerializeField] private string[] availableProcedureTypeNames = null; + + [SerializeField] private string entranceProcedureTypeName = null; + + /// + /// 获取当前流程。 + /// + public ProcedureBase CurrentProcedure + { + get + { + if (_procedureManager == null) + { + return null; + } + + return _procedureManager.CurrentProcedure; + } + } + + /// + /// 获取当前流程持续时间。 + /// + public float CurrentProcedureTime + { + get + { + if (_procedureManager == null) + { + return 0f; + } + + return _procedureManager.CurrentProcedureTime; + } + } + + /// + /// 游戏框架模块初始化。 + /// + protected override void Awake() + { + base.Awake(); + + _procedureManager = ModuleImpSystem.GetModule(); + if (_procedureManager == null) + { + Log.Fatal("Procedure manager is invalid."); + } + } + + private IEnumerator Start() + { + ProcedureBase[] procedures = new ProcedureBase[availableProcedureTypeNames.Length]; + for (int i = 0; i < availableProcedureTypeNames.Length; i++) + { + Type procedureType = Utility.Assembly.GetType(availableProcedureTypeNames[i]); + if (procedureType == null) + { + Log.Error("Can not find procedure type '{0}'.", availableProcedureTypeNames[i]); + yield break; + } + + procedures[i] = (ProcedureBase)Activator.CreateInstance(procedureType); + if (procedures[i] == null) + { + Log.Error("Can not create procedure instance '{0}'.", availableProcedureTypeNames[i]); + yield break; + } + + if (entranceProcedureTypeName == availableProcedureTypeNames[i]) + { + _entranceProcedure = procedures[i]; + } + } + + if (_entranceProcedure == null) + { + Log.Error("Entrance procedure is invalid."); + yield break; + } + + _procedureManager.Initialize(ModuleImpSystem.GetModule(), procedures); + + yield return new WaitForEndOfFrame(); + + _procedureManager.StartProcedure(_entranceProcedure.GetType()); + } + + /// + /// 是否存在流程。 + /// + /// 要检查的流程类型。 + /// 是否存在流程。 + public bool HasProcedure() where T : ProcedureBase + { + return _procedureManager.HasProcedure(); + } + + /// + /// 是否存在流程。 + /// + /// 要检查的流程类型。 + /// 是否存在流程。 + public bool HasProcedure(Type procedureType) + { + return _procedureManager.HasProcedure(procedureType); + } + + /// + /// 获取流程。 + /// + /// 要获取的流程类型。 + /// 要获取的流程。 + public ProcedureBase GetProcedure() where T : ProcedureBase + { + return _procedureManager.GetProcedure(); + } + + /// + /// 获取流程。 + /// + /// 要获取的流程类型。 + /// 要获取的流程。 + public ProcedureBase GetProcedure(Type procedureType) + { + return _procedureManager.GetProcedure(procedureType); + } + + /// + /// 重启流程。 + /// 默认使用第一个流程作为启动流程。 + /// + /// 新的的流程。 + /// 是否重启成功。 + /// 重启异常。 + public bool RestartProcedure(params ProcedureBase[] procedures) + { + if (procedures == null || procedures.Length <= 0) + { + throw new GameFrameworkException("RestartProcedure Failed procedures is invalid."); + } + + IFsmManager fsmManager = ModuleImpSystem.GetModule(); + + if (!fsmManager.DestroyFsm()) + { + return false; + } + + _procedureManager = null; + _procedureManager = ModuleImpSystem.GetModule(); + _procedureManager.Initialize(fsmManager, procedures); + _procedureManager.StartProcedure(procedures[0].GetType()); + return true; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureModule.cs.meta new file mode 100644 index 00000000..d66a4619 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ProcedureModule/ProcedureModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1587cae710f84819b0056e98344f204d +timeCreated: 1680663317 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule.meta new file mode 100644 index 00000000..1a1c0ec2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7d12c5da87d43c449ce8443f1adef3c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/BuildinFileManifest.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/BuildinFileManifest.cs new file mode 100644 index 00000000..c8d0faee --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/BuildinFileManifest.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace GameFramework.Runtime +{ + /// + /// 内置资源清单 + /// + public class BuildinFileManifest : ScriptableObject + { + [Serializable] + public class Element + { + public string PackageName; + public string FileName; + public string FileCRC32; + } + + public List BuildinFiles = new List(); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/BuildinFileManifest.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/BuildinFileManifest.cs.meta new file mode 100644 index 00000000..8e115523 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/BuildinFileManifest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1e80c36cce1943d59b8e55f22dadecfa +timeCreated: 1706862932 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback.meta new file mode 100644 index 00000000..2c66e65d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 14d2634f18c5470688ea929ce4d780d6 +timeCreated: 1679316822 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetCallbacks.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetCallbacks.cs new file mode 100644 index 00000000..5f017978 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetCallbacks.cs @@ -0,0 +1,92 @@ +namespace TEngine +{ + /// + /// 加载资源回调函数集。 + /// + public sealed class LoadAssetCallbacks + { + private readonly LoadAssetSuccessCallback m_LoadAssetSuccessCallback; + private readonly LoadAssetFailureCallback m_LoadAssetFailureCallback; + private readonly LoadAssetUpdateCallback m_LoadAssetUpdateCallback; + + /// + /// 初始化加载资源回调函数集的新实例。 + /// + /// 加载资源成功回调函数。 + public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback) + : this(loadAssetSuccessCallback, null, null) + { + } + + /// + /// 初始化加载资源回调函数集的新实例。 + /// + /// 加载资源成功回调函数。 + /// 加载资源失败回调函数。 + public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback, LoadAssetFailureCallback loadAssetFailureCallback) + : this(loadAssetSuccessCallback, loadAssetFailureCallback, null) + { + } + + /// + /// 初始化加载资源回调函数集的新实例。 + /// + /// 加载资源成功回调函数。 + /// 加载资源更新回调函数。 + public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback, LoadAssetUpdateCallback loadAssetUpdateCallback) + : this(loadAssetSuccessCallback, null, loadAssetUpdateCallback) + { + } + + /// + /// 初始化加载资源回调函数集的新实例。 + /// + /// 加载资源成功回调函数。 + /// 加载资源失败回调函数。 + /// 加载资源更新回调函数。 + public LoadAssetCallbacks(LoadAssetSuccessCallback loadAssetSuccessCallback, LoadAssetFailureCallback loadAssetFailureCallback, LoadAssetUpdateCallback loadAssetUpdateCallback) + { + if (loadAssetSuccessCallback == null) + { + throw new GameFrameworkException("Load asset success callback is invalid."); + } + + m_LoadAssetSuccessCallback = loadAssetSuccessCallback; + m_LoadAssetFailureCallback = loadAssetFailureCallback; + m_LoadAssetUpdateCallback = loadAssetUpdateCallback; + } + + /// + /// 获取加载资源成功回调函数。 + /// + public LoadAssetSuccessCallback LoadAssetSuccessCallback + { + get + { + return m_LoadAssetSuccessCallback; + } + } + + /// + /// 获取加载资源失败回调函数。 + /// + public LoadAssetFailureCallback LoadAssetFailureCallback + { + get + { + return m_LoadAssetFailureCallback; + } + } + + /// + /// 获取加载资源更新回调函数。 + /// + public LoadAssetUpdateCallback LoadAssetUpdateCallback + { + get + { + return m_LoadAssetUpdateCallback; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetCallbacks.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetCallbacks.cs.meta new file mode 100644 index 00000000..4aa905e7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetCallbacks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26e66be1676a33748b8b1295656013b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetFailureCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetFailureCallback.cs new file mode 100644 index 00000000..3bf401d9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetFailureCallback.cs @@ -0,0 +1,11 @@ +namespace TEngine +{ + /// + /// 加载资源失败回调函数。 + /// + /// 要加载的资源名称。 + /// 加载资源状态。 + /// 错误信息。 + /// 用户自定义数据。 + public delegate void LoadAssetFailureCallback(string assetName, LoadResourceStatus status, string errorMessage, object userData); +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetFailureCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetFailureCallback.cs.meta new file mode 100644 index 00000000..c5b383dc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetFailureCallback.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 97294112416a4078b82c79fce4b39b4c +timeCreated: 1679305076 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetSuccessCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetSuccessCallback.cs new file mode 100644 index 00000000..cfc89c50 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetSuccessCallback.cs @@ -0,0 +1,11 @@ +namespace TEngine +{ + /// + /// 加载资源成功回调函数。 + /// + /// 要加载的资源名称。 + /// 已加载的资源。 + /// 加载持续时间。 + /// 用户自定义数据。 + public delegate void LoadAssetSuccessCallback(string assetName, object asset, float duration, object userData); +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetSuccessCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetSuccessCallback.cs.meta new file mode 100644 index 00000000..990ffe85 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetSuccessCallback.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 361143f2485d4d3bacd6511c9996b9f7 +timeCreated: 1679305063 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetUpdateCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetUpdateCallback.cs new file mode 100644 index 00000000..c7fa6697 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetUpdateCallback.cs @@ -0,0 +1,10 @@ +namespace TEngine +{ + /// + /// 加载资源更新回调函数。 + /// + /// 要加载的资源名称。 + /// 加载资源进度。 + /// 用户自定义数据。 + public delegate void LoadAssetUpdateCallback(string assetName, float progress, object userData); +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetUpdateCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetUpdateCallback.cs.meta new file mode 100644 index 00000000..c56046fc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadAssetUpdateCallback.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 52e1bb16c13b4b6ab5906c94d90691b2 +timeCreated: 1679305085 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadResourceStatus.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadResourceStatus.cs new file mode 100644 index 00000000..c661b701 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadResourceStatus.cs @@ -0,0 +1,38 @@ +namespace TEngine +{ + /// + /// 加载资源状态。 + /// + public enum LoadResourceStatus : byte + { + /// + /// 加载资源完成。 + /// + Success = 0, + + /// + /// 资源不存在。 + /// + NotExist, + + /// + /// 资源尚未准备完毕。 + /// + NotReady, + + /// + /// 依赖资源错误。 + /// + DependencyError, + + /// + /// 资源类型错误。 + /// + TypeError, + + /// + /// 加载资源错误。 + /// + AssetError + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadResourceStatus.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadResourceStatus.cs.meta new file mode 100644 index 00000000..5e3a96b3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadResourceStatus.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 253086b233644891aa78aad38d935438 +timeCreated: 1679305107 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneCallbacks.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneCallbacks.cs new file mode 100644 index 00000000..a0168bdb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneCallbacks.cs @@ -0,0 +1,92 @@ +namespace TEngine +{ + /// + /// 加载场景回调函数集。 + /// + public sealed class LoadSceneCallbacks + { + private readonly LoadSceneSuccessCallback m_LoadSceneSuccessCallback; + private readonly LoadSceneFailureCallback m_LoadSceneFailureCallback; + private readonly LoadSceneUpdateCallback m_LoadSceneUpdateCallback; + + /// + /// 初始化加载场景回调函数集的新实例。 + /// + /// 加载场景成功回调函数。 + public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback) + : this(loadSceneSuccessCallback, null, null) + { + } + + /// + /// 初始化加载场景回调函数集的新实例。 + /// + /// 加载场景成功回调函数。 + /// 加载场景失败回调函数。 + public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback, LoadSceneFailureCallback loadSceneFailureCallback) + : this(loadSceneSuccessCallback, loadSceneFailureCallback, null) + { + } + + /// + /// 初始化加载场景回调函数集的新实例。 + /// + /// 加载场景成功回调函数。 + /// 加载场景更新回调函数。 + public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback, LoadSceneUpdateCallback loadSceneUpdateCallback) + : this(loadSceneSuccessCallback, null, loadSceneUpdateCallback) + { + } + + /// + /// 初始化加载场景回调函数集的新实例。 + /// + /// 加载场景成功回调函数。 + /// 加载场景失败回调函数。 + /// 加载场景更新回调函数。 + public LoadSceneCallbacks(LoadSceneSuccessCallback loadSceneSuccessCallback, LoadSceneFailureCallback loadSceneFailureCallback, LoadSceneUpdateCallback loadSceneUpdateCallback) + { + if (loadSceneSuccessCallback == null) + { + throw new GameFrameworkException("Load scene success callback is invalid."); + } + + m_LoadSceneSuccessCallback = loadSceneSuccessCallback; + m_LoadSceneFailureCallback = loadSceneFailureCallback; + m_LoadSceneUpdateCallback = loadSceneUpdateCallback; + } + + /// + /// 获取加载场景成功回调函数。 + /// + public LoadSceneSuccessCallback LoadSceneSuccessCallback + { + get + { + return m_LoadSceneSuccessCallback; + } + } + + /// + /// 获取加载场景失败回调函数。 + /// + public LoadSceneFailureCallback LoadSceneFailureCallback + { + get + { + return m_LoadSceneFailureCallback; + } + } + + /// + /// 获取加载场景更新回调函数。 + /// + public LoadSceneUpdateCallback LoadSceneUpdateCallback + { + get + { + return m_LoadSceneUpdateCallback; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneCallbacks.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneCallbacks.cs.meta new file mode 100644 index 00000000..cca1bb57 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneCallbacks.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b3b7ca7cca2f46b78088053497ee643a +timeCreated: 1679316813 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneFailureCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneFailureCallback.cs new file mode 100644 index 00000000..a8016514 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneFailureCallback.cs @@ -0,0 +1,11 @@ +namespace TEngine +{ + /// + /// 加载场景失败回调函数。 + /// + /// 要加载的场景资源名称。 + /// 加载场景状态。 + /// 错误信息。 + /// 用户自定义数据。 + public delegate void LoadSceneFailureCallback(string sceneAssetName, LoadResourceStatus status, string errorMessage, object userData); +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneFailureCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneFailureCallback.cs.meta new file mode 100644 index 00000000..0fa1b853 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneFailureCallback.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: df4ff889191c4ac28cbed649cf06942d +timeCreated: 1679316813 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneSuccessCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneSuccessCallback.cs new file mode 100644 index 00000000..a68e305f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneSuccessCallback.cs @@ -0,0 +1,11 @@ +namespace TEngine +{ + /// + /// 加载场景成功回调函数。 + /// + /// 要加载的场景资源名称。 + /// 场景对象。 + /// 加载持续时间。 + /// 用户自定义数据。 + public delegate void LoadSceneSuccessCallback(string sceneAssetName,UnityEngine.SceneManagement.Scene scene, float duration, object userData); +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneSuccessCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneSuccessCallback.cs.meta new file mode 100644 index 00000000..8978b8c9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneSuccessCallback.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6371185a505d4ca180124b4998bc8c41 +timeCreated: 1679316813 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneUpdateCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneUpdateCallback.cs new file mode 100644 index 00000000..77ae184a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneUpdateCallback.cs @@ -0,0 +1,10 @@ +namespace TEngine +{ + /// + /// 加载场景更新回调函数。 + /// + /// 要加载的场景资源名称。 + /// 加载场景进度。 + /// 用户自定义数据。 + public delegate void LoadSceneUpdateCallback(string sceneAssetName, float progress, object userData); +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneUpdateCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneUpdateCallback.cs.meta new file mode 100644 index 00000000..c9dd7ff4 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/LoadSceneUpdateCallback.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 41a9345d683043db816feb9ff0749d22 +timeCreated: 1679316813 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneCallbacks.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneCallbacks.cs new file mode 100644 index 00000000..1f581e29 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneCallbacks.cs @@ -0,0 +1,58 @@ +namespace TEngine +{ + /// + /// 卸载场景回调函数集。 + /// + public sealed class UnloadSceneCallbacks + { + private readonly UnloadSceneSuccessCallback m_UnloadSceneSuccessCallback; + private readonly UnloadSceneFailureCallback m_UnloadSceneFailureCallback; + + /// + /// 初始化卸载场景回调函数集的新实例。 + /// + /// 卸载场景成功回调函数。 + public UnloadSceneCallbacks(UnloadSceneSuccessCallback unloadSceneSuccessCallback) + : this(unloadSceneSuccessCallback, null) + { + } + + /// + /// 初始化卸载场景回调函数集的新实例。 + /// + /// 卸载场景成功回调函数。 + /// 卸载场景失败回调函数。 + public UnloadSceneCallbacks(UnloadSceneSuccessCallback unloadSceneSuccessCallback, UnloadSceneFailureCallback unloadSceneFailureCallback) + { + if (unloadSceneSuccessCallback == null) + { + throw new GameFrameworkException("Unload scene success callback is invalid."); + } + + m_UnloadSceneSuccessCallback = unloadSceneSuccessCallback; + m_UnloadSceneFailureCallback = unloadSceneFailureCallback; + } + + /// + /// 获取卸载场景成功回调函数。 + /// + public UnloadSceneSuccessCallback UnloadSceneSuccessCallback + { + get + { + return m_UnloadSceneSuccessCallback; + } + } + + /// + /// 获取卸载场景失败回调函数。 + /// + public UnloadSceneFailureCallback UnloadSceneFailureCallback + { + get + { + return m_UnloadSceneFailureCallback; + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneCallbacks.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneCallbacks.cs.meta new file mode 100644 index 00000000..96419e9f --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneCallbacks.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3856e1a17ca34727908a23ef8e8bf14c +timeCreated: 1679316871 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneFailureCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneFailureCallback.cs new file mode 100644 index 00000000..9023e5e0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneFailureCallback.cs @@ -0,0 +1,9 @@ +namespace TEngine +{ + /// + /// 卸载场景失败回调函数。 + /// + /// 要卸载的场景资源名称。 + /// 用户自定义数据。 + public delegate void UnloadSceneFailureCallback(string sceneAssetName, object userData); +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneFailureCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneFailureCallback.cs.meta new file mode 100644 index 00000000..e0bf533c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneFailureCallback.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9ebdb92d718b42868dfea9cfab1b34d3 +timeCreated: 1679316871 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneSuccessCallback.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneSuccessCallback.cs new file mode 100644 index 00000000..b284b0b8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneSuccessCallback.cs @@ -0,0 +1,9 @@ +namespace TEngine +{ + /// + /// 卸载场景成功回调函数。 + /// + /// 要卸载的场景资源名称。 + /// 用户自定义数据。 + public delegate void UnloadSceneSuccessCallback(string sceneAssetName, object userData); +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneSuccessCallback.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneSuccessCallback.cs.meta new file mode 100644 index 00000000..528ab6aa --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Callback/UnloadSceneSuccessCallback.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 61bcb17553f54f38af01a421632178f1 +timeCreated: 1679316871 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension.meta new file mode 100644 index 00000000..32147634 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 05aa6b982b8e4d91b48b18cf8f095cd3 +timeCreated: 1710733578 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/AssetItemObject.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/AssetItemObject.cs new file mode 100644 index 00000000..67e7d09a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/AssetItemObject.cs @@ -0,0 +1,21 @@ +namespace TEngine +{ + public class AssetItemObject : ObjectBase + { + public static AssetItemObject Create(string location, UnityEngine.Object target) + { + AssetItemObject item = MemoryPool.Acquire(); + item.Initialize(location, target); + return item; + } + + protected internal override void Release(bool isShutdown) + { + if (Target == null) + { + return; + } + GameModule.Resource?.UnloadAsset(Target); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/AssetItemObject.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/AssetItemObject.cs.meta new file mode 100644 index 00000000..28d25dc3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/AssetItemObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 55c1ec74e0324d7eb85a5ac1a2fbae8c +timeCreated: 1710733596 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ISetAssetObject.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ISetAssetObject.cs new file mode 100644 index 00000000..63b43941 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ISetAssetObject.cs @@ -0,0 +1,22 @@ +using GameFramework; + +namespace TEngine +{ + public interface ISetAssetObject : IMemory + { + /// + /// 资源定位地址。 + /// + string Location { get; } + + /// + /// 设置资源。 + /// + void SetAsset(UnityEngine.Object asset); + + /// + /// 是否可以回收。 + /// + bool IsCanRelease(); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ISetAssetObject.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ISetAssetObject.cs.meta new file mode 100644 index 00000000..a809cb13 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ISetAssetObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 62103ad6957d43f9b0f7aedefb5f0fd2 +timeCreated: 1710733596 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement.meta new file mode 100644 index 00000000..9d6e598b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b1adb79bf9f64cf0bcfd261dac77366f +timeCreated: 1710733596 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteExtensions.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteExtensions.cs new file mode 100644 index 00000000..99cbf351 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteExtensions.cs @@ -0,0 +1,27 @@ +using TEngine; +using UnityEngine; +using UnityEngine.UI; + +public static class SetSpriteExtensions +{ + /// + /// 设置图片。 + /// + /// UI/Image。 + /// 资源定位地址。 + /// 是否使用原始分辨率。 + public static void SetSprite(this Image image, string location, bool setNativeSize = false) + { + GameModule.ResourceExt.SetAssetByResources(SetSpriteObject.Create(image, location, setNativeSize)).Forget(); + } + + /// + /// 设置图片。 + /// + /// 2D/SpriteRender。 + /// 资源定位地址。 + public static void SetSprite(this SpriteRenderer spriteRenderer, string location) + { + GameModule.ResourceExt.SetAssetByResources(SetSpriteObject.Create(spriteRenderer, location)).Forget(); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteExtensions.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteExtensions.cs.meta new file mode 100644 index 00000000..b943e1ef --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cdc73f8631e248cf87a4d6151cf3cdaa +timeCreated: 1709017662 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteObject.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteObject.cs new file mode 100644 index 00000000..fa672916 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteObject.cs @@ -0,0 +1,106 @@ +using System; +using UnityEngine; +using UnityEngine.UI; +using Object = UnityEngine.Object; +#if ODIN_INSPECTOR +using Sirenix.OdinInspector; +#endif + +namespace TEngine +{ + [Serializable] + public class SetSpriteObject : ISetAssetObject + { + enum SetType + { + None, + Image, + SpriteRender, + } +#if ODIN_INSPECTOR + [ShowInInspector] +#endif + private SetType setType; + +#if ODIN_INSPECTOR + [ShowInInspector] +#endif + private Image m_Image; + +#if ODIN_INSPECTOR + [ShowInInspector] +#endif + private SpriteRenderer m_SpriteRenderer; + +#if ODIN_INSPECTOR + [ShowInInspector] +#endif + private Sprite Sprite; + + public string Location { get; private set; } + + private bool m_SetNativeSize = false; + + public void SetAsset(Object asset) + { + Sprite = (Sprite)asset; + + if (m_Image != null) + { + m_Image.sprite = Sprite; + if (m_SetNativeSize) + { + m_Image.SetNativeSize(); + } + } + else if (m_SpriteRenderer != null) + { + m_SpriteRenderer.sprite = Sprite; + } + } + + public bool IsCanRelease() + { + if (setType == SetType.Image) + { + return m_Image == null || m_Image.sprite == null || + (Sprite != null && m_Image.sprite != Sprite); + } + else if (setType == SetType.SpriteRender) + { + return m_SpriteRenderer == null || m_SpriteRenderer.sprite == null || + (Sprite != null && m_SpriteRenderer.sprite != Sprite); + } + return true; + } + + public void Clear() + { + m_SpriteRenderer = null; + m_Image = null; + Location = null; + Sprite = null; + setType = SetType.None; + m_SetNativeSize = false; + } + + public static SetSpriteObject Create(Image image, string location, bool setNativeSize = false) + { + SetSpriteObject item = MemoryPool.Acquire(); + item.m_Image = image; + item.m_SetNativeSize = setNativeSize; + item.Location = location; + item.setType = SetType.Image; + return item; + } + + public static SetSpriteObject Create(SpriteRenderer spriteRenderer, string location) + { + SetSpriteObject item = MemoryPool.Acquire(); + item.m_SpriteRenderer = spriteRenderer; + item.Location = location; + item.setType = SetType.SpriteRender; + return item; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteObject.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteObject.cs.meta new file mode 100644 index 00000000..4b7883e0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/Implement/SetSpriteObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bc8ed415858143f6b4a144fc582cd5f2 +timeCreated: 1709016956 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/LoadAssetObject.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/LoadAssetObject.cs new file mode 100644 index 00000000..622e3040 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/LoadAssetObject.cs @@ -0,0 +1,28 @@ +using System; +#if ODIN_INSPECTOR +using Sirenix.OdinInspector; +#endif + +namespace TEngine +{ + [Serializable] + public class LoadAssetObject + { +#if ODIN_INSPECTOR + [ShowInInspector] +#endif + public ISetAssetObject AssetObject { get; } +#if ODIN_INSPECTOR + [ShowInInspector] +#endif + public UnityEngine.Object AssetTarget { get; } +#if UNITY_EDITOR + public bool IsSelect { get; set; } +#endif + public LoadAssetObject(ISetAssetObject obj, UnityEngine.Object assetTarget) + { + AssetObject = obj; + AssetTarget = assetTarget; + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/LoadAssetObject.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/LoadAssetObject.cs.meta new file mode 100644 index 00000000..026a05be --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/LoadAssetObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4d974629251346849206425ac547ba58 +timeCreated: 1710733596 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.Resource.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.Resource.cs new file mode 100644 index 00000000..57b2d325 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.Resource.cs @@ -0,0 +1,62 @@ +using Cysharp.Threading.Tasks; + +namespace TEngine +{ + public partial class ResourceExtComponent + { + /// + /// 资源组件。 + /// + private ResourceModule m_ResourceModule; + + private LoadAssetCallbacks m_LoadAssetCallbacks; + + private void InitializedResources() + { + m_ResourceModule = GameModule.Get(); + m_LoadAssetCallbacks = new LoadAssetCallbacks(OnLoadAssetSuccess, OnLoadAssetFailure); + } + + private void OnLoadAssetFailure(string assetName, LoadResourceStatus status, string errormessage, object userdata) + { + _assetLoadingList.Remove(assetName); + Log.Error("Can not load asset from '{0}' with error message '{1}'.", assetName, errormessage); + } + + private void OnLoadAssetSuccess(string assetName, object asset, float duration, object userdata) + { + _assetLoadingList.Remove(assetName); + ISetAssetObject setAssetObject = (ISetAssetObject)userdata; + UnityEngine.Object assetObject = asset as UnityEngine.Object; + if (assetObject != null) + { + m_AssetItemPool.Register(AssetItemObject.Create(setAssetObject.Location, assetObject), true); + SetAsset(setAssetObject, assetObject); + } + else + { + Log.Error($"Load failure asset type is {asset.GetType()}."); + } + } + + /// + /// 通过资源系统设置资源。 + /// + /// 需要设置的对象。 + public async UniTaskVoid SetAssetByResources(ISetAssetObject setAssetObject) where T : UnityEngine.Object + { + await TryWaitingLoading(setAssetObject.Location); + + if (m_AssetItemPool.CanSpawn(setAssetObject.Location)) + { + var assetObject = (T)m_AssetItemPool.Spawn(setAssetObject.Location).Target; + SetAsset(setAssetObject, assetObject); + } + else + { + _assetLoadingList.Add(setAssetObject.Location); + m_ResourceModule.LoadAssetAsync(setAssetObject.Location, typeof(T), m_LoadAssetCallbacks, setAssetObject); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.Resource.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.Resource.cs.meta new file mode 100644 index 00000000..45ace5fb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.Resource.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 20f4f4f63f9643b79fbbd05750a3a6e0 +timeCreated: 1710733596 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.cs new file mode 100644 index 00000000..fb9a0580 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Cysharp.Threading.Tasks; +using UnityEngine; +using Object = UnityEngine.Object; +#if ODIN_INSPECTOR +using Sirenix.OdinInspector; +#endif + +namespace TEngine +{ + /// + /// 资源组件拓展。 + /// + [DisallowMultipleComponent] + public partial class ResourceExtComponent : Module + { + private readonly TimeoutController _timeoutController = new TimeoutController(); + + /// + /// 正在加载的资源列表。 + /// + private readonly HashSet _assetLoadingList = new HashSet(); + + /// + /// 检查是否可以释放间隔 + /// + [SerializeField] private float m_CheckCanReleaseInterval = 30f; + + private float m_CheckCanReleaseTime = 0.0f; + + /// + /// 对象池自动释放时间间隔 + /// + [SerializeField] private float m_AutoReleaseInterval = 60f; + + /// + /// 保存加载的图片对象 + /// +#if ODIN_INSPECTOR + [ShowInInspector] +#endif + private LinkedList m_LoadAssetObjectsLinkedList; + + /// + /// 散图集合对象池 + /// + private IObjectPool m_AssetItemPool; + + +#if UNITY_EDITOR + public LinkedList LoadAssetObjectsLinkedList + { + get => m_LoadAssetObjectsLinkedList; + set => m_LoadAssetObjectsLinkedList = value; + } +#endif + private IEnumerator Start() + { + yield return new WaitForEndOfFrame(); + ObjectPoolModule objectPoolComponent = GameModule.Get(); + m_AssetItemPool = objectPoolComponent.CreateMultiSpawnObjectPool( + "SetAssetPool", + m_AutoReleaseInterval, 16, 60, 0); + m_LoadAssetObjectsLinkedList = new LinkedList(); + + InitializedResources(); + } + + private void Update() + { + m_CheckCanReleaseTime += Time.unscaledDeltaTime; + if (m_CheckCanReleaseTime < (double)m_CheckCanReleaseInterval) + { + return; + } + + ReleaseUnused(); + } + + /// + /// 回收无引用的缓存资产。 + /// +#if ODIN_INSPECTOR + [Button("Release Unused")] +#endif + public void ReleaseUnused() + { + if (m_LoadAssetObjectsLinkedList == null) + { + return; + } + + LinkedListNode current = m_LoadAssetObjectsLinkedList.First; + while (current != null) + { + var next = current.Next; + if (current.Value.AssetObject.IsCanRelease()) + { + m_AssetItemPool.Unspawn(current.Value.AssetTarget); + MemoryPool.Release(current.Value.AssetObject); + m_LoadAssetObjectsLinkedList.Remove(current); + } + + current = next; + } + + m_CheckCanReleaseTime = 0f; + } + + private void SetAsset(ISetAssetObject setAssetObject, Object assetObject) + { + m_LoadAssetObjectsLinkedList.AddLast(new LoadAssetObject(setAssetObject, assetObject)); + setAssetObject.SetAsset(assetObject); + } + + private async UniTask TryWaitingLoading(string assetObjectKey) + { + if (_assetLoadingList.Contains(assetObjectKey)) + { + try + { + await UniTask.WaitUntil( + () => !_assetLoadingList.Contains(assetObjectKey)) +#if UNITY_EDITOR + .AttachExternalCancellation(_timeoutController.Timeout(TimeSpan.FromSeconds(60))); + _timeoutController.Reset(); +#else + ; +#endif + + } + catch (OperationCanceledException ex) + { + if (_timeoutController.IsTimeout()) + { + Log.Error($"LoadAssetAsync Waiting {assetObjectKey} timeout. reason:{ex.Message}"); + } + } + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.cs.meta new file mode 100644 index 00000000..c83e3e54 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Extension/ResourceExtComponent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6153d27eaaa74c0e9a00c9eb273cc21c +timeCreated: 1710733596 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/HasAssetResult.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/HasAssetResult.cs new file mode 100644 index 00000000..629e5032 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/HasAssetResult.cs @@ -0,0 +1,43 @@ +namespace TEngine +{ + /// + /// 检查资源是否存在的结果。 + /// + public enum HasAssetResult : byte + { + /// + /// 资源不存在。 + /// + NotExist = 0, + + /// + /// 资源需要从远端更新下载。 + /// + AssetOnline, + + /// + /// 存在资源且存储在磁盘上。 + /// + AssetOnDisk, + + /// + /// 存在资源且存储在文件系统里。 + /// + AssetOnFileSystem, + + /// + /// 存在二进制资源且存储在磁盘上。 + /// + BinaryOnDisk, + + /// + /// 存在二进制资源且存储在文件系统里。 + /// + BinaryOnFileSystem, + + /// + /// 资源定位地址无效。 + /// + Valid, + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/HasAssetResult.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/HasAssetResult.cs.meta new file mode 100644 index 00000000..f5755bb2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/HasAssetResult.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2920cfbd71444763a0eb543e88df0bd4 +timeCreated: 1679316902 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs new file mode 100644 index 00000000..25e6f2a2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs @@ -0,0 +1,271 @@ +using System; +using System.Threading; +using Cysharp.Threading.Tasks; +using UnityEngine; +using YooAsset; + +namespace TEngine +{ + /// + /// 资源管理器接口。 + /// + public interface IResourceManager + { + /// + /// 获取当前资源适用的游戏版本号。 + /// + string ApplicableGameVersion { get; } + + /// + /// 获取当前内部资源版本号。 + /// + int InternalResourceVersion { get; } + + /// + /// 获取或设置运行模式。 + /// + EPlayMode PlayMode { get; set; } + + /// + /// 缓存系统启动时的验证级别。 + /// + EVerifyLevel VerifyLevel { get; set; } + + /// + /// 同时下载的最大数目。 + /// + int DownloadingMaxNum { get; set; } + + /// + /// 失败重试最大数目。 + /// + int FailedTryAgain { get; set; } + + /// + /// 获取资源只读区路径。 + /// + string ReadOnlyPath { get; } + + /// + /// 获取资源读写区路径。 + /// + string ReadWritePath { get; } + + /// + /// 设置资源只读区路径。 + /// + /// 资源只读区路径。 + void SetReadOnlyPath(string readOnlyPath); + + /// + /// 设置资源读写区路径。 + /// + /// 资源读写区路径。 + void SetReadWritePath(string readWritePath); + + /// + /// 初始化接口。 + /// + void Initialize(); + + /// + /// 初始化操作。 + /// + /// 资源包名称。 + UniTask InitPackage(string packageName); + + /// + /// 默认资源包名称。 + /// + string DefaultPackageName { get; set; } + + /// + /// 获取或设置异步系统参数,每帧执行消耗的最大时间切片(单位:毫秒)。 + /// + long Milliseconds { get; set; } + + Transform InstanceRoot { get; set; } + + /// + /// 热更链接URL。 + /// + string HostServerURL { get; set; } + + /// + /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 + /// + float AssetAutoReleaseInterval + { + get; + set; + } + + /// + /// 获取或设置资源对象池的容量。 + /// + int AssetCapacity + { + get; + set; + } + + /// + /// 获取或设置资源对象池对象过期秒数。 + /// + float AssetExpireTime + { + get; + set; + } + + /// + /// 获取或设置资源对象池的优先级。 + /// + int AssetPriority + { + get; + set; + } + + /// + /// 卸载资源。 + /// + /// 要卸载的资源。 + void UnloadAsset(object asset); + + /// + /// 资源回收(卸载引用计数为零的资源) + /// + void UnloadUnusedAssets(); + + /// + /// 强制回收所有资源 + /// + void ForceUnloadAllAssets(); + + /// + /// 检查资源是否存在。 + /// + /// 资源定位地址。 + /// 资源包名称。 + /// 检查资源是否存在的结果。 + public HasAssetResult HasAsset(string location, string packageName = ""); + + /// + /// 检查资源定位地址是否有效。 + /// + /// 资源的定位地址 + /// 指定资源包的名称。不传使用默认资源包 + bool CheckLocationValid(string location, string packageName = ""); + + /// + /// 获取资源信息列表。 + /// + /// 资源标签。 + /// 指定资源包的名称。不传使用默认资源包 + /// 资源信息列表。 + AssetInfo[] GetAssetInfos(string resTag, string packageName = ""); + + /// + /// 获取资源信息列表。 + /// + /// 资源标签列表。 + /// 指定资源包的名称。不传使用默认资源包 + /// 资源信息列表。 + AssetInfo[] GetAssetInfos(string[] tags, string packageName = ""); + + /// + /// 获取资源信息。 + /// + /// 资源的定位地址。 + /// 指定资源包的名称。不传使用默认资源包 + /// 资源信息。 + AssetInfo GetAssetInfo(string location, string packageName = ""); + + /// + /// 异步加载资源。 + /// + /// 资源的定位地址。 + /// 加载资源的优先级。 + /// 加载资源回调函数集。 + /// 用户自定义数据。 + /// 指定资源包的名称。不传使用默认资源包。 + void LoadAssetAsync(string location, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = ""); + + /// + /// 异步加载资源。 + /// + /// 资源的定位地址。 + /// 要加载的资源类型。 + /// 加载资源的优先级。 + /// 加载资源回调函数集。 + /// 用户自定义数据。 + /// 指定资源包的名称。不传使用默认资源包。 + void LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = ""); + + /// + /// 同步加载资源。 + /// + /// 资源的定位地址。 + /// 指定资源包的名称。不传使用默认资源包 + /// 要加载资源的类型。 + /// 资源实例。 + T LoadAsset(string location, string packageName = "") where T : UnityEngine.Object; + + /// + /// 同步加载游戏物体并实例化。 + /// + /// 资源的定位地址。 + /// 资源实例父节点。 + /// 指定资源包的名称。不传使用默认资源包 + /// 资源实例。 + /// 会实例化资源到场景,无需主动UnloadAsset,Destroy时自动UnloadAsset。 + GameObject LoadGameObject(string location, Transform parent = null, string packageName = ""); + + /// + /// 异步加载资源。 + /// + /// 资源的定位地址。 + /// 回调函数。 + /// 指定资源包的名称。不传使用默认资源包 + /// 要加载资源的类型。 + UniTaskVoid LoadAsset(string location, Action callback, string packageName = "") where T : UnityEngine.Object; + + /// + /// 同步加载子资源对象。 + /// + /// 资源类型。 + /// 资源的定位地址。 + /// 指定资源包的名称。不传使用默认资源包 + public TObject[] LoadSubAssetsSync(string location, string packageName = "") where TObject : UnityEngine.Object; + + /// + /// 异步加载子资源对象。 + /// + /// 资源类型。 + /// 资源的定位地址。 + /// 指定资源包的名称。不传使用默认资源包 + public UniTask LoadSubAssetsAsync(string location, string packageName = "") where TObject : UnityEngine.Object; + + /// + /// 异步加载资源。 + /// + /// 资源定位地址。 + /// 取消操作Token。 + /// 指定资源包的名称。不传使用默认资源包 + /// 要加载资源的类型。 + /// 异步资源实例。 + UniTask LoadAssetAsync(string location, CancellationToken cancellationToken = default, string packageName = "") where T : UnityEngine.Object; + + /// + /// 异步加载游戏物体并实例化。 + /// + /// 资源定位地址。 + /// 资源实例父节点。 + /// 取消操作Token。 + /// 指定资源包的名称。不传使用默认资源包 + /// 异步游戏物体实例。 + /// 会实例化资源到场景,无需主动UnloadAsset,Destroy时自动UnloadAsset。 + UniTask LoadGameObjectAsync(string location, Transform parent = null, CancellationToken cancellationToken = default, string packageName = ""); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs.meta new file mode 100644 index 00000000..a23cf01a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/IResourceManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e20a9858963a4474bd4d6530e2063925 +timeCreated: 1706852080 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ReadWritePathType.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ReadWritePathType.cs new file mode 100644 index 00000000..93d49ee9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ReadWritePathType.cs @@ -0,0 +1,23 @@ +namespace TEngine +{ + /// + /// 读写区路径类型。 + /// + public enum ReadWritePathType : byte + { + /// + /// 未指定。 + /// + Unspecified = 0, + + /// + /// 临时缓存。 + /// + TemporaryCache, + + /// + /// 持久化数据。 + /// + PersistentData, + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ReadWritePathType.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ReadWritePathType.cs.meta new file mode 100644 index 00000000..c87236f1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ReadWritePathType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8341f456508843e3b4b4dee2db753a0d +timeCreated: 1679327686 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference.meta new file mode 100644 index 00000000..9330e607 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bef1492ba93a44e69ad169534623e043 +timeCreated: 1708489036 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsReference.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsReference.cs new file mode 100644 index 00000000..4029cd3d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsReference.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace TEngine +{ + [Serializable] + public struct AssetsRefInfo + { + public int instanceId; + + public Object refAsset; + + public AssetsRefInfo(Object refAsset) + { + this.refAsset = refAsset; + instanceId = this.refAsset.GetInstanceID(); + } + } + + public sealed class AssetsReference : MonoBehaviour + { + [SerializeField] private GameObject _sourceGameObject; + + [SerializeField] private List _refAssetInfoList; + + private IResourceManager _resourceManager; + + private void OnDestroy() + { + if (_resourceManager == null) + { + _resourceManager = ModuleImpSystem.GetModule(); + } + + if (_resourceManager == null) + { + throw new GameFrameworkException($"ResourceManager is null."); + } + + if (_sourceGameObject != null) + { + _resourceManager.UnloadAsset(_sourceGameObject); + } + + ReleaseRefAssetInfoList(); + } + + private void ReleaseRefAssetInfoList() + { + if (_refAssetInfoList != null) + { + foreach (var refInfo in _refAssetInfoList) + { + _resourceManager.UnloadAsset(refInfo.refAsset); + } + + _refAssetInfoList.Clear(); + } + } + + public AssetsReference Ref(GameObject source, IResourceManager resourceManager = null) + { + if (source == null) + { + throw new GameFrameworkException($"Source gameObject is null."); + } + + if (source.scene.name != null) + { + throw new GameFrameworkException($"Source gameObject is in scene."); + } + + _resourceManager = resourceManager; + _sourceGameObject = source; + return this; + } + + public AssetsReference Ref(T source, IResourceManager resourceManager = null) where T : UnityEngine.Object + { + if (source == null) + { + throw new GameFrameworkException($"Source gameObject is null."); + } + + _resourceManager = resourceManager; + if (_refAssetInfoList == null) + { + _refAssetInfoList = new List(); + } + _refAssetInfoList.Add(new AssetsRefInfo(source)); + return this; + } + + public static AssetsReference Instantiate(GameObject source, Transform parent = null, IResourceManager resourceManager = null) + { + if (source == null) + { + throw new GameFrameworkException($"Source gameObject is null."); + } + + if (source.scene.name != null) + { + throw new GameFrameworkException($"Source gameObject is in scene."); + } + + GameObject instance = Object.Instantiate(source, parent); + return instance.AddComponent().Ref(source, resourceManager); + } + + public static AssetsReference Ref(GameObject source, GameObject instance, IResourceManager resourceManager = null) + { + if (source == null) + { + throw new GameFrameworkException($"Source gameObject is null."); + } + + if (source.scene.name != null) + { + throw new GameFrameworkException($"Source gameObject is in scene."); + } + + return instance.GetOrAddComponent().Ref(source, resourceManager); + } + + public static AssetsReference Ref(T source, GameObject instance, IResourceManager resourceManager = null) where T : UnityEngine.Object + { + if (source == null) + { + throw new GameFrameworkException($"Source gameObject is null."); + } + + return instance.GetOrAddComponent().Ref(source, resourceManager); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsReference.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsReference.cs.meta new file mode 100644 index 00000000..7d7ce39c --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsReference.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 06f544cfcd9c41f0a316144b949e8d01 +timeCreated: 1708487319 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsSetHelper.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsSetHelper.cs new file mode 100644 index 00000000..2c48bd5d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsSetHelper.cs @@ -0,0 +1,150 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace TEngine +{ + public static class AssetsSetHelper + { + private static IResourceManager _resourceManager; + + private static void CheckResourceManager() + { + if (_resourceManager == null) + { + _resourceManager = ModuleImpSystem.GetModule(); + } + } + + #region SetMaterial + + public static void SetMaterial(this Image image, string location, bool isAsync = false, string packageName = "") + { + if (image == null) + { + throw new GameFrameworkException($"SetSprite failed. Because image is null."); + } + + CheckResourceManager(); + + if (!isAsync) + { + Material material = _resourceManager.LoadAsset(location, packageName); + image.material = material; + AssetsReference.Ref(material, image.gameObject); + } + else + { + _resourceManager.LoadAsset(location, material => + { + if (image == null || image.gameObject == null) + { + _resourceManager.UnloadAsset(material); + material = null; + return; + } + + image.material = material; + AssetsReference.Ref(material, image.gameObject); + }, packageName); + } + } + + public static void SetMaterial(this SpriteRenderer spriteRenderer, string location, bool isAsync = false, string packageName = "") + { + if (spriteRenderer == null) + { + throw new GameFrameworkException($"SetSprite failed. Because image is null."); + } + + CheckResourceManager(); + + if (!isAsync) + { + Material material = _resourceManager.LoadAsset(location, packageName); + spriteRenderer.material = material; + AssetsReference.Ref(material, spriteRenderer.gameObject); + } + else + { + _resourceManager.LoadAsset(location, material => + { + if (spriteRenderer == null || spriteRenderer.gameObject == null) + { + _resourceManager.UnloadAsset(material); + material = null; + return; + } + + spriteRenderer.material = material; + AssetsReference.Ref(material, spriteRenderer.gameObject); + }, packageName); + } + } + + public static void SetMaterial(this MeshRenderer meshRenderer, string location, bool needInstance = true, bool isAsync = false, string packageName = "") + { + if (meshRenderer == null) + { + throw new GameFrameworkException($"SetSprite failed. Because image is null."); + } + + CheckResourceManager(); + + if (!isAsync) + { + Material material = _resourceManager.LoadAsset(location, packageName); + meshRenderer.material = needInstance ? Object.Instantiate(material) : material; + AssetsReference.Ref(material, meshRenderer.gameObject); + } + else + { + _resourceManager.LoadAsset(location, material => + { + if (meshRenderer == null || meshRenderer.gameObject == null) + { + _resourceManager.UnloadAsset(material); + material = null; + return; + } + + meshRenderer.material = needInstance ? Object.Instantiate(material) : material; + AssetsReference.Ref(material, meshRenderer.gameObject); + }, packageName); + } + } + + public static void SetSharedMaterial(this MeshRenderer meshRenderer, string location, bool isAsync = false, string packageName = "") + { + if (meshRenderer == null) + { + throw new GameFrameworkException($"SetSprite failed. Because image is null."); + } + + CheckResourceManager(); + + if (!isAsync) + { + Material material = _resourceManager.LoadAsset(location, packageName); + meshRenderer.sharedMaterial = material; + AssetsReference.Ref(material, meshRenderer.gameObject); + } + else + { + _resourceManager.LoadAsset(location, material => + { + if (meshRenderer == null || meshRenderer.gameObject == null) + { + _resourceManager.UnloadAsset(material); + material = null; + return; + } + + meshRenderer.sharedMaterial = material; + AssetsReference.Ref(material, meshRenderer.gameObject); + }, packageName); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsSetHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsSetHelper.cs.meta new file mode 100644 index 00000000..70d234bd --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/Reference/AssetsSetHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b78d5b769389454b9cf8f086f97246db +timeCreated: 1708490345 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceLogger.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceLogger.cs new file mode 100644 index 00000000..6fb34c26 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceLogger.cs @@ -0,0 +1,25 @@ +namespace TEngine +{ + internal class ResourceLogger : YooAsset.ILogger + { + public void Log(string message) + { + TEngine.Log.Info(message); + } + + public void Warning(string message) + { + TEngine.Log.Warning(message); + } + + public void Error(string message) + { + TEngine.Log.Error(message); + } + + public void Exception(System.Exception exception) + { + TEngine.Log.Fatal(exception.Message); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceLogger.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceLogger.cs.meta new file mode 100644 index 00000000..d035c917 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceLogger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2415ba61b5cf4bd2a00173f638c6bb39 +timeCreated: 1706863755 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.AssetObject.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.AssetObject.cs new file mode 100644 index 00000000..f371c402 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.AssetObject.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using YooAsset; + +namespace TEngine +{ + internal partial class ResourceManager + { + /// + /// 资源对象。 + /// + private sealed class AssetObject : ObjectBase + { + private AssetHandle m_AssetHandle; + private ResourceManager m_ResourceManager; + + + public AssetObject() + { + m_AssetHandle = null; + } + + public static AssetObject Create(string name, object target, object assetHandle, ResourceManager resourceManager) + { + if (assetHandle == null) + { + throw new GameFrameworkException("Resource is invalid."); + } + + if (resourceManager == null) + { + throw new GameFrameworkException("Resource Manager is invalid."); + } + + AssetObject assetObject = MemoryPool.Acquire(); + assetObject.Initialize(name, target); + assetObject.m_AssetHandle = (AssetHandle)assetHandle; + assetObject.m_ResourceManager = resourceManager; + return assetObject; + } + + public override void Clear() + { + base.Clear(); + m_AssetHandle = null; + } + + protected internal override void OnUnspawn() + { + base.OnUnspawn(); + } + + protected internal override void Release(bool isShutdown) + { + if (!isShutdown) + { + AssetHandle handle = m_AssetHandle; + if (handle is { IsValid: true }) + { + handle.Dispose(); + } + handle = null; + } + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.AssetObject.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.AssetObject.cs.meta new file mode 100644 index 00000000..268b4a76 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.AssetObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3d1fa38cbc7a45e1b36acf2f337aa0a0 +timeCreated: 1706867174 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Pool.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Pool.cs new file mode 100644 index 00000000..061c8eb9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Pool.cs @@ -0,0 +1,68 @@ +namespace TEngine +{ + internal partial class ResourceManager + { + private IObjectPool m_AssetPool; + + /// + /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 + /// + public float AssetAutoReleaseInterval + { + get => m_AssetPool.AutoReleaseInterval; + set => m_AssetPool.AutoReleaseInterval = value; + } + + /// + /// 获取或设置资源对象池的容量。 + /// + public int AssetCapacity + { + get => m_AssetPool.Capacity; + set => m_AssetPool.Capacity = value; + } + + /// + /// 获取或设置资源对象池对象过期秒数。 + /// + public float AssetExpireTime + { + get => m_AssetPool.ExpireTime; + set => m_AssetPool.ExpireTime = value; + } + + /// + /// 获取或设置资源对象池的优先级。 + /// + public int AssetPriority + { + get => m_AssetPool.Priority; + set => m_AssetPool.Priority = value; + } + + /// + /// 卸载资源。 + /// + /// 要卸载的资源。 + public void UnloadAsset(object asset) + { + if (m_AssetPool != null) + { + m_AssetPool.Unspawn(asset); + } + } + + /// + /// 设置对象池管理器。 + /// + /// 对象池管理器。 + public void SetObjectPoolManager(IObjectPoolManager objectPoolManager) + { + if (objectPoolManager == null) + { + throw new GameFrameworkException("Object pool manager is invalid."); + } + m_AssetPool = objectPoolManager.CreateMultiSpawnObjectPool("Asset Pool"); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Pool.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Pool.cs.meta new file mode 100644 index 00000000..b9017c43 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Pool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 53fdfc057f4c4fafa91d6a0d563f6dfa +timeCreated: 1706867111 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Services.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Services.cs new file mode 100644 index 00000000..2a046843 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Services.cs @@ -0,0 +1,297 @@ +using System.Collections.Generic; +using System.IO; +using GameFramework.Runtime; +using UnityEngine; +using YooAsset; + +namespace TEngine +{ + internal partial class ResourceManager + { + /// + /// 远端资源地址查询服务类 + /// + private class RemoteServices : IRemoteServices + { + private readonly string _defaultHostServer; + private readonly string _fallbackHostServer; + + public RemoteServices(string defaultHostServer, string fallbackHostServer) + { + _defaultHostServer = defaultHostServer; + _fallbackHostServer = fallbackHostServer; + } + string IRemoteServices.GetRemoteMainURL(string fileName) + { + return $"{_defaultHostServer}/{fileName}"; + } + string IRemoteServices.GetRemoteFallbackURL(string fileName) + { + return $"{_fallbackHostServer}/{fileName}"; + } + } + + /// + /// 资源文件流加载解密类 + /// + private class FileStreamDecryption : IDecryptionServices + { + /// + /// 同步方式获取解密的资源包对象 + /// 注意:加载流对象在资源包对象释放的时候会自动释放 + /// + AssetBundle IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo, out Stream managedStream) + { + BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read); + managedStream = bundleStream; + return AssetBundle.LoadFromStream(bundleStream, fileInfo.ConentCRC, GetManagedReadBufferSize()); + } + + /// + /// 异步方式获取解密的资源包对象 + /// 注意:加载流对象在资源包对象释放的时候会自动释放 + /// + AssetBundleCreateRequest IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo, out Stream managedStream) + { + BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read); + managedStream = bundleStream; + return AssetBundle.LoadFromStreamAsync(bundleStream, fileInfo.ConentCRC, GetManagedReadBufferSize()); + } + + private static uint GetManagedReadBufferSize() + { + return 1024; + } + } + + /// + /// 资源文件偏移加载解密类 + /// + private class FileOffsetDecryption : IDecryptionServices + { + /// + /// 同步方式获取解密的资源包对象 + /// 注意:加载流对象在资源包对象释放的时候会自动释放 + /// + AssetBundle IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo, out Stream managedStream) + { + managedStream = null; + return AssetBundle.LoadFromFile(fileInfo.FileLoadPath, fileInfo.ConentCRC, GetFileOffset()); + } + + /// + /// 异步方式获取解密的资源包对象 + /// 注意:加载流对象在资源包对象释放的时候会自动释放 + /// + AssetBundleCreateRequest IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo, out Stream managedStream) + { + managedStream = null; + return AssetBundle.LoadFromFileAsync(fileInfo.FileLoadPath, fileInfo.ConentCRC, GetFileOffset()); + } + + private static ulong GetFileOffset() + { + return 32; + } + } + } + + /// + /// 资源文件解密流 + /// + public class BundleStream : FileStream + { + public const byte KEY = 64; + + public BundleStream(string path, FileMode mode, FileAccess access, FileShare share) : base(path, mode, access, share) + { + } + + public BundleStream(string path, FileMode mode) : base(path, mode) + { + } + + public override int Read(byte[] array, int offset, int count) + { + var index = base.Read(array, offset, count); + for (int i = 0; i < array.Length; i++) + { + array[i] ^= KEY; + } + + return index; + } + } + + /// + /// 资源文件查询服务类 + /// + public class GameQueryServices : IBuildinQueryServices + { + /// + /// 查询内置文件的时候,是否比对文件哈希值 + /// + public static bool CompareFileCRC = false; + + public bool Query(string packageName, string fileName, string fileCRC) + { + // 注意:fileName包含文件格式 + return StreamingAssetsHelper.FileExists(packageName, fileName, fileCRC); + } + } + + public class StreamingAssetsDefine + { + /// + /// 根目录名称(保持和YooAssets资源系统一致) + /// + public const string RootFolderName = "package"; + } + +#if UNITY_EDITOR + public sealed class StreamingAssetsHelper + { + public static void Init() + { + } + + public static bool FileExists(string packageName, string fileName, string fileCRC) + { + string filePath = Path.Combine(Application.streamingAssetsPath, StreamingAssetsDefine.RootFolderName, packageName, fileName); + if (File.Exists(filePath)) + { + if (GameQueryServices.CompareFileCRC) + { + string crc32 = YooAsset.HashUtility.FileCRC32(filePath); + return crc32 == fileCRC; + } + else + { + return true; + } + } + else + { + return false; + } + } + } +#else +public sealed class StreamingAssetsHelper +{ + private class PackageQuery + { + public readonly Dictionary Elements = new Dictionary(1000); + } + + private static bool _isInit = false; + private static readonly Dictionary _packages = new Dictionary(10); + + /// + /// 初始化 + /// + public static void Init() + { + if (_isInit == false) + { + _isInit = true; + + var manifest = Resources.Load("BuildinFileManifest"); + if (manifest != null) + { + foreach (var element in manifest.BuildinFiles) + { + if (_packages.TryGetValue(element.PackageName, out PackageQuery package) == false) + { + package = new PackageQuery(); + _packages.Add(element.PackageName, package); + } + package.Elements.Add(element.FileName, element); + } + } + } + } + + /// + /// 内置文件查询方法 + /// + public static bool FileExists(string packageName, string fileName, string fileCRC32) + { + if (_isInit == false) + Init(); + + if (_packages.TryGetValue(packageName, out PackageQuery package) == false) + return false; + + if (package.Elements.TryGetValue(fileName, out var element) == false) + return false; + + if (GameQueryServices.CompareFileCRC) + { + return element.FileCRC32 == fileCRC32; + } + else + { + return true; + } + } +} +#endif + + +#if UNITY_EDITOR + internal class PreprocessBuild : UnityEditor.Build.IPreprocessBuildWithReport + { + public int callbackOrder + { + get { return 0; } + } + + /// + /// 在构建应用程序前处理 + /// 原理:在构建APP之前,搜索StreamingAssets目录下的所有资源文件,然后将这些文件信息写入内置清单,内置清单存储在Resources文件夹下。 + /// + public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report) + { + string saveFilePath = "Assets/AATemp/Resources/BuildinFileManifest.asset"; + if (File.Exists(saveFilePath)) + { + File.Delete(saveFilePath); + UnityEditor.AssetDatabase.SaveAssets(); + UnityEditor.AssetDatabase.Refresh(); + } + + string folderPath = $"{Application.dataPath}/StreamingAssets/{StreamingAssetsDefine.RootFolderName}"; + DirectoryInfo root = new DirectoryInfo(folderPath); + if (root.Exists == false) + { + Debug.LogWarning($"没有发现YooAsset内置目录 : {folderPath}"); + return; + } + + var manifest = ScriptableObject.CreateInstance(); + FileInfo[] files = root.GetFiles("*", SearchOption.AllDirectories); + foreach (var fileInfo in files) + { + if (fileInfo.Extension == ".meta") + continue; + if (fileInfo.Name.StartsWith("PackageManifest_")) + continue; + + BuildinFileManifest.Element element = new BuildinFileManifest.Element(); + element.PackageName = fileInfo.Directory.Name; + element.FileCRC32 = YooAsset.HashUtility.FileCRC32(fileInfo.FullName); + element.FileName = fileInfo.Name; + manifest.BuildinFiles.Add(element); + } + + if (Directory.Exists("Assets/AATemp/Resources") == false) + Directory.CreateDirectory("Assets/AATemp/Resources"); + UnityEditor.AssetDatabase.CreateAsset(manifest, saveFilePath); + UnityEditor.AssetDatabase.SaveAssets(); + UnityEditor.AssetDatabase.Refresh(); + Debug.Log($"一共{manifest.BuildinFiles.Count}个内置文件,内置资源清单保存成功 : {saveFilePath}"); + } + } +#endif +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Services.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Services.cs.meta new file mode 100644 index 00000000..056f5d78 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.Services.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c5103c2001ac40f48b5e3d4653624a5a +timeCreated: 1679030837 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs new file mode 100644 index 00000000..6918a340 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs @@ -0,0 +1,976 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using Cysharp.Threading.Tasks; +using UnityEngine; +using YooAsset; + +namespace TEngine +{ + /// + /// 资源管理器。 + /// + internal sealed partial class ResourceManager : ModuleImp, IResourceManager + { + #region Propreties + + /// + /// 资源包名称。 + /// + public string DefaultPackageName + { + get => _defaultPackageName; + set => _defaultPackageName = value; + } + + /// + /// 资源系统运行模式。 + /// + public EPlayMode PlayMode { get; set; } + + /// + /// 下载文件校验等级。 + /// + public EVerifyLevel VerifyLevel { get; set; } + + /// + /// 设置异步系统参数,每帧执行消耗的最大时间切片(单位:毫秒) + /// + public long Milliseconds { get; set; } + + /// + /// 获取游戏框架模块优先级。 + /// + /// 优先级较高的模块会优先轮询,并且关闭操作会后进行。 + internal override int Priority => 4; + + /// + /// 实例化的根节点。 + /// + public Transform InstanceRoot { get; set; } + + /// + /// Propagates notification that operations should be canceled. + /// + public CancellationToken CancellationToken { get; private set; } + + /// + /// 资源服务器地址。 + /// + public string HostServerURL { get; set; } + + public string FallbackHostServerURL { get; set; } + + private string m_ApplicableGameVersion; + + private int m_InternalResourceVersion; + + private string m_ReadOnlyPath; + private string m_ReadWritePath; + private string _defaultPackageName = "DefaultPackage"; + + /// + /// 获取资源只读区路径。 + /// + public string ReadOnlyPath => m_ReadOnlyPath; + + /// + /// 获取资源读写区路径。 + /// + public string ReadWritePath => m_ReadWritePath; + + /// + /// 获取当前资源适用的游戏版本号。 + /// + public string ApplicableGameVersion => m_ApplicableGameVersion; + + /// + /// 获取当前内部资源版本号。 + /// + public int InternalResourceVersion => m_InternalResourceVersion; + + public int DownloadingMaxNum { get; set; } + public int FailedTryAgain { get; set; } + + + /// + /// 默认资源包。 + /// + internal ResourcePackage DefaultPackage { private set; get; } + + /// + /// 资源包列表。 + /// + private Dictionary PackageMap { get; } = new Dictionary(); + + /// + /// 资源信息列表。 + /// + private readonly Dictionary _assetInfoMap = new Dictionary(); + + /// + /// 正在加载的资源列表。 + /// + private readonly HashSet _assetLoadingList = new HashSet(); + #endregion + + /// + /// 初始化资源管理器的新实例。 + /// + public ResourceManager() + { + } + + public void Initialize() + { + // 初始化资源系统 + YooAssets.Initialize(new ResourceLogger()); + YooAssets.SetOperationSystemMaxTimeSlice(Milliseconds); + +#if UNITY_WECHAT_GAME && !UNITY_EDITOR + YooAssets.SetCacheSystemDisableCacheOnWebGL(); +#endif + + // 创建默认的资源包 + string packageName = DefaultPackageName; + var defaultPackage = YooAssets.TryGetPackage(packageName); + if (defaultPackage == null) + { + defaultPackage = YooAssets.CreatePackage(packageName); + YooAssets.SetDefaultPackage(defaultPackage); + DefaultPackage = defaultPackage; + } + + CancellationToken = InstanceRoot.gameObject.GetCancellationTokenOnDestroy(); + + IObjectPoolManager objectPoolManager = ModuleImpSystem.GetModule(); + SetObjectPoolManager(objectPoolManager); + } + + #region 设置接口 + + /// + /// 设置资源只读区路径。 + /// + /// 资源只读区路径。 + public void SetReadOnlyPath(string readOnlyPath) + { + if (string.IsNullOrEmpty(readOnlyPath)) + { + throw new GameFrameworkException("Read-only path is invalid."); + } + + m_ReadOnlyPath = readOnlyPath; + } + + /// + /// 设置资源读写区路径。 + /// + /// 资源读写区路径。 + public void SetReadWritePath(string readWritePath) + { + if (string.IsNullOrEmpty(readWritePath)) + { + throw new GameFrameworkException("Read-write path is invalid."); + } + + m_ReadWritePath = readWritePath; + } + + #endregion + + public async UniTask InitPackage(string packageName) + { +#if UNITY_EDITOR + //编辑器模式使用。 + EPlayMode playMode = (EPlayMode)UnityEditor.EditorPrefs.GetInt("EditorPlayMode"); + Log.Warning($"Editor Module Used :{playMode}"); +#else + //运行时使用。 + EPlayMode playMode = (EPlayMode)PlayMode; +#endif + + if (PackageMap.ContainsKey(packageName)) + { + Log.Error($"ResourceSystem has already init package : {packageName}"); + return null; + } + + // 创建资源包裹类 + var package = YooAssets.TryGetPackage(packageName); + if (package == null) + { + package = YooAssets.CreatePackage(packageName); + } + + PackageMap[packageName] = package; + + // 编辑器下的模拟模式 + InitializationOperation initializationOperation = null; + if (playMode == EPlayMode.EditorSimulateMode) + { + var createParameters = new EditorSimulateModeParameters(); + createParameters.CacheBootVerifyLevel = VerifyLevel; + createParameters.SimulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild(EDefaultBuildPipeline.BuiltinBuildPipeline, packageName); + initializationOperation = package.InitializeAsync(createParameters); + } + + // 单机运行模式 + if (playMode == EPlayMode.OfflinePlayMode) + { + var createParameters = new OfflinePlayModeParameters(); + createParameters.CacheBootVerifyLevel = VerifyLevel; + createParameters.DecryptionServices = new FileStreamDecryption(); + initializationOperation = package.InitializeAsync(createParameters); + } + + // 联机运行模式 + if (playMode == EPlayMode.HostPlayMode) + { + string defaultHostServer = HostServerURL; + string fallbackHostServer = FallbackHostServerURL; + var createParameters = new HostPlayModeParameters(); + createParameters.CacheBootVerifyLevel = VerifyLevel; + createParameters.DecryptionServices = new FileStreamDecryption(); + createParameters.BuildinQueryServices = new GameQueryServices(); + createParameters.RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer); + initializationOperation = package.InitializeAsync(createParameters); + } + + // WebGL运行模式 + if (playMode == EPlayMode.WebPlayMode) + { + string defaultHostServer = HostServerURL; + string fallbackHostServer = FallbackHostServerURL; + var createParameters = new WebPlayModeParameters(); + createParameters.CacheBootVerifyLevel = VerifyLevel; + createParameters.DecryptionServices = new FileStreamDecryption(); + createParameters.BuildinQueryServices = new GameQueryServices(); + createParameters.RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer); + initializationOperation = package.InitializeAsync(createParameters); + } + + await initializationOperation.ToUniTask(); + + Log.Info($"Init resource package version : {initializationOperation?.PackageVersion}"); + + return initializationOperation; + } + + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + } + + internal override void Shutdown() + { + PackageMap.Clear(); + m_AssetPool = null; + _assetLoadingList.Clear(); + _assetInfoMap.Clear(); +#if !UNITY_WEBGL + YooAssets.Destroy(); +#endif + } + + #region Public Methods + + #region 获取资源信息 + + /// + /// 是否需要从远端更新下载。 + /// + /// 资源的定位地址。 + /// 资源包名称。 + public bool IsNeedDownloadFromRemote(string location, string packageName = "") + { + if (string.IsNullOrEmpty(packageName)) + { + return YooAssets.IsNeedDownloadFromRemote(location); + } + else + { + var package = YooAssets.GetPackage(packageName); + return package.IsNeedDownloadFromRemote(location); + } + } + + /// + /// 是否需要从远端更新下载。 + /// + /// 资源信息。 + /// 资源包名称。 + public bool IsNeedDownloadFromRemote(AssetInfo assetInfo, string packageName = "") + { + if (string.IsNullOrEmpty(packageName)) + { + return YooAssets.IsNeedDownloadFromRemote(assetInfo); + } + else + { + var package = YooAssets.GetPackage(packageName); + return package.IsNeedDownloadFromRemote(assetInfo); + } + } + + /// + /// 获取资源信息列表。 + /// + /// 资源标签。 + /// 资源包名称。 + /// 资源信息列表。 + public AssetInfo[] GetAssetInfos(string tag, string packageName = "") + { + if (string.IsNullOrEmpty(packageName)) + { + return YooAssets.GetAssetInfos(tag); + } + else + { + var package = YooAssets.GetPackage(packageName); + return package.GetAssetInfos(tag); + } + } + + /// + /// 获取资源信息列表。 + /// + /// 资源标签列表。 + /// 资源包名称。 + /// 资源信息列表。 + public AssetInfo[] GetAssetInfos(string[] tags, string packageName = "") + { + if (string.IsNullOrEmpty(packageName)) + { + return YooAssets.GetAssetInfos(tags); + } + else + { + var package = YooAssets.GetPackage(packageName); + return package.GetAssetInfos(tags); + } + } + + /// + /// 获取资源信息。 + /// + /// 资源的定位地址。 + /// 资源包名称。 + /// 资源信息。 + public AssetInfo GetAssetInfo(string location, string packageName = "") + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + if (string.IsNullOrEmpty(packageName)) + { + if (_assetInfoMap.TryGetValue(location, out AssetInfo assetInfo)) + { + return assetInfo; + } + + assetInfo = YooAssets.GetAssetInfo(location); + _assetInfoMap[location] = assetInfo; + return assetInfo; + } + else + { + string key = $"{packageName}/{location}"; + if (_assetInfoMap.TryGetValue(key, out AssetInfo assetInfo)) + { + return assetInfo; + } + + var package = YooAssets.GetPackage(packageName); + if (package == null) + { + throw new GameFrameworkException($"The package does not exist. Package Name :{packageName}"); + } + + assetInfo = package.GetAssetInfo(location); + _assetInfoMap[key] = assetInfo; + return assetInfo; + } + } + + /// + /// 检查资源是否存在。 + /// + /// 资源定位地址。 + /// 资源包名称。 + /// 检查资源是否存在的结果。 + public HasAssetResult HasAsset(string location, string packageName = "") + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + AssetInfo assetInfo = GetAssetInfo(location, packageName); + + if (!CheckLocationValid(location)) + { + return HasAssetResult.Valid; + } + + if (assetInfo == null) + { + return HasAssetResult.NotExist; + } + + if (IsNeedDownloadFromRemote(assetInfo)) + { + return HasAssetResult.AssetOnline; + } + + return HasAssetResult.AssetOnDisk; + } + + /// + /// 检查资源定位地址是否有效。 + /// + /// 资源的定位地址 + /// 资源包名称。 + public bool CheckLocationValid(string location, string packageName = "") + { + if (string.IsNullOrEmpty(packageName)) + { + return YooAssets.CheckLocationValid(location); + } + else + { + var package = YooAssets.GetPackage(packageName); + return package.CheckLocationValid(location); + } + } + + #endregion + + #region 资源加载 + + #region 获取资源句柄 + /// + /// 获取同步资源句柄。 + /// + /// 资源定位地址。 + /// 指定资源包的名称。不传使用默认资源包 + /// 资源类型。 + /// 资源句柄。 + private AssetHandle GetHandleSync(string location, string packageName = "") where T : UnityEngine.Object + { + return GetHandleSync(location,typeof(T), packageName); + } + + private AssetHandle GetHandleSync(string location, Type assetType, string packageName = "") + { + if (string.IsNullOrEmpty(packageName)) + { + return YooAssets.LoadAssetSync(location, assetType); + } + + var package = YooAssets.GetPackage(packageName); + return package.LoadAssetSync(location, assetType); + } + + /// + /// 获取异步资源句柄。 + /// + /// 资源定位地址。 + /// 指定资源包的名称。不传使用默认资源包 + /// 资源类型。 + /// 资源句柄。 + private AssetHandle GetHandleAsync(string location, string packageName = "") where T : UnityEngine.Object + { + return GetHandleAsync(location, typeof(T), packageName); + } + + private AssetHandle GetHandleAsync(string location, Type assetType, string packageName = "") + { + if (string.IsNullOrEmpty(packageName)) + { + return YooAssets.LoadAssetAsync(location, assetType); + } + + var package = YooAssets.GetPackage(packageName); + return package.LoadAssetAsync(location, assetType); + } + #endregion + + /// + /// 获取资源定位地址的缓存Key。 + /// + /// 资源定位地址。 + /// 资源包名称。 + /// 资源定位地址的缓存Key。 + private string GetCacheKey(string location, string packageName = "") + { + if (string.IsNullOrEmpty(packageName) || packageName.Equals(DefaultPackageName)) + { + return location; + } + return $"{packageName}/{location}"; + } + + public T LoadAsset(string location, string packageName = "") where T : UnityEngine.Object + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + string assetObjectKey = GetCacheKey(location, packageName); + AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey); + if (assetObject != null) + { + return assetObject.Target as T; + } + + AssetHandle handle = GetHandleSync(location, packageName: packageName); + + T ret = handle.AssetObject as T; + + assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle,this); + m_AssetPool.Register(assetObject, true); + + return ret; + } + + public GameObject LoadGameObject(string location, Transform parent = null, string packageName = "") + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + string assetObjectKey = GetCacheKey(location, packageName); + AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey); + if (assetObject != null) + { + return AssetsReference.Instantiate(assetObject.Target as GameObject, parent, this).gameObject; + } + + AssetHandle handle = GetHandleSync(location, packageName: packageName); + + GameObject gameObject = AssetsReference.Instantiate(handle.AssetObject as GameObject, parent, this).gameObject; + + assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle,this); + m_AssetPool.Register(assetObject, true); + + return gameObject; + } + + /// + /// 异步加载资源。 + /// + /// 资源的定位地址。 + /// 回调函数。 + /// 指定资源包的名称。不传使用默认资源包 + /// 要加载资源的类型。 + public async UniTaskVoid LoadAsset(string location, Action callback, string packageName = "") where T : UnityEngine.Object + { + if (string.IsNullOrEmpty(location)) + { + Log.Error("Asset name is invalid."); + return; + } + + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + string assetObjectKey = GetCacheKey(location, packageName); + + await TryWaitingLoading(assetObjectKey); + + AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey); + if (assetObject != null) + { + await UniTask.Yield(); + callback?.Invoke(assetObject.Target as T); + return; + } + + _assetLoadingList.Add(assetObjectKey); + + AssetHandle handle = GetHandleAsync(location, packageName: packageName); + + handle.Completed += assetHandle => + { + _assetLoadingList.Remove(assetObjectKey); + + if (assetHandle.AssetObject != null) + { + assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle,this); + m_AssetPool.Register(assetObject, true); + + callback?.Invoke(assetObject.Target as T); + } + else + { + callback?.Invoke(null); + } + }; + } + + public TObject[] LoadSubAssetsSync(string location, string packageName = "") where TObject : UnityEngine.Object + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + throw new NotImplementedException(); + } + + public UniTask LoadSubAssetsAsync(string location, string packageName = "") where TObject : UnityEngine.Object + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + throw new NotImplementedException(); + } + + public async UniTask LoadAssetAsync(string location, CancellationToken cancellationToken = default, string packageName = "") where T : UnityEngine.Object + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + string assetObjectKey = GetCacheKey(location, packageName); + + await TryWaitingLoading(assetObjectKey); + + AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey); + if (assetObject != null) + { + await UniTask.Yield(); + return assetObject.Target as T; + } + + _assetLoadingList.Add(assetObjectKey); + + AssetHandle handle = GetHandleAsync(location, packageName: packageName); + + bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow(); + + if (cancelOrFailed) + { + _assetLoadingList.Remove(assetObjectKey); + return null; + } + + assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle,this); + m_AssetPool.Register(assetObject, true); + + _assetLoadingList.Remove(assetObjectKey); + + return handle.AssetObject as T; + } + + public async UniTask LoadGameObjectAsync(string location, Transform parent = null, CancellationToken cancellationToken = default, string packageName = "") + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + string assetObjectKey = GetCacheKey(location, packageName); + + await TryWaitingLoading(assetObjectKey); + + AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey); + if (assetObject != null) + { + await UniTask.Yield(); + return AssetsReference.Instantiate(assetObject.Target as GameObject, parent, this).gameObject; + } + + _assetLoadingList.Add(assetObjectKey); + + AssetHandle handle = GetHandleAsync(location, packageName: packageName); + + bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow(); + + if (cancelOrFailed) + { + _assetLoadingList.Remove(assetObjectKey); + return null; + } + + GameObject gameObject = AssetsReference.Instantiate(handle.AssetObject as GameObject, parent, this).gameObject; + + assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle,this); + m_AssetPool.Register(assetObject, true); + + _assetLoadingList.Remove(assetObjectKey); + + return gameObject; + } + + #endregion + + /// + /// 异步加载资源。 + /// + /// 资源的定位地址。 + /// 要加载资源的类型。 + /// 加载资源的优先级。 + /// 加载资源回调函数集。 + /// 用户自定义数据。 + /// 指定资源包的名称。不传使用默认资源包。 + public async void LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "") + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + if (loadAssetCallbacks == null) + { + throw new GameFrameworkException("Load asset callbacks is invalid."); + } + + string assetObjectKey = GetCacheKey(location, packageName); + + await TryWaitingLoading(assetObjectKey); + + float duration = Time.time; + + AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey); + if (assetObject != null) + { + await UniTask.Yield(); + loadAssetCallbacks.LoadAssetSuccessCallback(location, assetObject.Target, Time.time - duration, userData); + return; + } + + _assetLoadingList.Add(assetObjectKey); + + AssetInfo assetInfo = GetAssetInfo(location, packageName); + + if (!string.IsNullOrEmpty(assetInfo.Error)) + { + _assetLoadingList.Remove(assetObjectKey); + + string errorMessage = Utility.Text.Format("Can not load asset '{0}' because :'{1}'.", location, assetInfo.Error); + if (loadAssetCallbacks.LoadAssetFailureCallback != null) + { + loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotExist, errorMessage, userData); + return; + } + + throw new GameFrameworkException(errorMessage); + } + + AssetHandle handle = GetHandleAsync(location, assetType, packageName: packageName); + + if (loadAssetCallbacks.LoadAssetUpdateCallback != null) + { + InvokeProgress(location, handle, loadAssetCallbacks.LoadAssetUpdateCallback, userData).Forget(); + } + + await handle.ToUniTask(); + + if (handle.AssetObject == null || handle.Status == EOperationStatus.Failed) + { + _assetLoadingList.Remove(assetObjectKey); + + string errorMessage = Utility.Text.Format("Can not load asset '{0}'.", location); + if (loadAssetCallbacks.LoadAssetFailureCallback != null) + { + loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotReady, errorMessage, userData); + return; + } + + throw new GameFrameworkException(errorMessage); + } + else + { + assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle,this); + m_AssetPool.Register(assetObject, true); + + _assetLoadingList.Remove(assetObjectKey); + + if (loadAssetCallbacks.LoadAssetSuccessCallback != null) + { + duration = Time.time - duration; + + loadAssetCallbacks.LoadAssetSuccessCallback(location, handle.AssetObject, duration, userData); + } + } + } + + /// + /// 异步加载资源。 + /// + /// 资源的定位地址。 + /// 加载资源的优先级。 + /// 加载资源回调函数集。 + /// 用户自定义数据。 + /// 指定资源包的名称。不传使用默认资源包。 + public async void LoadAssetAsync(string location, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "") + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + if (loadAssetCallbacks == null) + { + throw new GameFrameworkException("Load asset callbacks is invalid."); + } + + string assetObjectKey = GetCacheKey(location, packageName); + + await TryWaitingLoading(assetObjectKey); + + float duration = Time.time; + + AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey); + if (assetObject != null) + { + await UniTask.Yield(); + loadAssetCallbacks.LoadAssetSuccessCallback(location, assetObject.Target, Time.time - duration, userData); + return; + } + + _assetLoadingList.Add(assetObjectKey); + + AssetInfo assetInfo = GetAssetInfo(location, packageName); + + if (!string.IsNullOrEmpty(assetInfo.Error)) + { + _assetLoadingList.Remove(assetObjectKey); + + string errorMessage = Utility.Text.Format("Can not load asset '{0}' because :'{1}'.", location, assetInfo.Error); + if (loadAssetCallbacks.LoadAssetFailureCallback != null) + { + loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotExist, errorMessage, userData); + return; + } + + throw new GameFrameworkException(errorMessage); + } + + AssetHandle handle = GetHandleAsync(location, assetInfo.AssetType, packageName: packageName); + + if (loadAssetCallbacks.LoadAssetUpdateCallback != null) + { + InvokeProgress(location, handle, loadAssetCallbacks.LoadAssetUpdateCallback, userData).Forget(); + } + + await handle.ToUniTask(); + + if (handle.AssetObject == null || handle.Status == EOperationStatus.Failed) + { + _assetLoadingList.Remove(assetObjectKey); + + string errorMessage = Utility.Text.Format("Can not load asset '{0}'.", location); + if (loadAssetCallbacks.LoadAssetFailureCallback != null) + { + loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotReady, errorMessage, userData); + return; + } + + throw new GameFrameworkException(errorMessage); + } + else + { + assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle,this); + m_AssetPool.Register(assetObject, true); + + _assetLoadingList.Remove(assetObjectKey); + + if (loadAssetCallbacks.LoadAssetSuccessCallback != null) + { + duration = Time.time - duration; + + loadAssetCallbacks.LoadAssetSuccessCallback(location, handle.AssetObject, duration, userData); + } + } + } + + private async UniTaskVoid InvokeProgress(string location, AssetHandle assetHandle, LoadAssetUpdateCallback loadAssetUpdateCallback, object userData) + { + if (string.IsNullOrEmpty(location)) + { + throw new GameFrameworkException("Asset name is invalid."); + } + + if (loadAssetUpdateCallback != null) + { + while (assetHandle is { IsValid: true, IsDone: false }) + { + await UniTask.Yield(); + + loadAssetUpdateCallback.Invoke(location, assetHandle.Progress, userData); + } + } + } + + private readonly TimeoutController _timeoutController = new TimeoutController(); + + private async UniTask TryWaitingLoading(string assetObjectKey) + { + if (_assetLoadingList.Contains(assetObjectKey)) + { + try + { + await UniTask.WaitUntil( + () => !_assetLoadingList.Contains(assetObjectKey), + cancellationToken:CancellationToken) +#if UNITY_EDITOR + .AttachExternalCancellation(_timeoutController.Timeout(TimeSpan.FromSeconds(60))); + _timeoutController.Reset(); +#else + ; +#endif + + } + catch (OperationCanceledException ex) + { + if (_timeoutController.IsTimeout()) + { + Log.Error($"LoadAssetAsync Waiting {assetObjectKey} timeout. reason:{ex.Message}"); + } + } + } + } + #endregion + + #region 资源回收 + public void UnloadUnusedAssets() + { + m_AssetPool.ReleaseAllUnused(); + foreach (var package in PackageMap.Values) + { + if (package is { InitializeStatus: EOperationStatus.Succeed }) + { + package.UnloadUnusedAssets(); + } + } + } + + public void ForceUnloadAllAssets() + { +#if UNITY_WEBGL + Log.Warning($"WebGL not support invoke {nameof(ForceUnloadAllAssets)}"); + return; +#else + + foreach (var package in PackageMap.Values) + { + if (package is { InitializeStatus: EOperationStatus.Succeed }) + { + package.ForceUnloadAllAssets(); + } + } +#endif + } + #endregion + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs.meta new file mode 100644 index 00000000..9f81db0e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e0141caf1ede44e9b8b7ff177803aa1f +timeCreated: 1678969240 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs new file mode 100644 index 00000000..03052dd1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs @@ -0,0 +1,713 @@ +using System; +using System.Threading; +using Cysharp.Threading.Tasks; +using UnityEngine; +using YooAsset; + +namespace TEngine +{ + /// + /// 资源组件。 + /// + [DisallowMultipleComponent] + public class ResourceModule : Module + { + #region Propreties + + private const int DefaultPriority = 0; + + private IResourceManager m_ResourceManager; + + private bool m_ForceUnloadUnusedAssets = false; + + private bool m_PreorderUnloadUnusedAssets = false; + + private bool m_PerformGCCollect = false; + + private AsyncOperation m_AsyncOperation = null; + + private float m_LastUnloadUnusedAssetsOperationElapseSeconds = 0f; + + [SerializeField] private float m_MinUnloadUnusedAssetsInterval = 60f; + + [SerializeField] private float m_MaxUnloadUnusedAssetsInterval = 300f; + + [SerializeField] private bool m_UseSystemUnloadUnusedAssets = true; + /// + /// 当前最新的包裹版本。 + /// + public string PackageVersion { set; get; } + + /// + /// 资源包名称。 + /// + [SerializeField] private string packageName = "DefaultPackage"; + + /// + /// 资源包名称。 + /// + public string PackageName + { + get => packageName; + set => packageName = value; + } + + /// + /// 资源系统运行模式。 + /// + [SerializeField] private EPlayMode playMode = EPlayMode.EditorSimulateMode; + + /// + /// 资源系统运行模式。 + /// 编辑器内优先使用。 + /// + public EPlayMode PlayMode + { + get + { +#if UNITY_EDITOR + //编辑器模式使用。 + return (EPlayMode)UnityEditor.EditorPrefs.GetInt("EditorPlayMode"); +#else + if (playMode == EPlayMode.EditorSimulateMode) + { + playMode = EPlayMode.OfflinePlayMode; + } + //运行时使用。 + return playMode; +#endif + } + set + { +#if UNITY_EDITOR + playMode = value; +#endif + } + } + + /// + /// 是否支持边玩边下载。 + /// + [SerializeField] private bool m_UpdatableWhilePlaying = false; + + /// + /// 是否支持边玩边下载。 + /// + public bool UpdatableWhilePlaying => m_UpdatableWhilePlaying; + + /// + /// 下载文件校验等级。 + /// + public EVerifyLevel VerifyLevel = EVerifyLevel.Middle; + + [SerializeField] private ReadWritePathType m_ReadWritePathType = ReadWritePathType.Unspecified; + + /// + /// 设置异步系统参数,每帧执行消耗的最大时间切片(单位:毫秒) + /// + [SerializeField] public long Milliseconds = 30; + + public int m_DownloadingMaxNum = 10; + + /// + /// 获取或设置同时最大下载数目。 + /// + public int DownloadingMaxNum + { + get => m_DownloadingMaxNum; + set => m_DownloadingMaxNum = value; + } + + public int m_FailedTryAgain = 3; + + public int FailedTryAgain + { + get => m_FailedTryAgain; + set => m_FailedTryAgain = value; + } + + /// + /// 获取当前资源适用的游戏版本号。 + /// + public string ApplicableGameVersion => m_ResourceManager.ApplicableGameVersion; + + /// + /// 获取当前内部资源版本号。 + /// + public int InternalResourceVersion => m_ResourceManager.InternalResourceVersion; + + /// + /// 获取资源读写路径类型。 + /// + public ReadWritePathType ReadWritePathType => m_ReadWritePathType; + + /// + /// 获取或设置无用资源释放的最小间隔时间,以秒为单位。 + /// + public float MinUnloadUnusedAssetsInterval + { + get => m_MinUnloadUnusedAssetsInterval; + set => m_MinUnloadUnusedAssetsInterval = value; + } + + /// + /// 获取或设置无用资源释放的最大间隔时间,以秒为单位。 + /// + public float MaxUnloadUnusedAssetsInterval + { + get => m_MaxUnloadUnusedAssetsInterval; + set => m_MaxUnloadUnusedAssetsInterval = value; + } + + /// + /// 使用系统释放无用资源策略。 + /// + public bool UseSystemUnloadUnusedAssets + { + get => m_UseSystemUnloadUnusedAssets; + set => m_UseSystemUnloadUnusedAssets = value; + } + + /// + /// 获取无用资源释放的等待时长,以秒为单位。 + /// + public float LastUnloadUnusedAssetsOperationElapseSeconds => m_LastUnloadUnusedAssetsOperationElapseSeconds; + + /// + /// 获取资源只读路径。 + /// + public string ReadOnlyPath => m_ResourceManager?.ReadOnlyPath; + + /// + /// 获取资源读写路径。 + /// + public string ReadWritePath => m_ResourceManager?.ReadWritePath; + + [SerializeField] + private float m_AssetAutoReleaseInterval = 60f; + + [SerializeField] + private int m_AssetCapacity = 64; + + [SerializeField] + private float m_AssetExpireTime = 60f; + + [SerializeField] + private int m_AssetPriority = 0; + + /// + /// 获取或设置资源对象池自动释放可释放对象的间隔秒数。 + /// + public float AssetAutoReleaseInterval + { + get + { + return m_ResourceManager.AssetAutoReleaseInterval; + } + set + { + m_ResourceManager.AssetAutoReleaseInterval = m_AssetAutoReleaseInterval = value; + } + } + + /// + /// 获取或设置资源对象池的容量。 + /// + public int AssetCapacity + { + get + { + return m_ResourceManager.AssetCapacity; + } + set + { + m_ResourceManager.AssetCapacity = m_AssetCapacity = value; + } + } + + /// + /// 获取或设置资源对象池对象过期秒数。 + /// + public float AssetExpireTime + { + get + { + return m_ResourceManager.AssetExpireTime; + } + set + { + m_ResourceManager.AssetExpireTime = m_AssetExpireTime = value; + } + } + + /// + /// 获取或设置资源对象池的优先级。 + /// + public int AssetPriority + { + get + { + return m_ResourceManager.AssetPriority; + } + set + { + m_ResourceManager.AssetPriority = m_AssetPriority = value; + } + } + #endregion + + private void Start() + { + RootModule rootModule = ModuleSystem.GetModule(); + if (rootModule == null) + { + Log.Fatal("Root module is invalid."); + return; + } + + m_ResourceManager = ModuleImpSystem.GetModule(); + if (m_ResourceManager == null) + { + Log.Fatal("Resource module is invalid."); + return; + } + + if (PlayMode == EPlayMode.EditorSimulateMode) + { + Log.Info("During this run, Game Framework will use editor resource files, which you should validate first."); +#if !UNITY_EDITOR + PlayMode = EPlayMode.OfflinePlayMode; +#endif + } + + m_ResourceManager.SetReadOnlyPath(Application.streamingAssetsPath); + if (m_ReadWritePathType == ReadWritePathType.TemporaryCache) + { + m_ResourceManager.SetReadWritePath(Application.temporaryCachePath); + } + else + { + if (m_ReadWritePathType == ReadWritePathType.Unspecified) + { + m_ReadWritePathType = ReadWritePathType.PersistentData; + } + + m_ResourceManager.SetReadWritePath(Application.persistentDataPath); + } + + m_ResourceManager.DefaultPackageName = PackageName; + m_ResourceManager.PlayMode = PlayMode; + m_ResourceManager.VerifyLevel = VerifyLevel; + m_ResourceManager.Milliseconds = Milliseconds; + m_ResourceManager.InstanceRoot = transform; + m_ResourceManager.HostServerURL = SettingsUtils.GetResDownLoadPath(); + m_ResourceManager.Initialize(); + m_ResourceManager.AssetAutoReleaseInterval = m_AssetAutoReleaseInterval; + m_ResourceManager.AssetCapacity = m_AssetCapacity; + m_ResourceManager.AssetExpireTime = m_AssetExpireTime; + m_ResourceManager.AssetPriority = m_AssetPriority; + Log.Info($"ResourceComponent Run Mode:{PlayMode}"); + } + + /// + /// 初始化操作。 + /// + /// + public async UniTask InitPackage(string packageName = "") + { + if (m_ResourceManager == null) + { + Log.Fatal("Resource component is invalid."); + return null; + } + + return await m_ResourceManager.InitPackage(string.IsNullOrEmpty(packageName) ? PackageName:packageName); + } + + #region 版本更新 + /// + /// 获取当前资源包版本。 + /// + /// 指定资源包的名称。不传使用默认资源包 + /// 资源包版本。 + public string GetPackageVersion(string customPackageName = "") + { + var package = string.IsNullOrEmpty(customPackageName) + ? YooAssets.GetPackage(PackageName) + : YooAssets.GetPackage(customPackageName); + if (package == null) + { + return string.Empty; + } + + return package.GetPackageVersion(); + } + + /// + /// 异步更新最新包的版本。 + /// + /// 请求URL是否需要带时间戳。 + /// 超时时间。 + /// 指定资源包的名称。不传使用默认资源包 + /// 请求远端包裹的最新版本操作句柄。 + public UpdatePackageVersionOperation UpdatePackageVersionAsync(bool appendTimeTicks = false, int timeout = 60, + string customPackageName = "") + { + var package = string.IsNullOrEmpty(customPackageName) + ? YooAssets.GetPackage(PackageName) + : YooAssets.GetPackage(customPackageName); + return package.UpdatePackageVersionAsync(appendTimeTicks, timeout); + } + + /// + /// 向网络端请求并更新清单 + /// + /// 更新的包裹版本 + /// 更新成功后自动保存版本号,作为下次初始化的版本。 + /// 超时时间(默认值:60秒) + /// 指定资源包的名称。不传使用默认资源包 + public UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, + bool autoSaveVersion = true, int timeout = 60, string customPackageName = "") + { + var package = string.IsNullOrEmpty(customPackageName) + ? YooAssets.GetPackage(PackageName) + : YooAssets.GetPackage(customPackageName); + return package.UpdatePackageManifestAsync(packageVersion, autoSaveVersion, timeout); + } + + /// + /// 资源下载器,用于下载当前资源版本所有的资源包文件。 + /// + public ResourceDownloaderOperation Downloader { get; set; } + + /// + /// 创建资源下载器,用于下载当前资源版本所有的资源包文件。 + /// + /// 指定资源包的名称。不传使用默认资源包 + public ResourceDownloaderOperation CreateResourceDownloader(string customPackageName = "") + { + if (string.IsNullOrEmpty(customPackageName)) + { + var package = YooAssets.GetPackage(PackageName); + Downloader = package.CreateResourceDownloader(DownloadingMaxNum, FailedTryAgain); + return Downloader; + } + else + { + var package = YooAssets.GetPackage(customPackageName); + Downloader = package.CreateResourceDownloader(DownloadingMaxNum, FailedTryAgain); + return Downloader; + } + } + + /// + /// 清理包裹未使用的缓存文件。 + /// + /// 指定资源包的名称。不传使用默认资源包 + public ClearUnusedCacheFilesOperation ClearUnusedCacheFilesAsync(string customPackageName = "") + { + var package = string.IsNullOrEmpty(customPackageName) + ? YooAssets.GetPackage(PackageName) + : YooAssets.GetPackage(customPackageName); + return package.ClearUnusedCacheFilesAsync(); + } + + /// + /// 清理沙盒路径。 + /// + /// 指定资源包的名称。不传使用默认资源包 + public void ClearSandbox(string customPackageName = "") + { + var package = string.IsNullOrEmpty(customPackageName) + ? YooAssets.GetPackage(PackageName) + : YooAssets.GetPackage(customPackageName); + package.ClearPackageSandbox(); + } + #endregion + + #region 获取资源 + /// + /// 检查资源是否存在。 + /// + /// 要检查资源的名称。 + /// 指定资源包的名称。不传使用默认资源包 + /// 检查资源是否存在的结果。 + public HasAssetResult HasAsset(string location, string customPackageName = "") + { + return m_ResourceManager.HasAsset(location, packageName: customPackageName); + } + + /// + /// 检查资源定位地址是否有效。 + /// + /// 资源的定位地址 + /// 指定资源包的名称。不传使用默认资源包 + public bool CheckLocationValid(string location, string customPackageName = "") + { + return m_ResourceManager.CheckLocationValid(location, packageName: customPackageName); + } + + /// + /// 获取资源信息列表。 + /// + /// 资源标签。 + /// 指定资源包的名称。不传使用默认资源包 + /// 资源信息列表。 + public AssetInfo[] GetAssetInfos(string resTag, string customPackageName = "") + { + return m_ResourceManager.GetAssetInfos(resTag, packageName: customPackageName); + } + + /// + /// 获取资源信息列表。 + /// + /// 资源标签列表。 + /// 指定资源包的名称。不传使用默认资源包 + /// 资源信息列表。 + public AssetInfo[] GetAssetInfos(string[] tags, string customPackageName = "") + { + return m_ResourceManager.GetAssetInfos(tags, packageName: customPackageName); + } + + /// + /// 获取资源信息。 + /// + /// 资源的定位地址。 + /// 指定资源包的名称。不传使用默认资源包 + /// 资源信息。 + public AssetInfo GetAssetInfo(string location, string customPackageName = "") + { + return m_ResourceManager.GetAssetInfo(location, packageName: customPackageName); + } + #endregion + + #region 加载资源 + + /// + /// 异步加载资源。 + /// + /// 资源的定位地址。 + /// 要加载资源的类型。 + /// 加载资源回调函数集。 + /// 用户自定义数据。 + /// 指定资源包的名称。不传使用默认资源包。 + public void LoadAssetAsync(string location, Type assetType, LoadAssetCallbacks loadAssetCallbacks, object userData = null, string packageName = "") + { + LoadAssetAsync(location, assetType, DefaultPriority, loadAssetCallbacks, userData, packageName); + } + + /// + /// 异步加载资源。 + /// + /// 资源的定位地址。 + /// 要加载资源的类型。 + /// 加载资源的优先级。 + /// 加载资源回调函数集。 + /// 用户自定义数据。 + /// 指定资源包的名称。不传使用默认资源包。 + public void LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "") + { + if (string.IsNullOrEmpty(location)) + { + Log.Error("Asset name is invalid."); + return; + } + + m_ResourceManager.LoadAssetAsync(location, assetType, priority, loadAssetCallbacks, userData, packageName); + } + + /// + /// 同步加载资源。 + /// + /// 资源的定位地址。 + /// 指定资源包的名称。不传使用默认资源包。 + /// 要加载资源的类型。 + /// 资源实例。 + public T LoadAsset(string location, string packageName = "") where T : UnityEngine.Object + { + if (string.IsNullOrEmpty(location)) + { + Log.Error("Asset name is invalid."); + return null; + } + + return m_ResourceManager.LoadAsset(location, packageName); + } + + /// + /// 同步加载游戏物体并实例化。 + /// + /// 资源的定位地址。 + /// 资源实例父节点。 + /// 指定资源包的名称。不传使用默认资源包。 + /// 资源实例。 + public GameObject LoadGameObject(string location, Transform parent = null, string packageName = "") + { + if (string.IsNullOrEmpty(location)) + { + Log.Error("Asset name is invalid."); + return null; + } + + return m_ResourceManager.LoadGameObject(location, parent, packageName); + } + + /// + /// 异步加载资源。 + /// + /// 资源的定位地址。 + /// 回调函数。 + /// 指定资源包的名称。不传使用默认资源包 + /// 要加载资源的类型。 + public void LoadAsset(string location, Action callback, string customPackageName = "") where T : UnityEngine.Object + { + if (string.IsNullOrEmpty(location)) + { + Log.Error("Asset name is invalid."); + return; + } + + m_ResourceManager.LoadAsset(location, callback, packageName: customPackageName); + } + + /// + /// 异步加载资源。 + /// + /// 资源定位地址。 + /// 取消操作Token。 + /// 指定资源包的名称。不传使用默认资源包。 + /// 要加载资源的类型。 + /// 异步资源实例。 + public async UniTask LoadAssetAsync(string location, CancellationToken cancellationToken = default, + string packageName = "") where T : UnityEngine.Object + { + if (string.IsNullOrEmpty(location)) + { + Log.Error("Asset name is invalid."); + return null; + } + + return await m_ResourceManager.LoadAssetAsync(location, cancellationToken, packageName); + } + + /// + /// 异步加载游戏物体并实例化。 + /// + /// 资源定位地址。 + /// 资源实例父节点。 + /// 取消操作Token。 + /// 指定资源包的名称。不传使用默认资源包。 + /// 异步游戏物体实例。 + public async UniTask LoadGameObjectAsync(string location, Transform parent = null, CancellationToken cancellationToken = default, + string packageName = "") + { + if (string.IsNullOrEmpty(location)) + { + Log.Error("Asset name is invalid."); + return null; + } + + return await m_ResourceManager.LoadGameObjectAsync(location, parent, cancellationToken, packageName); + } + + internal AssetHandle LoadAssetGetOperation(string location, + string packageName = "") where T : UnityEngine.Object + { + if (string.IsNullOrEmpty(packageName)) + { + return YooAssets.LoadAssetSync(location); + } + + var package = YooAssets.GetPackage(packageName); + return package.LoadAssetSync(location); + } + + internal AssetHandle LoadAssetAsyncHandle(string location, string packageName = "") where T : UnityEngine.Object + { + if (string.IsNullOrEmpty(packageName)) + { + return YooAssets.LoadAssetAsync(location); + } + + var package = YooAssets.GetPackage(packageName); + return package.LoadAssetAsync(location); + } + #endregion + + #region 卸载资源 + + /// + /// 卸载资源。 + /// + /// 要卸载的资源。 + public void UnloadAsset(object asset) + { + if (asset == null) + { + return; + } + m_ResourceManager.UnloadAsset(asset); + } + + #endregion + + #region 释放资源 + + /// + /// 强制执行释放未被使用的资源。 + /// + /// 是否使用垃圾回收。 + public void ForceUnloadUnusedAssets(bool performGCCollect) + { + m_ForceUnloadUnusedAssets = true; + if (performGCCollect) + { + m_PerformGCCollect = true; + } + } + + /// + /// 预订执行释放未被使用的资源。 + /// + /// 是否使用垃圾回收。 + public void UnloadUnusedAssets(bool performGCCollect) + { + m_PreorderUnloadUnusedAssets = true; + if (performGCCollect) + { + m_PerformGCCollect = true; + } + } + + private void Update() + { + m_LastUnloadUnusedAssetsOperationElapseSeconds += Time.unscaledDeltaTime; + if (m_AsyncOperation == null && (m_ForceUnloadUnusedAssets || m_LastUnloadUnusedAssetsOperationElapseSeconds >= m_MaxUnloadUnusedAssetsInterval || + m_PreorderUnloadUnusedAssets && m_LastUnloadUnusedAssetsOperationElapseSeconds >= m_MinUnloadUnusedAssetsInterval)) + { + Log.Info("Unload unused assets..."); + m_ForceUnloadUnusedAssets = false; + m_PreorderUnloadUnusedAssets = false; + m_LastUnloadUnusedAssetsOperationElapseSeconds = 0f; + m_AsyncOperation = Resources.UnloadUnusedAssets(); + if (m_UseSystemUnloadUnusedAssets) + { + m_ResourceManager.UnloadUnusedAssets(); + } + } + + if (m_AsyncOperation is { isDone: true }) + { + m_AsyncOperation = null; + if (m_PerformGCCollect) + { + Log.Info("GC.Collect..."); + m_PerformGCCollect = false; + GC.Collect(); + } + } + } + + #endregion + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs.meta new file mode 100644 index 00000000..7e235a40 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/ResourceModule/ResourceModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da56eb8e282380a478681f0d4445502d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/RootModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/RootModule.cs new file mode 100644 index 00000000..77388fdc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/RootModule.cs @@ -0,0 +1,316 @@ +using System; +using UnityEngine; + +namespace TEngine +{ + /// + /// 基础模块。 + /// + [DisallowMultipleComponent] + public sealed class RootModule : Module + { + private const int DefaultDpi = 96; // default windows dpi + + private float m_GameSpeedBeforePause = 1f; + + [SerializeField] + private Language m_EditorLanguage = Language.Unspecified; + + [SerializeField] + private string m_TextHelperTypeName = "TEngine.DefaultTextHelper"; + + [SerializeField] + private string m_VersionHelperTypeName = "TEngine.DefaultVersionHelper"; + + [SerializeField] + private string m_LogHelperTypeName = "TEngine.DefaultLogHelper"; + + [SerializeField] + private string m_JsonHelperTypeName = "TEngine.DefaultJsonHelper"; + + [SerializeField] + private int m_FrameRate = 120; + + [SerializeField] + private float m_GameSpeed = 1f; + + [SerializeField] + private bool m_RunInBackground = true; + + [SerializeField] + private bool m_NeverSleep = true; + + /// + /// 获取或设置编辑器语言(仅编辑器内有效)。 + /// + public Language EditorLanguage + { + get => m_EditorLanguage; + set => m_EditorLanguage = value; + } + + /// + /// 获取或设置游戏帧率。 + /// + public int FrameRate + { + get => m_FrameRate; + set => Application.targetFrameRate = m_FrameRate = value; + } + + /// + /// 获取或设置游戏速度。 + /// + public float GameSpeed + { + get => m_GameSpeed; + set => Time.timeScale = m_GameSpeed = value >= 0f ? value : 0f; + } + + /// + /// 获取游戏是否暂停。 + /// + public bool IsGamePaused => m_GameSpeed <= 0f; + + /// + /// 获取是否正常游戏速度。 + /// + public bool IsNormalGameSpeed => Math.Abs(m_GameSpeed - 1f) < 0.01f; + + /// + /// 获取或设置是否允许后台运行。 + /// + public bool RunInBackground + { + get => m_RunInBackground; + set => Application.runInBackground = m_RunInBackground = value; + } + + /// + /// 获取或设置是否禁止休眠。 + /// + public bool NeverSleep + { + get => m_NeverSleep; + set + { + m_NeverSleep = value; + Screen.sleepTimeout = value ? SleepTimeout.NeverSleep : SleepTimeout.SystemSetting; + } + } + + /// + /// 游戏框架模块初始化。 + /// + protected override void Awake() + { + base.Awake(); + + InitTextHelper(); + InitVersionHelper(); + InitLogHelper(); + Log.Info("TEngine Version: {0}", Version.GameFrameworkVersion); + Log.Info("Game Version: {0} ({1})", Version.GameVersion, Version.InternalGameVersion); + Log.Info("Unity Version: {0}", Application.unityVersion); + + InitJsonHelper(); + + Utility.Converter.ScreenDpi = Screen.dpi; + if (Utility.Converter.ScreenDpi <= 0) + { + Utility.Converter.ScreenDpi = DefaultDpi; + } + + Application.targetFrameRate = m_FrameRate; + Time.timeScale = m_GameSpeed; + Application.runInBackground = m_RunInBackground; + Screen.sleepTimeout = m_NeverSleep ? SleepTimeout.NeverSleep : SleepTimeout.SystemSetting; + + Application.lowMemory += OnLowMemory; + GameTime.StartFrame(); + } + + private void Update() + { + GameTime.StartFrame(); + ModuleImpSystem.Update(GameTime.deltaTime, GameTime.unscaledDeltaTime); + } + + private void FixedUpdate() + { + GameTime.StartFrame(); + } + + private void LateUpdate() + { + GameTime.StartFrame(); + } + + private void OnApplicationQuit() + { + Application.lowMemory -= OnLowMemory; + StopAllCoroutines(); + } + + private void OnDestroy() + { +#if !UNITY_EDITOR + ModuleImpSystem.Shutdown(); +#endif + } + + /// + /// 暂停游戏。 + /// + public void PauseGame() + { + if (IsGamePaused) + { + return; + } + + m_GameSpeedBeforePause = GameSpeed; + GameSpeed = 0f; + } + + /// + /// 恢复游戏。 + /// + public void ResumeGame() + { + if (!IsGamePaused) + { + return; + } + + GameSpeed = m_GameSpeedBeforePause; + } + + /// + /// 重置为正常游戏速度。 + /// + public void ResetNormalGameSpeed() + { + if (IsNormalGameSpeed) + { + return; + } + + GameSpeed = 1f; + } + + internal void Shutdown() + { + Destroy(gameObject); + } + + private void InitTextHelper() + { + if (string.IsNullOrEmpty(m_TextHelperTypeName)) + { + return; + } + + Type textHelperType = Utility.Assembly.GetType(m_TextHelperTypeName); + if (textHelperType == null) + { + Log.Error("Can not find text helper type '{0}'.", m_TextHelperTypeName); + return; + } + + Utility.Text.ITextHelper textHelper = (Utility.Text.ITextHelper)Activator.CreateInstance(textHelperType); + if (textHelper == null) + { + Log.Error("Can not create text helper instance '{0}'.", m_TextHelperTypeName); + return; + } + + Utility.Text.SetTextHelper(textHelper); + } + + private void InitVersionHelper() + { + if (string.IsNullOrEmpty(m_VersionHelperTypeName)) + { + return; + } + + Type versionHelperType = Utility.Assembly.GetType(m_VersionHelperTypeName); + if (versionHelperType == null) + { + throw new GameFrameworkException(Utility.Text.Format("Can not find version helper type '{0}'.", m_VersionHelperTypeName)); + } + + Version.IVersionHelper versionHelper = (Version.IVersionHelper)Activator.CreateInstance(versionHelperType); + if (versionHelper == null) + { + throw new GameFrameworkException(Utility.Text.Format("Can not create version helper instance '{0}'.", m_VersionHelperTypeName)); + } + + Version.SetVersionHelper(versionHelper); + } + + private void InitLogHelper() + { + if (string.IsNullOrEmpty(m_LogHelperTypeName)) + { + return; + } + + Type logHelperType = Utility.Assembly.GetType(m_LogHelperTypeName); + if (logHelperType == null) + { + throw new GameFrameworkException(Utility.Text.Format("Can not find log helper type '{0}'.", m_LogHelperTypeName)); + } + + GameFrameworkLog.ILogHelper logHelper = (GameFrameworkLog.ILogHelper)Activator.CreateInstance(logHelperType); + if (logHelper == null) + { + throw new GameFrameworkException(Utility.Text.Format("Can not create log helper instance '{0}'.", m_LogHelperTypeName)); + } + + GameFrameworkLog.SetLogHelper(logHelper); + } + + private void InitJsonHelper() + { + if (string.IsNullOrEmpty(m_JsonHelperTypeName)) + { + return; + } + + Type jsonHelperType = Utility.Assembly.GetType(m_JsonHelperTypeName); + if (jsonHelperType == null) + { + Log.Error("Can not find JSON helper type '{0}'.", m_JsonHelperTypeName); + return; + } + + Utility.Json.IJsonHelper jsonHelper = (Utility.Json.IJsonHelper)Activator.CreateInstance(jsonHelperType); + if (jsonHelper == null) + { + Log.Error("Can not create JSON helper instance '{0}'.", m_JsonHelperTypeName); + return; + } + + Utility.Json.SetJsonHelper(jsonHelper); + } + + private void OnLowMemory() + { + Log.Warning("Low memory reported..."); + + ObjectPoolModule objectPoolModule = ModuleSystem.GetModule(); + if (objectPoolModule != null) + { + objectPoolModule.ReleaseAllUnused(); + } + + ResourceModule resourceModule = ModuleSystem.GetModule(); + if (resourceModule != null) + { + resourceModule.ForceUnloadUnusedAssets(true); + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/RootModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/RootModule.cs.meta new file mode 100644 index 00000000..78a2f867 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/RootModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fdf67b39cb924343bb79dd202dc5dd2d +timeCreated: 1694840225 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule.meta new file mode 100644 index 00000000..a02999fe --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2c67061fae264c5a861a5bdb257128a2 +timeCreated: 1697614501 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/ISceneModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/ISceneModule.cs new file mode 100644 index 00000000..8191f986 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/ISceneModule.cs @@ -0,0 +1,67 @@ +using System; +using UnityEngine.SceneManagement; +using YooAsset; + +namespace TEngine +{ + public interface ISceneModule + { + /// + /// 当前主场景名称。 + /// + public string CurrentMainSceneName { get; } + + /// + /// 加载场景。 + /// + /// 场景的定位地址 + /// 场景加载模式 + /// 加载完毕时是否主动挂起 + /// 优先级 + /// 加载回调。 + /// 加载主场景是否回收垃圾。 + /// 加载进度回调。 + public SceneHandle LoadScene(string location, + LoadSceneMode sceneMode = LoadSceneMode.Single, + bool suspendLoad = false, + int priority = 100, + Action callBack = null, + bool gcCollect = true, + Action progressCallBack = null); + + /// + /// 激活场景(当同时存在多个场景时用于切换激活场景)。 + /// + /// 场景资源定位地址。 + /// 是否操作成功。 + public bool ActivateScene(string location); + + /// + /// 解除场景加载挂起操作。 + /// + /// 场景资源定位地址。 + /// 是否操作成功。 + public bool UnSuspend(string location); + + /// + /// 是否为主场景。 + /// + /// 场景资源定位地址。 + /// 是否主场景。 + public bool IsMainScene(string location); + + /// + /// 异步卸载子场景。 + /// + /// 场景资源定位地址。 + /// 场景卸载异步操作类。 + public UnloadSceneOperation UnloadAsync(string location); + + /// + /// 是否包含场景。 + /// + /// 场景资源定位地址。 + /// 是否包含场景。 + public bool IsContainScene(string location); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/ISceneModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/ISceneModule.cs.meta new file mode 100644 index 00000000..df6f62c1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/ISceneModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f0b4f7a8db8740098bcb15904587e077 +timeCreated: 1697614518 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModule.cs new file mode 100644 index 00000000..351d722d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModule.cs @@ -0,0 +1,117 @@ +using System; +using UnityEngine.SceneManagement; +using YooAsset; + +namespace TEngine +{ + /// + /// 场景管理模块。 + /// + public sealed class SceneModule: Module + { + private ISceneModule _sceneModule; + + private void Start() + { + RootModule baseComponent = ModuleSystem.GetModule(); + if (baseComponent == null) + { + Log.Fatal("Root module is invalid."); + return; + } + + _sceneModule = ModuleImpSystem.GetModule(); + if (_sceneModule == null) + { + Log.Fatal("SceneModule is invalid."); + return; + } + } + + /// + /// 当前主场景名称。 + /// + public string CurrentMainSceneName => _sceneModule.CurrentMainSceneName; + + /// + /// 加载场景。 + /// + /// 场景的定位地址 + /// 场景加载模式 + /// 加载完毕时是否主动挂起 + /// 优先级 + /// 加载回调。 + /// 加载主场景是否回收垃圾。 + /// 加载进度回调。 + public SceneHandle LoadScene(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, int priority = 100, + Action callBack = null, bool gcCollect = true, Action progressCallBack = null) + { + return _sceneModule.LoadScene(location, sceneMode, suspendLoad, priority, callBack, gcCollect, progressCallBack); + } + + /// + /// 加载子场景。 + /// + /// 场景的定位地址 + /// 加载完毕时是否主动挂起 + /// 优先级 + /// 加载回调。 + /// 加载主场景是否回收垃圾。 + /// 加载进度回调。 + public SceneHandle LoadSubScene(string location, bool suspendLoad = false, int priority = 100, + Action callBack = null, bool gcCollect = true, Action progressCallBack = null) + { + return _sceneModule.LoadScene(location, LoadSceneMode.Additive, suspendLoad, priority, callBack, gcCollect, progressCallBack); + } + + /// + /// 激活场景(当同时存在多个场景时用于切换激活场景)。 + /// + /// 场景资源定位地址。 + /// 是否操作成功。 + public bool ActivateScene(string location) + { + return _sceneModule.ActivateScene(location); + } + + /// + /// 解除场景加载挂起操作。 + /// + /// 场景资源定位地址。 + /// 是否操作成功。 + public bool UnSuspend(string location) + { + return _sceneModule.UnSuspend(location); + } + + /// + /// 是否为主场景。 + /// + /// 场景资源定位地址。 + /// 是否主场景。 + public bool IsMainScene(string location) + { + return _sceneModule.IsMainScene(location); + } + + /// + /// 异步卸载子场景。 + /// + /// 场景资源定位地址。 + /// 场景卸载异步操作类。 + public UnloadSceneOperation UnloadAsync(string location) + { + return _sceneModule.UnloadAsync(location); + } + + /// + /// 是否包含场景。 + /// + /// 场景资源定位地址。 + /// 是否包含场景。 + public bool IsContainScene(string location) + { + return _sceneModule.IsContainScene(location); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModule.cs.meta new file mode 100644 index 00000000..b4365d7b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 86342cc6845c403da1a3f6db507fae9d +timeCreated: 1697616931 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModuleImp.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModuleImp.cs new file mode 100644 index 00000000..a02e42f5 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModuleImp.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using Cysharp.Threading.Tasks; +using UnityEngine.SceneManagement; +using YooAsset; + +namespace TEngine +{ + /// + /// 场景管理器。 + /// + internal class SceneModuleImp : ModuleImp, ISceneModule + { + private string _currentMainSceneName = string.Empty; + + private SceneHandle _currentMainScene; + + private readonly Dictionary _subScenes = new Dictionary(); + + /// + /// 当前主场景名称。 + /// + public string CurrentMainSceneName => _currentMainSceneName; + + internal override void Shutdown() + { + var iter = _subScenes.Values.GetEnumerator(); + while (iter.MoveNext()) + { + SceneHandle subScene = iter.Current; + if (subScene != null) + { + subScene.UnloadAsync(); + } + } + iter.Dispose(); + _subScenes.Clear(); + _currentMainSceneName = string.Empty; + } + + /// + /// 加载场景。 + /// + /// 场景的定位地址R + /// 场景加载模式 + /// 加载完毕时是否主动挂起 + /// 优先级 + /// 加载回调。 + /// 加载主场景是否回收垃圾。 + /// 加载进度回调。 + public SceneHandle LoadScene(string location, + LoadSceneMode sceneMode = LoadSceneMode.Single, + bool suspendLoad = false, + int priority = 100, + Action callBack = null, + bool gcCollect = true, + Action progressCallBack = null) + { + if (sceneMode == LoadSceneMode.Additive) + { + if (_subScenes.TryGetValue(location, out SceneHandle subScene)) + { + Log.Warning($"Could not load subScene while already loaded. Scene: {location}"); + return subScene; + } + subScene = YooAssets.LoadSceneAsync(location, sceneMode, suspendLoad, (uint)priority); + + if (callBack != null) + { + subScene.Completed += callBack; + } + + if (progressCallBack != null) + { + InvokeProgress(subScene, progressCallBack).Forget(); + } + _subScenes.Add(location, subScene); + + return subScene; + } + else + { + if (_currentMainScene is { IsDone: false }) + { + Log.Warning($"Could not load MainScene while loading. CurrentMainScene: {_currentMainSceneName}."); + return null; + } + + _currentMainSceneName = location; + + _currentMainScene = YooAssets.LoadSceneAsync(location, sceneMode, suspendLoad, (uint)priority); + + if (callBack != null) + { + _currentMainScene.Completed += callBack; + } + + if (progressCallBack != null) + { + InvokeProgress(_currentMainScene, progressCallBack).Forget(); + } + + GameModule.Resource.ForceUnloadUnusedAssets(gcCollect); + + return _currentMainScene; + } + } + + private async UniTaskVoid InvokeProgress(SceneHandle SceneHandle,Action progress) + { + if (SceneHandle == null) + { + return; + } + + while (!SceneHandle.IsDone) + { + await UniTask.Yield(); + + progress?.Invoke(SceneHandle.Progress); + } + } + + /// + /// 激活场景(当同时存在多个场景时用于切换激活场景)。 + /// + /// 场景资源定位地址。 + /// 是否操作成功。 + public bool ActivateScene(string location) + { + if (_currentMainSceneName.Equals(location)) + { + if (_currentMainScene != null) + { + return _currentMainScene.ActivateScene(); + } + return false; + } + _subScenes.TryGetValue(location, out SceneHandle subScene); + if (subScene != null) + { + return subScene.ActivateScene(); + } + Log.Warning($"IsMainScene invalid location:{location}"); + return false; + } + + /// + /// 解除场景加载挂起操作。 + /// + /// 场景资源定位地址。 + /// 是否操作成功。 + public bool UnSuspend(string location) + { + if (_currentMainSceneName.Equals(location)) + { + if (_currentMainScene != null) + { + return _currentMainScene.UnSuspend(); + } + return false; + } + _subScenes.TryGetValue(location, out SceneHandle subScene); + if (subScene != null) + { + return subScene.UnSuspend(); + } + Log.Warning($"IsMainScene invalid location:{location}"); + return false; + } + + /// + /// 是否为主场景。 + /// + /// 场景资源定位地址。 + /// 是否主场景。 + public bool IsMainScene(string location) + { + if (_currentMainSceneName.Equals(location)) + { + if (_currentMainScene != null) + { + return _currentMainScene.IsMainScene(); + } + return true; + } + _subScenes.TryGetValue(location, out SceneHandle subScene); + if (subScene != null) + { + return subScene.IsMainScene(); + } + Log.Warning($"IsMainScene invalid location:{location}"); + return false; + } + + /// + /// 异步卸载子场景。 + /// + /// 场景资源定位地址。 + /// 场景卸载异步操作类。 + public UnloadSceneOperation UnloadAsync(string location) + { + _subScenes.TryGetValue(location, out SceneHandle subScene); + if (subScene != null) + { + if (subScene.SceneObject == default) + { + Log.Error($"Could not unload Scene while not loaded. Scene: {location}"); + return null; + } + _subScenes.Remove(location); + return subScene.UnloadAsync(); + } + Log.Warning($"UnloadAsync invalid location:{location}"); + return null; + } + + /// + /// 是否包含场景。 + /// + /// 场景资源定位地址。 + /// 是否包含场景。 + public bool IsContainScene(string location) + { + if (_currentMainSceneName.Equals(location)) + { + return true; + } + return _subScenes.TryGetValue(location, out var _); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModuleImp.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModuleImp.cs.meta new file mode 100644 index 00000000..3b59d24a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SceneModule/SceneModuleImp.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 67fca5b8a8634d7b9e62c640a4049d02 +timeCreated: 1697614527 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule.meta new file mode 100644 index 00000000..bce40bd3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a1f7d48dfbb80274eb5f64dcbe153c49 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSetting.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSetting.cs new file mode 100644 index 00000000..4f735fb0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSetting.cs @@ -0,0 +1,305 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace TEngine +{ + /// + /// 默认游戏配置。 + /// + public sealed class DefaultSetting + { + private readonly SortedDictionary m_Settings = new SortedDictionary(StringComparer.Ordinal); + + /// + /// 初始化本地版本资源列表的新实例。 + /// + public DefaultSetting() + { + } + + /// + /// 获取游戏配置项数量。 + /// + public int Count + { + get + { + return m_Settings.Count; + } + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public string[] GetAllSettingNames() + { + int index = 0; + string[] allSettingNames = new string[m_Settings.Count]; + foreach (KeyValuePair setting in m_Settings) + { + allSettingNames[index++] = setting.Key; + } + + return allSettingNames; + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public void GetAllSettingNames(List results) + { + if (results == null) + { + throw new GameFrameworkException("Results is invalid."); + } + + results.Clear(); + foreach (KeyValuePair setting in m_Settings) + { + results.Add(setting.Key); + } + } + + /// + /// 检查是否存在指定游戏配置项。 + /// + /// 要检查游戏配置项的名称。 + /// 指定的游戏配置项是否存在。 + public bool HasSetting(string settingName) + { + return m_Settings.ContainsKey(settingName); + } + + /// + /// 移除指定游戏配置项。 + /// + /// 要移除游戏配置项的名称。 + /// 是否移除指定游戏配置项成功。 + public bool RemoveSetting(string settingName) + { + return m_Settings.Remove(settingName); + } + + /// + /// 清空所有游戏配置项。 + /// + public void RemoveAllSettings() + { + m_Settings.Clear(); + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的布尔值。 + public bool GetBool(string settingName) + { + string value = null; + if (!m_Settings.TryGetValue(settingName, out value)) + { + Log.Warning("Setting '{0}' is not exist.", settingName); + return false; + } + + return int.Parse(value) != 0; + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的布尔值。 + public bool GetBool(string settingName, bool defaultValue) + { + string value = null; + if (!m_Settings.TryGetValue(settingName, out value)) + { + return defaultValue; + } + + return int.Parse(value) != 0; + } + + /// + /// 向指定游戏配置项写入布尔值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的布尔值。 + public void SetBool(string settingName, bool value) + { + m_Settings[settingName] = value ? "1" : "0"; + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的整数值。 + public int GetInt(string settingName) + { + string value = null; + if (!m_Settings.TryGetValue(settingName, out value)) + { + Log.Warning("Setting '{0}' is not exist.", settingName); + return 0; + } + + return int.Parse(value); + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的整数值。 + public int GetInt(string settingName, int defaultValue) + { + string value = null; + if (!m_Settings.TryGetValue(settingName, out value)) + { + return defaultValue; + } + + return int.Parse(value); + } + + /// + /// 向指定游戏配置项写入整数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的整数值。 + public void SetInt(string settingName, int value) + { + m_Settings[settingName] = value.ToString(); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的浮点数值。 + public float GetFloat(string settingName) + { + string value = null; + if (!m_Settings.TryGetValue(settingName, out value)) + { + Log.Warning("Setting '{0}' is not exist.", settingName); + return 0f; + } + + return float.Parse(value); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的浮点数值。 + public float GetFloat(string settingName, float defaultValue) + { + string value = null; + if (!m_Settings.TryGetValue(settingName, out value)) + { + return defaultValue; + } + + return float.Parse(value); + } + + /// + /// 向指定游戏配置项写入浮点数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的浮点数值。 + public void SetFloat(string settingName, float value) + { + m_Settings[settingName] = value.ToString(); + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的字符串值。 + public string GetString(string settingName) + { + string value = null; + if (!m_Settings.TryGetValue(settingName, out value)) + { + Log.Warning("Setting '{0}' is not exist.", settingName); + return null; + } + + return value; + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的字符串值。 + public string GetString(string settingName, string defaultValue) + { + string value = null; + if (!m_Settings.TryGetValue(settingName, out value)) + { + return defaultValue; + } + + return value; + } + + /// + /// 向指定游戏配置项写入字符串值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的字符串值。 + public void SetString(string settingName, string value) + { + m_Settings[settingName] = value; + } + + /// + /// 序列化数据。 + /// + /// 目标流。 + public void Serialize(Stream stream) + { + using (BinaryWriter binaryWriter = new BinaryWriter(stream, Encoding.UTF8)) + { + binaryWriter.Write7BitEncodedInt32(m_Settings.Count); + foreach (KeyValuePair setting in m_Settings) + { + binaryWriter.Write(setting.Key); + binaryWriter.Write(setting.Value); + } + } + } + + /// + /// 反序列化数据。 + /// + /// 指定流。 + public void Deserialize(Stream stream) + { + m_Settings.Clear(); + using (BinaryReader binaryReader = new BinaryReader(stream, Encoding.UTF8)) + { + int settingCount = binaryReader.Read7BitEncodedInt32(); + for (int i = 0; i < settingCount; i++) + { + m_Settings.Add(binaryReader.ReadString(), binaryReader.ReadString()); + } + } + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSetting.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSetting.cs.meta new file mode 100644 index 00000000..cd0b3863 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSetting.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: eaa6327836444075b03413516af7166c +timeCreated: 1680490094 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingHelper.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingHelper.cs new file mode 100644 index 00000000..59c07247 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingHelper.cs @@ -0,0 +1,355 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +namespace TEngine +{ + /// + /// 默认游戏配置辅助器。 + /// + public class DefaultSettingHelper : SettingHelperBase + { + private const string SettingFileName = "TEngineSetting.dat"; + + private string m_FilePath = null; + private DefaultSetting m_Settings = null; + private DefaultSettingSerializer m_Serializer = null; + + /// + /// 获取游戏配置项数量。 + /// + public override int Count => m_Settings != null ? m_Settings.Count : 0; + + /// + /// 获取游戏配置存储文件路径。 + /// + public string FilePath => m_FilePath; + + /// + /// 获取游戏配置。 + /// + public DefaultSetting Setting => m_Settings; + + /// + /// 获取游戏配置序列化器。 + /// + public DefaultSettingSerializer Serializer => m_Serializer; + + /// + /// 加载游戏配置。 + /// + /// 是否加载游戏配置成功。 + public override bool Load() + { + try + { + if (!File.Exists(m_FilePath)) + { + return true; + } + + using (FileStream fileStream = new FileStream(m_FilePath, FileMode.Open, FileAccess.Read)) + { + m_Serializer.Deserialize(fileStream); + return true; + } + } + catch (Exception exception) + { + Log.Warning("Load settings failure with exception '{0}'.", exception); + return false; + } + } + + /// + /// 保存游戏配置。 + /// + /// 是否保存游戏配置成功。 + public override bool Save() + { + try + { + using (FileStream fileStream = new FileStream(m_FilePath, FileMode.Create, FileAccess.Write)) + { + return m_Serializer.Serialize(fileStream, m_Settings); + } + } + catch (Exception exception) + { + Log.Warning("Save settings failure with exception '{0}'.", exception); + return false; + } + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public override string[] GetAllSettingNames() + { + return m_Settings.GetAllSettingNames(); + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public override void GetAllSettingNames(List results) + { + m_Settings.GetAllSettingNames(results); + } + + /// + /// 检查是否存在指定游戏配置项。 + /// + /// 要检查游戏配置项的名称。 + /// 指定的游戏配置项是否存在。 + public override bool HasSetting(string settingName) + { + return m_Settings.HasSetting(settingName); + } + + /// + /// 移除指定游戏配置项。 + /// + /// 要移除游戏配置项的名称。 + /// 是否移除指定游戏配置项成功。 + public override bool RemoveSetting(string settingName) + { + return m_Settings.RemoveSetting(settingName); + } + + /// + /// 清空所有游戏配置项。 + /// + public override void RemoveAllSettings() + { + m_Settings.RemoveAllSettings(); + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的布尔值。 + public override bool GetBool(string settingName) + { + return m_Settings.GetBool(settingName); + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的布尔值。 + public override bool GetBool(string settingName, bool defaultValue) + { + return m_Settings.GetBool(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入布尔值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的布尔值。 + public override void SetBool(string settingName, bool value) + { + m_Settings.SetBool(settingName, value); + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的整数值。 + public override int GetInt(string settingName) + { + return m_Settings.GetInt(settingName); + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的整数值。 + public override int GetInt(string settingName, int defaultValue) + { + return m_Settings.GetInt(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入整数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的整数值。 + public override void SetInt(string settingName, int value) + { + m_Settings.SetInt(settingName, value); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的浮点数值。 + public override float GetFloat(string settingName) + { + return m_Settings.GetFloat(settingName); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的浮点数值。 + public override float GetFloat(string settingName, float defaultValue) + { + return m_Settings.GetFloat(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入浮点数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的浮点数值。 + public override void SetFloat(string settingName, float value) + { + m_Settings.SetFloat(settingName, value); + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的字符串值。 + public override string GetString(string settingName) + { + return m_Settings.GetString(settingName); + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的字符串值。 + public override string GetString(string settingName, string defaultValue) + { + return m_Settings.GetString(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入字符串值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的字符串值。 + public override void SetString(string settingName, string value) + { + m_Settings.SetString(settingName, value); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public override T GetObject(string settingName) + { + return Utility.Json.ToObject(GetString(settingName)); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public override object GetObject(Type objectType, string settingName) + { + return Utility.Json.ToObject(objectType, GetString(settingName)); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public override T GetObject(string settingName, T defaultObj) + { + string json = GetString(settingName, null); + if (json == null) + { + return defaultObj; + } + + return Utility.Json.ToObject(json); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public override object GetObject(Type objectType, string settingName, object defaultObj) + { + string json = GetString(settingName, null); + if (json == null) + { + return defaultObj; + } + + return Utility.Json.ToObject(objectType, json); + } + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入对象的类型。 + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public override void SetObject(string settingName, T obj) + { + SetString(settingName, Utility.Json.ToJson(obj)); + } + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public override void SetObject(string settingName, object obj) + { + SetString(settingName, Utility.Json.ToJson(obj)); + } + + private void Awake() + { + m_FilePath = Utility.Path.GetRegularPath(Path.Combine(Application.persistentDataPath, SettingFileName)); + m_Settings = new DefaultSetting(); + m_Serializer = new DefaultSettingSerializer(); + m_Serializer.RegisterSerializeCallback(0, SerializeDefaultSettingCallback); + m_Serializer.RegisterDeserializeCallback(0, DeserializeDefaultSettingCallback); + } + + private bool SerializeDefaultSettingCallback(Stream stream, DefaultSetting defaultSetting) + { + m_Settings.Serialize(stream); + return true; + } + + private DefaultSetting DeserializeDefaultSettingCallback(Stream stream) + { + m_Settings.Deserialize(stream); + return m_Settings; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingHelper.cs.meta new file mode 100644 index 00000000..8b37345e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dd3adf671d5e4b4c9653e7f07d6d0792 +timeCreated: 1680490094 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingSerializer.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingSerializer.cs new file mode 100644 index 00000000..3a18265e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingSerializer.cs @@ -0,0 +1,26 @@ +namespace TEngine +{ + /// + /// 默认游戏配置序列化器。 + /// + public sealed class DefaultSettingSerializer : GameFrameworkSerializer + { + private static readonly byte[] Header = new byte[] { (byte)'T', (byte)'E', (byte)'S' }; + + /// + /// 初始化默认游戏配置序列化器的新实例。 + /// + public DefaultSettingSerializer() + { + } + + /// + /// 获取默认游戏配置头标识。 + /// + /// 默认游戏配置头标识。 + protected override byte[] GetHeader() + { + return Header; + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingSerializer.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingSerializer.cs.meta new file mode 100644 index 00000000..484d24ef --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/DefaultSettingSerializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1688211d367a4e3da941dc3c33ea37f2 +timeCreated: 1680490094 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingHelper.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingHelper.cs new file mode 100644 index 00000000..8611955d --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingHelper.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 游戏配置辅助器接口。 + /// + public interface ISettingHelper + { + /// + /// 获取游戏配置项数量。 + /// + int Count + { + get; + } + + /// + /// 加载游戏配置。 + /// + /// 是否加载游戏配置成功。 + bool Load(); + + /// + /// 保存游戏配置。 + /// + /// 是否保存游戏配置成功。 + bool Save(); + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + string[] GetAllSettingNames(); + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + void GetAllSettingNames(List results); + + /// + /// 检查是否存在指定游戏配置项。 + /// + /// 要检查游戏配置项的名称。 + /// 指定的游戏配置项是否存在。 + bool HasSetting(string settingName); + + /// + /// 移除指定游戏配置项。 + /// + /// 要移除游戏配置项的名称。 + /// 是否移除指定游戏配置项成功。 + bool RemoveSetting(string settingName); + + /// + /// 清空所有游戏配置项。 + /// + void RemoveAllSettings(); + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的布尔值。 + bool GetBool(string settingName); + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的布尔值。 + bool GetBool(string settingName, bool defaultValue); + + /// + /// 向指定游戏配置项写入布尔值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的布尔值。 + void SetBool(string settingName, bool value); + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的整数值。 + int GetInt(string settingName); + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的整数值。 + int GetInt(string settingName, int defaultValue); + + /// + /// 向指定游戏配置项写入整数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的整数值。 + void SetInt(string settingName, int value); + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的浮点数值。 + float GetFloat(string settingName); + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的浮点数值。 + float GetFloat(string settingName, float defaultValue); + + /// + /// 向指定游戏配置项写入浮点数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的浮点数值。 + void SetFloat(string settingName, float value); + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的字符串值。 + string GetString(string settingName); + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的字符串值。 + string GetString(string settingName, string defaultValue); + + /// + /// 向指定游戏配置项写入字符串值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的字符串值。 + void SetString(string settingName, string value); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + T GetObject(string settingName); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + object GetObject(Type objectType, string settingName); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + T GetObject(string settingName, T defaultObj); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + object GetObject(Type objectType, string settingName, object defaultObj); + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入对象的类型。 + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + void SetObject(string settingName, T obj); + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + void SetObject(string settingName, object obj); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingHelper.cs.meta new file mode 100644 index 00000000..6f2df8fd --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6d173740f25d459a9d09b86f7598fd79 +timeCreated: 1680490156 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingManager.cs new file mode 100644 index 00000000..e8b7f184 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingManager.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 游戏配置管理器接口。 + /// + public interface ISettingManager + { + /// + /// 获取游戏配置项数量。 + /// + int Count + { + get; + } + + /// + /// 设置游戏配置辅助器。 + /// + /// 游戏配置辅助器。 + void SetSettingHelper(ISettingHelper settingHelper); + + /// + /// 加载游戏配置。 + /// + /// 是否加载游戏配置成功。 + bool Load(); + + /// + /// 保存游戏配置。 + /// + /// 是否保存游戏配置成功。 + bool Save(); + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + string[] GetAllSettingNames(); + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + void GetAllSettingNames(List results); + + /// + /// 检查是否存在指定游戏配置项。 + /// + /// 要检查游戏配置项的名称。 + /// 指定的游戏配置项是否存在。 + bool HasSetting(string settingName); + + /// + /// 移除指定游戏配置项。 + /// + /// 要移除游戏配置项的名称。 + /// 是否移除指定游戏配置项成功。 + bool RemoveSetting(string settingName); + + /// + /// 清空所有游戏配置项。 + /// + void RemoveAllSettings(); + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的布尔值。 + bool GetBool(string settingName); + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的布尔值。 + bool GetBool(string settingName, bool defaultValue); + + /// + /// 向指定游戏配置项写入布尔值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的布尔值。 + void SetBool(string settingName, bool value); + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的整数值。 + int GetInt(string settingName); + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的整数值。 + int GetInt(string settingName, int defaultValue); + + /// + /// 向指定游戏配置项写入整数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的整数值。 + void SetInt(string settingName, int value); + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的浮点数值。 + float GetFloat(string settingName); + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的浮点数值。 + float GetFloat(string settingName, float defaultValue); + + /// + /// 向指定游戏配置项写入浮点数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的浮点数值。 + void SetFloat(string settingName, float value); + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的字符串值。 + string GetString(string settingName); + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的字符串值。 + string GetString(string settingName, string defaultValue); + + /// + /// 向指定游戏配置项写入字符串值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的字符串值。 + void SetString(string settingName, string value); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + T GetObject(string settingName); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + object GetObject(Type objectType, string settingName); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + T GetObject(string settingName, T defaultObj); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + object GetObject(Type objectType, string settingName, object defaultObj); + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入对象的类型。 + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + void SetObject(string settingName, T obj); + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + void SetObject(string settingName, object obj); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingManager.cs.meta new file mode 100644 index 00000000..0ed19a48 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/ISettingManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: aa9d9f6f6c6747a39bdd2b382bf0ae21 +timeCreated: 1680490156 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/PlayerPrefsSettingHelper.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/PlayerPrefsSettingHelper.cs new file mode 100644 index 00000000..2595ef88 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/PlayerPrefsSettingHelper.cs @@ -0,0 +1,304 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine +{ + /// + /// PlayerPrefs 游戏配置辅助器。 + /// + public class PlayerPrefsSettingHelper : SettingHelperBase + { + /// + /// 获取游戏配置项数量。 + /// + public override int Count + { + get + { + return -1; + } + } + + /// + /// 加载游戏配置。 + /// + /// 是否加载游戏配置成功。 + public override bool Load() + { + return true; + } + + /// + /// 保存游戏配置。 + /// + /// 是否保存游戏配置成功。 + public override bool Save() + { + PlayerPrefs.Save(); + return true; + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public override string[] GetAllSettingNames() + { + Log.Warning("GetAllSettingNames is not supported."); + return null; + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public override void GetAllSettingNames(List results) + { + if (results == null) + { + throw new GameFrameworkException("Results is invalid."); + } + + results.Clear(); + Log.Warning("GetAllSettingNames is not supported."); + } + + /// + /// 检查是否存在指定游戏配置项。 + /// + /// 要检查游戏配置项的名称。 + /// 指定的游戏配置项是否存在。 + public override bool HasSetting(string settingName) + { + return PlayerPrefs.HasKey(settingName); + } + + /// + /// 移除指定游戏配置项。 + /// + /// 要移除游戏配置项的名称。 + /// 是否移除指定游戏配置项成功。 + public override bool RemoveSetting(string settingName) + { + if (!PlayerPrefs.HasKey(settingName)) + { + return false; + } + + PlayerPrefs.DeleteKey(settingName); + return true; + } + + /// + /// 清空所有游戏配置项。 + /// + public override void RemoveAllSettings() + { + PlayerPrefs.DeleteAll(); + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的布尔值。 + public override bool GetBool(string settingName) + { + return PlayerPrefs.GetInt(settingName) != 0; + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的布尔值。 + public override bool GetBool(string settingName, bool defaultValue) + { + return PlayerPrefs.GetInt(settingName, defaultValue ? 1 : 0) != 0; + } + + /// + /// 向指定游戏配置项写入布尔值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的布尔值。 + public override void SetBool(string settingName, bool value) + { + PlayerPrefs.SetInt(settingName, value ? 1 : 0); + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的整数值。 + public override int GetInt(string settingName) + { + return PlayerPrefs.GetInt(settingName); + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的整数值。 + public override int GetInt(string settingName, int defaultValue) + { + return PlayerPrefs.GetInt(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入整数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的整数值。 + public override void SetInt(string settingName, int value) + { + PlayerPrefs.SetInt(settingName, value); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的浮点数值。 + public override float GetFloat(string settingName) + { + return PlayerPrefs.GetFloat(settingName); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的浮点数值。 + public override float GetFloat(string settingName, float defaultValue) + { + return PlayerPrefs.GetFloat(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入浮点数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的浮点数值。 + public override void SetFloat(string settingName, float value) + { + PlayerPrefs.SetFloat(settingName, value); + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的字符串值。 + public override string GetString(string settingName) + { + return PlayerPrefs.GetString(settingName); + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的字符串值。 + public override string GetString(string settingName, string defaultValue) + { + return PlayerPrefs.GetString(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入字符串值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的字符串值。 + public override void SetString(string settingName, string value) + { + PlayerPrefs.SetString(settingName, value); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public override T GetObject(string settingName) + { + return Utility.Json.ToObject(GetString(settingName)); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public override object GetObject(Type objectType, string settingName) + { + return Utility.Json.ToObject(objectType, GetString(settingName)); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public override T GetObject(string settingName, T defaultObj) + { + string json = GetString(settingName, null); + if (json == null) + { + return defaultObj; + } + + return Utility.Json.ToObject(json); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public override object GetObject(Type objectType, string settingName, object defaultObj) + { + string json = GetString(settingName, null); + if (json == null) + { + return defaultObj; + } + + return Utility.Json.ToObject(objectType, json); + } + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入对象的类型。 + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public override void SetObject(string settingName, T obj) + { + PlayerPrefs.SetString(settingName, Utility.Json.ToJson(obj)); + } + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public override void SetObject(string settingName, object obj) + { + PlayerPrefs.SetString(settingName, Utility.Json.ToJson(obj)); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/PlayerPrefsSettingHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/PlayerPrefsSettingHelper.cs.meta new file mode 100644 index 00000000..07ad8ec9 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/PlayerPrefsSettingHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c2f3305694c04457a879ef21d5bc7956 +timeCreated: 1680490094 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingHelperBase.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingHelperBase.cs new file mode 100644 index 00000000..f03f37b8 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingHelperBase.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine +{ + /// + /// 游戏配置辅助器基类。 + /// + public abstract class SettingHelperBase : MonoBehaviour, ISettingHelper + { + /// + /// 获取游戏配置项数量。 + /// + public abstract int Count + { + get; + } + + /// + /// 加载游戏配置。 + /// + /// 是否加载游戏配置成功。 + public abstract bool Load(); + + /// + /// 保存游戏配置。 + /// + /// 是否保存游戏配置成功。 + public abstract bool Save(); + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public abstract string[] GetAllSettingNames(); + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public abstract void GetAllSettingNames(List results); + + /// + /// 检查是否存在指定游戏配置项。 + /// + /// 要检查游戏配置项的名称。 + /// 指定的游戏配置项是否存在。 + public abstract bool HasSetting(string settingName); + + /// + /// 移除指定游戏配置项。 + /// + /// 要移除游戏配置项的名称。 + /// 是否移除指定游戏配置项成功。 + public abstract bool RemoveSetting(string settingName); + + /// + /// 清空所有游戏配置项。 + /// + public abstract void RemoveAllSettings(); + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的布尔值。 + public abstract bool GetBool(string settingName); + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的布尔值。 + public abstract bool GetBool(string settingName, bool defaultValue); + + /// + /// 向指定游戏配置项写入布尔值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的布尔值。 + public abstract void SetBool(string settingName, bool value); + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的整数值。 + public abstract int GetInt(string settingName); + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的整数值。 + public abstract int GetInt(string settingName, int defaultValue); + + /// + /// 向指定游戏配置项写入整数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的整数值。 + public abstract void SetInt(string settingName, int value); + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的浮点数值。 + public abstract float GetFloat(string settingName); + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的浮点数值。 + public abstract float GetFloat(string settingName, float defaultValue); + + /// + /// 向指定游戏配置项写入浮点数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的浮点数值。 + public abstract void SetFloat(string settingName, float value); + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的字符串值。 + public abstract string GetString(string settingName); + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的字符串值。 + public abstract string GetString(string settingName, string defaultValue); + + /// + /// 向指定游戏配置项写入字符串值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的字符串值。 + public abstract void SetString(string settingName, string value); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public abstract T GetObject(string settingName); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public abstract object GetObject(Type objectType, string settingName); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public abstract T GetObject(string settingName, T defaultObj); + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public abstract object GetObject(Type objectType, string settingName, object defaultObj); + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入对象的类型。 + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public abstract void SetObject(string settingName, T obj); + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public abstract void SetObject(string settingName, object obj); + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingHelperBase.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingHelperBase.cs.meta new file mode 100644 index 00000000..a7bf7790 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingHelperBase.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a00f613e91e248f29afcf49bf919e01e +timeCreated: 1680490094 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingManager.cs new file mode 100644 index 00000000..cbc59e80 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingManager.cs @@ -0,0 +1,558 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + /// + /// 游戏配置管理器。 + /// + internal sealed class SettingManager : ModuleImp, ISettingManager + { + private ISettingHelper m_SettingHelper; + + /// + /// 初始化游戏配置管理器的新实例。 + /// + public SettingManager() + { + m_SettingHelper = null; + } + + /// + /// 获取游戏配置项数量。 + /// + public int Count + { + get + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + return m_SettingHelper.Count; + } + } + + /// + /// 游戏配置管理器轮询。 + /// + /// 逻辑流逝时间,以秒为单位。 + /// 真实流逝时间,以秒为单位。 + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + } + + /// + /// 关闭并清理游戏配置管理器。 + /// + internal override void Shutdown() + { + Save(); + } + + /// + /// 设置游戏配置辅助器。 + /// + /// 游戏配置辅助器。 + public void SetSettingHelper(ISettingHelper settingHelper) + { + if (settingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + m_SettingHelper = settingHelper; + } + + /// + /// 加载游戏配置。 + /// + /// 是否加载游戏配置成功。 + public bool Load() + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + return m_SettingHelper.Load(); + } + + /// + /// 保存游戏配置。 + /// + /// 是否保存游戏配置成功。 + public bool Save() + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + return m_SettingHelper.Save(); + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public string[] GetAllSettingNames() + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + return m_SettingHelper.GetAllSettingNames(); + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public void GetAllSettingNames(List results) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + m_SettingHelper.GetAllSettingNames(results); + } + + /// + /// 检查是否存在指定游戏配置项。 + /// + /// 要检查游戏配置项的名称。 + /// 指定的游戏配置项是否存在。 + public bool HasSetting(string settingName) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.HasSetting(settingName); + } + + /// + /// 移除指定游戏配置项。 + /// + /// 要移除游戏配置项的名称。 + /// 是否移除指定游戏配置项成功。 + public bool RemoveSetting(string settingName) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.RemoveSetting(settingName); + } + + /// + /// 清空所有游戏配置项。 + /// + public void RemoveAllSettings() + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + m_SettingHelper.RemoveAllSettings(); + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的布尔值。 + public bool GetBool(string settingName) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetBool(settingName); + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的布尔值。 + public bool GetBool(string settingName, bool defaultValue) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetBool(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入布尔值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的布尔值。 + public void SetBool(string settingName, bool value) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + m_SettingHelper.SetBool(settingName, value); + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的整数值。 + public int GetInt(string settingName) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetInt(settingName); + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的整数值。 + public int GetInt(string settingName, int defaultValue) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetInt(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入整数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的整数值。 + public void SetInt(string settingName, int value) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + m_SettingHelper.SetInt(settingName, value); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的浮点数值。 + public float GetFloat(string settingName) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetFloat(settingName); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的浮点数值。 + public float GetFloat(string settingName, float defaultValue) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetFloat(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入浮点数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的浮点数值。 + public void SetFloat(string settingName, float value) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + m_SettingHelper.SetFloat(settingName, value); + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的字符串值。 + public string GetString(string settingName) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetString(settingName); + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的字符串值。 + public string GetString(string settingName, string defaultValue) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetString(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入字符串值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的字符串值。 + public void SetString(string settingName, string value) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + m_SettingHelper.SetString(settingName, value); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public T GetObject(string settingName) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetObject(settingName); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public object GetObject(Type objectType, string settingName) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetObject(objectType, settingName); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public T GetObject(string settingName, T defaultObj) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetObject(settingName, defaultObj); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public object GetObject(Type objectType, string settingName, object defaultObj) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + return m_SettingHelper.GetObject(objectType, settingName, defaultObj); + } + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入对象的类型。 + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public void SetObject(string settingName, T obj) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + m_SettingHelper.SetObject(settingName, obj); + } + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public void SetObject(string settingName, object obj) + { + if (m_SettingHelper == null) + { + throw new GameFrameworkException("Setting helper is invalid."); + } + + if (string.IsNullOrEmpty(settingName)) + { + throw new GameFrameworkException("Setting name is invalid."); + } + + m_SettingHelper.SetObject(settingName, obj); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingManager.cs.meta new file mode 100644 index 00000000..b92543cb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b35233fe04f74c928937f53330ed5bfd +timeCreated: 1680490156 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingModule.cs new file mode 100644 index 00000000..e826a459 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingModule.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine +{ + /// + /// 游戏配置模块。 + /// + [DisallowMultipleComponent] + public sealed class SettingModule : Module + { + private ISettingManager m_SettingManager = null; + + [SerializeField] + private string m_SettingHelperTypeName = "TEngine.DefaultSettingHelper"; + + [SerializeField] + private SettingHelperBase m_CustomSettingHelper = null; + + /// + /// 获取游戏配置项数量。 + /// + public int Count + { + get + { + return m_SettingManager.Count; + } + } + + /// + /// 游戏框架模块初始化。 + /// + protected override void Awake() + { + base.Awake(); + + m_SettingManager = ModuleImpSystem.GetModule(); + if (m_SettingManager == null) + { + Log.Fatal("Setting manager is invalid."); + return; + } + + SettingHelperBase settingHelper = Helper.CreateHelper(m_SettingHelperTypeName, m_CustomSettingHelper); + if (settingHelper == null) + { + Log.Error("Can not create setting helper."); + return; + } + + settingHelper.name = "Setting Helper"; + Transform transform = settingHelper.transform; + transform.SetParent(this.transform); + transform.localScale = Vector3.one; + + m_SettingManager.SetSettingHelper(settingHelper); + } + + private void Start() + { + if (!m_SettingManager.Load()) + { + Log.Error("Load settings failure."); + } + } + + /// + /// 保存游戏配置。 + /// + public void Save() + { + m_SettingManager.Save(); + } + + private void OnDestroy() + { + m_SettingManager.Save(); + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public string[] GetAllSettingNames() + { + return m_SettingManager.GetAllSettingNames(); + } + + /// + /// 获取所有游戏配置项的名称。 + /// + /// 所有游戏配置项的名称。 + public void GetAllSettingNames(List results) + { + m_SettingManager.GetAllSettingNames(results); + } + + /// + /// 检查是否存在指定游戏配置项。 + /// + /// 要检查游戏配置项的名称。 + /// 指定的游戏配置项是否存在。 + public bool HasSetting(string settingName) + { + return m_SettingManager.HasSetting(settingName); + } + + /// + /// 移除指定游戏配置项。 + /// + /// 要移除游戏配置项的名称。 + public void RemoveSetting(string settingName) + { + m_SettingManager.RemoveSetting(settingName); + } + + /// + /// 清空所有游戏配置项。 + /// + public void RemoveAllSettings() + { + m_SettingManager.RemoveAllSettings(); + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的布尔值。 + public bool GetBool(string settingName) + { + return m_SettingManager.GetBool(settingName); + } + + /// + /// 从指定游戏配置项中读取布尔值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的布尔值。 + public bool GetBool(string settingName, bool defaultValue) + { + return m_SettingManager.GetBool(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入布尔值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的布尔值。 + public void SetBool(string settingName, bool value) + { + m_SettingManager.SetBool(settingName, value); + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的整数值。 + public int GetInt(string settingName) + { + return m_SettingManager.GetInt(settingName); + } + + /// + /// 从指定游戏配置项中读取整数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的整数值。 + public int GetInt(string settingName, int defaultValue) + { + return m_SettingManager.GetInt(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入整数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的整数值。 + public void SetInt(string settingName, int value) + { + m_SettingManager.SetInt(settingName, value); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的浮点数值。 + public float GetFloat(string settingName) + { + return m_SettingManager.GetFloat(settingName); + } + + /// + /// 从指定游戏配置项中读取浮点数值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的浮点数值。 + public float GetFloat(string settingName, float defaultValue) + { + return m_SettingManager.GetFloat(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入浮点数值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的浮点数值。 + public void SetFloat(string settingName, float value) + { + m_SettingManager.SetFloat(settingName, value); + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 读取的字符串值。 + public string GetString(string settingName) + { + return m_SettingManager.GetString(settingName); + } + + /// + /// 从指定游戏配置项中读取字符串值。 + /// + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认值。 + /// 读取的字符串值。 + public string GetString(string settingName, string defaultValue) + { + return m_SettingManager.GetString(settingName, defaultValue); + } + + /// + /// 向指定游戏配置项写入字符串值。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的字符串值。 + public void SetString(string settingName, string value) + { + m_SettingManager.SetString(settingName, value); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public T GetObject(string settingName) + { + return m_SettingManager.GetObject(settingName); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 读取的对象。 + public object GetObject(Type objectType, string settingName) + { + return m_SettingManager.GetObject(objectType, settingName); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public T GetObject(string settingName, T defaultObj) + { + return m_SettingManager.GetObject(settingName, defaultObj); + } + + /// + /// 从指定游戏配置项中读取对象。 + /// + /// 要读取对象的类型。 + /// 要获取游戏配置项的名称。 + /// 当指定的游戏配置项不存在时,返回此默认对象。 + /// 读取的对象。 + public object GetObject(Type objectType, string settingName, object defaultObj) + { + return m_SettingManager.GetObject(objectType, settingName, defaultObj); + } + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入对象的类型。 + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public void SetObject(string settingName, T obj) + { + m_SettingManager.SetObject(settingName, obj); + } + + /// + /// 向指定游戏配置项写入对象。 + /// + /// 要写入游戏配置项的名称。 + /// 要写入的对象。 + public void SetObject(string settingName, object obj) + { + m_SettingManager.SetObject(settingName, obj); + } + } +} diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingModule.cs.meta new file mode 100644 index 00000000..dfa1f3f0 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/SettingModule/SettingModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 352db63f3a7b449bac6e5de8bb32141a +timeCreated: 1680490094 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule.meta b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule.meta new file mode 100644 index 00000000..4e8c7993 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d56be587f7b64f4aac094df08798619f +timeCreated: 1700625097 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/GameTimerTick.cs b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/GameTimerTick.cs new file mode 100644 index 00000000..87d3e5fa --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/GameTimerTick.cs @@ -0,0 +1,60 @@ +using UnityEngine; + +namespace TEngine +{ + public class GameTimerTick + { + protected OnTick Handle; + protected float LastTime; + protected float Interval; + protected bool ResetInterval = true; + + public GameTimerTick(float interval, OnTick tickHandle) => Init(interval, true, true, tickHandle); + + public GameTimerTick(float interval, bool immediately, OnTick tickHandle) => Init(interval, immediately, true, tickHandle); + + public GameTimerTick(float interval, bool immediately, bool resetInterval, OnTick tickHandle) + { + Init(interval, immediately, resetInterval, tickHandle); + } + + private void Init(float interval, bool immediately, bool resetInterval, OnTick tickHandle) + { + Interval = interval; + Handle = tickHandle; + ResetInterval = resetInterval; + if (immediately) + { + return; + } + + LastTime = Time.time; + } + + public void OnUpdate() + { + float time = Time.time; + if (LastTime + Interval >= time) + { + return; + } + + if (ResetInterval) + { + LastTime = time; + } + else if (LastTime == 0.0) + { + LastTime = time; + } + else + { + LastTime += Interval; + } + + Handle(); + } + + public delegate void OnTick(); + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/GameTimerTick.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/GameTimerTick.cs.meta new file mode 100644 index 00000000..f41e6d2b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/GameTimerTick.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 76843c14c1344aa68863289bf7388238 +timeCreated: 1701088103 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs new file mode 100644 index 00000000..bbfc6da1 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + public delegate void TimerHandler(object[] args); + + [UpdateModule] + internal class TimerManager : ModuleImp + { + [Serializable] + internal class Timer + { + public int timerId = 0; + public float curTime = 0; + public float time = 0; + public TimerHandler Handler; + public bool isLoop = false; + public bool isNeedRemove = false; + public bool isRunning = false; + public bool isUnscaled = false; //是否使用非缩放的时间 + public object[] Args = null; //回调参数 + } + + private int _curTimerId = 0; + private readonly List _timerList = new List(); + private readonly List _unscaledTimerList = new List(); + private readonly List _cacheRemoveTimers = new List(); + private readonly List _cacheRemoveUnscaledTimers = new List(); + + /// + /// 添加计时器。 + /// + /// 计时器回调。 + /// 计时器间隔。 + /// 是否循环。 + /// 是否不收时间缩放影响。 + /// 传参。(避免闭包) + /// 计时器Id。 + public int AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args) + { + Timer timer = new Timer + { + timerId = ++_curTimerId, + curTime = time, + time = time, + Handler = callback, + isLoop = isLoop, + isUnscaled = isUnscaled, + Args = args, + isNeedRemove = false, + isRunning = true + }; + + InsertTimer(timer); + return timer.timerId; + } + + private void InsertTimer(Timer timer) + { + bool isInsert = false; + if (timer.isUnscaled) + { + for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) + { + if (_unscaledTimerList[i].curTime > timer.curTime) + { + _unscaledTimerList.Insert(i, timer); + isInsert = true; + break; + } + } + + if (!isInsert) + { + _unscaledTimerList.Add(timer); + } + } + else + { + for (int i = 0, len = _timerList.Count; i < len; i++) + { + if (_timerList[i].curTime > timer.curTime) + { + _timerList.Insert(i, timer); + isInsert = true; + break; + } + } + + if (!isInsert) + { + _timerList.Add(timer); + } + } + } + + /// + /// 暂停计时器。 + /// + /// 计时器Id。 + public void Stop(int timerId) + { + Timer timer = GetTimer(timerId); + if (timer != null) timer.isRunning = false; + } + + /// + /// 恢复计时器。 + /// + /// 计时器Id。 + public void Resume(int timerId) + { + Timer timer = GetTimer(timerId); + if (timer != null) timer.isRunning = true; + } + + /// + /// 计时器是否在运行中。 + /// + /// 计时器Id。 + /// 否在运行中。 + public bool IsRunning(int timerId) + { + Timer timer = GetTimer(timerId); + return timer is { isRunning: true }; + } + + /// + /// 获得计时器剩余时间 + /// + public float GetLeftTime(int timerId) + { + Timer timer = GetTimer(timerId); + if (timer == null) return 0; + return timer.curTime; + } + + /// + /// 重置计时器,恢复到开始状态。 + /// + public void Restart(int timerId) + { + Timer timer = GetTimer(timerId); + if (timer != null) + { + timer.curTime = timer.time; + timer.isRunning = true; + } + } + + /// + /// 重置计时器。 + /// + public void Reset(int timerId, TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false) + { + Timer timer = GetTimer(timerId); + if (timer != null) + { + timer.curTime = time; + timer.time = time; + timer.Handler = callback; + timer.isLoop = isLoop; + timer.isNeedRemove = false; + if (timer.isUnscaled != isUnscaled) + { + RemoveTimerImmediate(timerId); + + timer.isUnscaled = isUnscaled; + InsertTimer(timer); + } + } + } + + /// + /// 重置计时器。 + /// + public void Reset(int timerId, float time, bool isLoop, bool isUnscaled) + { + Timer timer = GetTimer(timerId); + if (timer != null) + { + timer.curTime = time; + timer.time = time; + timer.isLoop = isLoop; + timer.isNeedRemove = false; + if (timer.isUnscaled != isUnscaled) + { + RemoveTimerImmediate(timerId); + + timer.isUnscaled = isUnscaled; + InsertTimer(timer); + } + } + } + + /// + /// 立即移除。 + /// + /// + private void RemoveTimerImmediate(int timerId) + { + for (int i = 0, len = _timerList.Count; i < len; i++) + { + if (_timerList[i].timerId == timerId) + { + _timerList.RemoveAt(i); + return; + } + } + + for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) + { + if (_unscaledTimerList[i].timerId == timerId) + { + _unscaledTimerList.RemoveAt(i); + return; + } + } + } + + /// + /// 移除计时器。 + /// + /// 计时器Id。 + public void RemoveTimer(int timerId) + { + for (int i = 0, len = _timerList.Count; i < len; i++) + { + if (_timerList[i].timerId == timerId) + { + _timerList[i].isNeedRemove = true; + return; + } + } + + for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) + { + if (_unscaledTimerList[i].timerId == timerId) + { + _unscaledTimerList[i].isNeedRemove = true; + return; + } + } + } + + /// + /// 移除所有计时器。 + /// + public void RemoveAllTimer() + { + _timerList.Clear(); + _unscaledTimerList.Clear(); + } + + private Timer GetTimer(int timerId) + { + for (int i = 0, len = _timerList.Count; i < len; i++) + { + if (_timerList[i].timerId == timerId) + { + return _timerList[i]; + } + } + + for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) + { + if (_unscaledTimerList[i].timerId == timerId) + { + return _unscaledTimerList[i]; + } + } + + return null; + } + + private void LoopCallInBadFrame() + { + bool isLoopCall = false; + for (int i = 0, len = _timerList.Count; i < len; i++) + { + Timer timer = _timerList[i]; + if (timer.isLoop && timer.curTime <= 0) + { + if (timer.Handler != null) + { + timer.Handler(timer.Args); + } + + timer.curTime += timer.time; + if (timer.curTime <= 0) + { + isLoopCall = true; + } + } + } + + if (isLoopCall) + { + LoopCallInBadFrame(); + } + } + + private void LoopCallUnscaledInBadFrame() + { + bool isLoopCall = false; + for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) + { + Timer timer = _unscaledTimerList[i]; + if (timer.isLoop && timer.curTime <= 0) + { + if (timer.Handler != null) + { + timer.Handler(timer.Args); + } + + timer.curTime += timer.time; + if (timer.curTime <= 0) + { + isLoopCall = true; + } + } + } + + if (isLoopCall) + { + LoopCallUnscaledInBadFrame(); + } + } + + private void UpdateTimer(float elapseSeconds) + { + bool isLoopCall = false; + for (int i = 0, len = _timerList.Count; i < len; i++) + { + Timer timer = _timerList[i]; + if (timer.isNeedRemove) + { + _cacheRemoveTimers.Add(i); + continue; + } + + if (!timer.isRunning) continue; + timer.curTime -= elapseSeconds; + if (timer.curTime <= 0) + { + if (timer.Handler != null) + { + timer.Handler(timer.Args); + } + + if (timer.isLoop) + { + timer.curTime += timer.time; + if (timer.curTime <= 0) + { + isLoopCall = true; + } + } + else + { + _cacheRemoveTimers.Add(i); + } + } + } + + for (int i = _cacheRemoveTimers.Count - 1; i >= 0; i--) + { + _timerList.RemoveAt(_cacheRemoveTimers[i]); + _cacheRemoveTimers.RemoveAt(i); + } + + if (isLoopCall) + { + LoopCallInBadFrame(); + } + } + + private void UpdateUnscaledTimer(float realElapseSeconds) + { + bool isLoopCall = false; + for (int i = 0, len = _unscaledTimerList.Count; i < len; i++) + { + Timer timer = _unscaledTimerList[i]; + if (timer.isNeedRemove) + { + _cacheRemoveUnscaledTimers.Add(i); + continue; + } + + if (!timer.isRunning) continue; + timer.curTime -= realElapseSeconds; + if (timer.curTime <= 0) + { + if (timer.Handler != null) + { + timer.Handler(timer.Args); + } + + if (timer.isLoop) + { + timer.curTime += timer.time; + if (timer.curTime <= 0) + { + isLoopCall = true; + } + } + else + { + _cacheRemoveUnscaledTimers.Add(i); + } + } + } + + for (int i = _cacheRemoveUnscaledTimers.Count - 1; i >= 0; i--) + { + _unscaledTimerList.RemoveAt(_cacheRemoveUnscaledTimers[i]); + _cacheRemoveUnscaledTimers.RemoveAt(i); + } + + if (isLoopCall) + { + LoopCallUnscaledInBadFrame(); + } + } + + private readonly List _ticker = new List(); + + public System.Timers.Timer AddSystemTimer(Action callBack) + { + int interval = 1000; + var timerTick = new System.Timers.Timer(interval); + timerTick.AutoReset = true; + timerTick.Enabled = true; + timerTick.Elapsed += new System.Timers.ElapsedEventHandler(callBack); + + _ticker.Add(timerTick); + + return timerTick; + } + + private void DestroySystemTimer() + { + foreach (var ticker in _ticker) + { + if (ticker != null) + { + ticker.Stop(); + } + } + } + + internal override void Update(float elapseSeconds, float realElapseSeconds) + { + UpdateTimer(elapseSeconds); + UpdateUnscaledTimer(realElapseSeconds); + } + + internal override void Shutdown() + { + RemoveAllTimer(); + DestroySystemTimer(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs.meta new file mode 100644 index 00000000..1b7e21a7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a3b960842a44c6fbba975083ba5fa50 +timeCreated: 1700625107 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs new file mode 100644 index 00000000..846b8b36 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs @@ -0,0 +1,170 @@ +using UnityEngine; + +namespace TEngine +{ + /// + /// 计时器模块。 + /// + [DisallowMultipleComponent] + public sealed partial class TimerModule : Module + { + private TimerManager _timerManager; + + /// + /// 游戏框架组件初始化。 + /// + protected override void Awake() + { + base.Awake(); + + _timerManager = ModuleImpSystem.GetModule(); + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + } + } + + /// + /// 添加计时器。 + /// + /// 计时器回调。 + /// 计时器间隔。 + /// 是否循环。 + /// 是否不收时间缩放影响。 + /// 传参。(避免闭包) + /// 计时器Id。 + public int AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + return _timerManager.AddTimer(callback, time, isLoop, isUnscaled, args); + } + + /// + /// 暂停计时器。 + /// + /// 计时器Id。 + public void Stop(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Stop(timerId); + } + + /// + /// 恢复计时器。 + /// + /// 计时器Id。 + public void Resume(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Resume(timerId); + } + + /// + /// 计时器是否在运行中。 + /// + /// 计时器Id。 + /// 否在运行中。 + public bool IsRunning(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + return _timerManager.IsRunning(timerId); + } + + /// + /// 获得计时器剩余时间。 + /// + public float GetLeftTime(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + return _timerManager.GetLeftTime(timerId); + } + + /// + /// 重置计时器,恢复到开始状态。 + /// + public void Restart(int timerId) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Restart(timerId); + } + + /// + /// 重置计时器。 + /// + public void ResetTimer(int timerId, TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Reset(timerId,callback,time,isLoop,isUnscaled); + } + + /// + /// 重置计时器。 + /// + public void ResetTimer(int timerId, float time, bool isLoop, bool isUnscaled) + { + if (_timerManager == null) + { + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.Reset(timerId, time,isLoop,isUnscaled); + } + + /// + /// 移除计时器。 + /// + /// 计时器Id。 + public void RemoveTimer(int timerId) + { + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.RemoveTimer(timerId); + } + + /// + /// 移除所有计时器。 + /// + public void RemoveAllTimer() + { + if (_timerManager == null) + { + Log.Fatal("TimerMgr is invalid."); + throw new GameFrameworkException("TimerMgr is invalid."); + } + + _timerManager.RemoveAllTimer(); + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs.meta new file mode 100644 index 00000000..4a2993bc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/TimerModule/TimerModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5e79c115d5054209810f42dc6e25cf94 +timeCreated: 1700625348 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule.meta b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule.meta new file mode 100644 index 00000000..25a59c32 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f9c48b7552e60034097a2f45049b3987 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool.meta b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool.meta new file mode 100644 index 00000000..b753b53b --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5fefbf9d90fc46eaaa7d12e5cd8cd219 +timeCreated: 1698301646 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/ComponentAutoBindTool.cs b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/ComponentAutoBindTool.cs new file mode 100644 index 00000000..9749d84e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/ComponentAutoBindTool.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +/// +/// 组件自动绑定工具 +/// +public class ComponentAutoBindTool : MonoBehaviour +{ +#if UNITY_EDITOR + [Serializable] + public class BindData + { + public BindData() + { + } + + public BindData(string name, Component bindCom, bool isGameObject = false) + { + Name = name; + BindCom = bindCom; + IsGameObject = isGameObject; + } + + public string Name; + public Component BindCom; + public bool IsGameObject; + } + + public List BindDatas = new List(); + + [SerializeField] + private string m_ClassName; + + [SerializeField] + private string m_Namespace; + + [SerializeField] + private string m_CodePath; + + [SerializeField] + private bool m_IsWidget; + + public string ClassName => m_ClassName; + + public string Namespace => m_Namespace; + + public string CodePath => m_CodePath; + + + public bool IsWidget => m_IsWidget; + + public IAutoBindRuleHelper RuleHelper + { + get; + set; + } +#endif + + [SerializeField] + public List bindComponents = new List(); + + public T GetBindComponent(int index) where T : Component + { + if (index >= bindComponents.Count) + { + Debug.LogError("索引无效"); + return null; + } + + T bindCom = bindComponents[index] as T; + + if (bindCom == null) + { + Debug.LogError("类型无效"); + return null; + } + + return bindCom; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/ComponentAutoBindTool.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/ComponentAutoBindTool.cs.meta new file mode 100644 index 00000000..4fc1032e --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/ComponentAutoBindTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 59269a619eb50d048840c07a31b0d368 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/DefaultAutoBindRuleHelper.cs b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/DefaultAutoBindRuleHelper.cs new file mode 100644 index 00000000..ef2c3afc --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/DefaultAutoBindRuleHelper.cs @@ -0,0 +1,77 @@ +#if false +using System.Collections.Generic; +using UnityEngine; + +/// +/// 默认自动绑定规则辅助器 +/// +public class DefaultAutoBindRuleHelper : IAutoBindRuleHelper +{ + + /// + /// 命名前缀与类型的映射 + /// + private Dictionary m_PrefixesDict = new Dictionary() + { + {"Trans","Transform" }, + {"OldAnim","Animation"}, + {"NewAnim","Animator"}, + + {"Rect","RectTransform"}, + {"Canvas","Canvas"}, + {"Group","CanvasGroup"}, + {"VGroup","VerticalLayoutGroup"}, + {"HGroup","HorizontalLayoutGroup"}, + {"GGroup","GridLayoutGroup"}, + {"TGroup","ToggleGroup"}, + + {"Btn","UIButtonSuper"}, + {"Img","Image"}, + {"RImg","RawImage"}, + {"Txt","Text"}, + {"TxtM","TextMeshProUGUI"}, + {"Input","TMP_InputField"}, + {"Slider","Slider"}, + {"Mask","Mask"}, + {"Mask2D","RectMask2D"}, + {"Tog","Toggle"}, + {"Sbar","Scrollbar"}, + {"SRect","ScrollRect"}, + {"Drop","Dropdown"}, + {"USpriteAni","UGUISpriteAnimation"}, + {"VGridV","LoopGridView"}, + {"HGridV","LoopGridView"}, + {"VListV","LoopListView2"}, + {"HListV","LoopListView2"}, + }; + + public bool IsValidBind( Transform target, List filedNames, List componentTypeNames) + { + string[] strArray = target.name.Split('_'); + + if (strArray.Length == 1) + { + return false; + } + + string filedName = strArray[^1]; + + for (int i = 0; i < strArray.Length - 1; i++) + { + string str = strArray[i]; + if (m_PrefixesDict.TryGetValue(str,out var componentName)) + { + filedNames.Add($"{str}_{filedName}"); + componentTypeNames.Add(componentName); + } + else + { + Debug.LogError($"{target.name}的命名中{str}不存在对应的组件类型,绑定失败"); + return false; + } + } + + return true; + } +} +#endif diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/DefaultAutoBindRuleHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/DefaultAutoBindRuleHelper.cs.meta new file mode 100644 index 00000000..71a6b995 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/DefaultAutoBindRuleHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 48a5faab9d684f14a38c5a001326eb03 +timeCreated: 1698301686 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/IAutoBindRuleHelper.cs b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/IAutoBindRuleHelper.cs new file mode 100644 index 00000000..de170bb3 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/IAutoBindRuleHelper.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using UnityEngine; + +/// +/// 自动绑定规则辅助器接口 +/// +public interface IAutoBindRuleHelper +{ + /// + /// 是否为有效绑定 + /// + bool IsValidBind(Transform target,List filedNames,List componentTypeNames); +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/IAutoBindRuleHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/IAutoBindRuleHelper.cs.meta new file mode 100644 index 00000000..87486be6 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/IAutoBindRuleHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5654ec3474b94b7fa84dfdc684fe2fa9 +timeCreated: 1698301670 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/UIAutoBindRuleHelper.cs b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/UIAutoBindRuleHelper.cs new file mode 100644 index 00000000..58b8abfb --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/UIAutoBindRuleHelper.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using UnityEngine; + +/// +/// UI自动绑定规则辅助器 +/// +public class UIAutoBindRuleHelper: IAutoBindRuleHelper +{ + public bool IsValidBind( Transform targetTransform, List filedNames, List componentTypeNames) + { + string uiElementName = targetTransform.name; + string[] strArray = targetTransform.name.Split('_'); + + if (strArray.Length == 1) + { + return false; + } + + string filedName = strArray[^1]; + var rule = SettingsUtils.GetScriptGenerateRule().Find(t => uiElementName.StartsWith(t.uiElementRegex)); + + if (rule != null) + { + filedNames.Add($"{filedName}"); + componentTypeNames.Add(rule.componentName); + return true; + } + Debug.LogWarning($"{targetTransform.name}的命名中{uiElementName}不存在对应的组件类型,绑定失败"); + return false; + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/UIAutoBindRuleHelper.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/UIAutoBindRuleHelper.cs.meta new file mode 100644 index 00000000..0f2b568a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ComponentAutoBindTool/UIAutoBindRuleHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a4256bde2e254a7f91fc70ea1f7420d8 +timeCreated: 1698306650 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger.meta b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger.meta new file mode 100644 index 00000000..d4932b72 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2885c31816f64323ab3d3e803f41d0fc +timeCreated: 1695196700 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/ErrorLogger.cs b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/ErrorLogger.cs new file mode 100644 index 00000000..6b6a33d2 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/ErrorLogger.cs @@ -0,0 +1,27 @@ +using System; +using UnityEngine; + +namespace TEngine +{ + public class ErrorLogger:IDisposable + { + public ErrorLogger() + { + Application.logMessageReceived += LogHandler; + } + + public void Dispose() + { + Application.logMessageReceived -= LogHandler; + } + + private void LogHandler(string condition, string stacktrace, LogType type) + { + if (type == LogType.Exception) + { + string des = $"客户端报错, \n#内容#:---{condition} \n#位置#:---{stacktrace}"; + //GameModule.UI.ShowUIAsync(des); + } + } + } +} \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/ErrorLogger.cs.meta b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/ErrorLogger.cs.meta new file mode 100644 index 00000000..0a3391c7 --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/ErrorLogger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9ccc9fc5faf14d93baec285acaa97907 +timeCreated: 1681807720 \ No newline at end of file diff --git a/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/LogUI.cs b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/LogUI.cs new file mode 100644 index 00000000..a2ba533a --- /dev/null +++ b/EintooAR/Assets/TEngine/Runtime/Modules/UIModule/ErrorLogger/LogUI.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Cysharp.Threading.Tasks; +using UnityEngine.UI; + +namespace TEngine +{ + [Window(UILayer.System,fromResources:true)] + class LogUI : UIWindow + { + private Stack _errorTextString = new Stack(); + + #region 脚本工具生成的代码 + private Text m_textError; + private Button m_btnClose; + protected override void ScriptGenerator() + { + m_textError = FindChildComponent("m_textError"); + m_btnClose = FindChildComponent